Order.java
package com.tradecloud.domain.model.ordermanagement;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.base.utils.DateUtils;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.base.utils.ObjectUtil;
import com.tradecloud.domain.comment.AddedComment;
import com.tradecloud.domain.comment.AddedCommentI;
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.SpecialRequirementConfig;
import com.tradecloud.domain.container.Container;
import com.tradecloud.domain.costing.clean.CostingVisitor;
import com.tradecloud.domain.costing.clean.EstimateCostSummary;
import com.tradecloud.domain.dms.DocumentGroupState;
import com.tradecloud.domain.dms.DocumentManagementHardCoding;
import com.tradecloud.domain.document.invoice.PlannedSettlementHelper;
import com.tradecloud.domain.document.invoice.UnitPricePerItem;
import com.tradecloud.domain.event.ActivityLog;
import com.tradecloud.domain.event.Event;
import com.tradecloud.domain.event.OrderEventType;
import com.tradecloud.domain.event.OrdersEvent;
import com.tradecloud.domain.item.AdditionalNotes;
import com.tradecloud.domain.item.ItemType;
import com.tradecloud.domain.item.LineItem;
import com.tradecloud.domain.model.DMSLinked;
import com.tradecloud.domain.model.Original;
import com.tradecloud.domain.model.goodsreceivedreceipt.GoodsReceivedReceipt;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.model.payment.PaymentMethod;
import com.tradecloud.domain.model.payment.PaymentTerm;
import com.tradecloud.domain.party.Employee;
import com.tradecloud.domain.party.ServiceProvider;
import com.tradecloud.domain.party.base.Contact;
import com.tradecloud.domain.payment.Payable;
import com.tradecloud.domain.place.PlaceOfDischarge;
import com.tradecloud.domain.settlement.PlannedSettlement;
import com.tradecloud.domain.settlement.Settleable;
import com.tradecloud.domain.shipment.ShippingInformation;
import com.tradecloud.domain.shipment.SubShipment;
import com.tradecloud.domain.state.Stateful;
import com.tradecloud.domain.supplier.SupplierCommon;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.*;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;
import static com.tradecloud.domain.model.ordermanagement.OrderState.*;
//import org.hibernate.annotations.Where;
/**
* Base class for orders in the system.
* https://connect.devstream.net/display/Dev/Order+Fields.
*
* @see PurchaseOrder
* @see SalesOrder
*/
@Entity
@Table(name = "orders", uniqueConstraints = {@UniqueConstraint(columnNames = {"number"}), @UniqueConstraint(columnNames = {"orderReference"})})
@FilterDef(name = "excludeCopies", defaultCondition = "copy is false")
@Inheritance(strategy = InheritanceType.JOINED)
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Order")
@XmlSeeAlso({PurchaseOrder.class, SalesOrder.class})
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@NamedQueries({
@NamedQuery(name = "order.findByNumber", query = "SELECT o FROM Order o WHERE o.number = :number"),
@NamedQuery(name = "order.findByShippingReference",
query = "SELECT o FROM Order o WHERE o.shippingInformation.shippingReference = :shippingReference"),
@NamedQuery(name = "order.findAllArchivedByReference",
query = "FROM Order o WHERE o.orderReference = :reference AND o.state in ('ARCHIVED') ORDER BY o.created"),
@NamedQuery(name = "order.findByReference", query = "SELECT o FROM Order o WHERE o.orderReference = :orderReference " +
"AND o.state NOT IN ('ARCHIVED')"),
@NamedQuery(name = "order.findByQuote", query = "SELECT o FROM Order o WHERE o.quoteReference = :quoteReference " +
"AND o.state NOT IN ('ARCHIVED')"),
@NamedQuery(name = "order.findByReferenceNotDeleted",
query = "SELECT o FROM Order o where o.orderReference = :orderReference and o.state not in ('DELETED', 'ARCHIVED')"),
@NamedQuery(name = "order.findByNumberAndReference",
query = "SELECT o FROM Order o WHERE o.number = :orderNumber AND o.orderReference = :orderReference"),
@NamedQuery(name = "findAllUnlinkedOrders", query = "SELECT o FROM Order o WHERE o.consignment IS NULL and o.elc='f'"),
// moved to subclass
// @NamedQuery(name = "order.findAllUnlinkedWithItems",
// query = "from Order o where o.state not in ('DELETED') and o.consignment is null and o.lineItems.size > 0"),
@NamedQuery(name = "order.findAllByState", query = "from Order o where o.state = :state and elc='f'"),
@NamedQuery(name = "order.findById",
query = "from Order ord left join fetch ord.lineItems as lineItems where ord.id=:id" +
" order by lineItems.created"),
@NamedQuery(name = "order.findAllByShipment", query = "from Order o where o.consignment.shipment.id = :id"),
@NamedQuery(name = "order.findByIdWithEventsAndPlannedSettlements",
query = "from Order ord left join fetch ord.events left join fetch ord.plannedSettlements where ord.id = :id")})
public abstract class Order extends PersistenceBase implements Commentable<AddedComment>, Original, Stateful<OrderState, OrdersEvent>,
Comparable<Order>, Payable, Settleable, DMSLinked {
public enum TradeAgreementOption {
COUNTRY_OF_ORIGIN, GENERAL
}
/**
* The name of the database sequence used for generating part of the order
* number.
*
* @see #number
*/
public static final String NUMBER_SEQUENCE = "ordernumber_sequence";
public final static Collection<OrderState> NON_EDITABLE_STATES = Arrays.asList(OrderState.SIGNED_OFF, OrderState.AWAITING_LSP_SIGNOFF,
OrderState.STOCK_RECEIVED, OrderState.BOOKED_IN, OrderState.FREIGHT_RECEIVED, OrderState.DELETED, OrderState.FINALISED,
SHIPMENT_CREATED, IN_EXECUTION, CARGO_READY, AWAITING_BOOKING, AWAITING_COLLECTION, SHIPMENT_CREATED, ARCHIVED);
protected final static Collection<OrderState> SALE_NON_EDITABLE_STATES = Arrays.asList(OrderState.SIGNED_OFF, OrderState.AWAITING_LSP_SIGNOFF,
OrderState.STOCK_RECEIVED, OrderState.BOOKED_IN, OrderState.FREIGHT_RECEIVED, OrderState.DELETED, OrderState.FINALISED,
STOCK_PARTIALLY_RECEIVED);
private static final long serialVersionUID = 1L;
public final static Collection<OrderState> SIGNED_OFF_STATES = Arrays.asList(OrderState.SIGNED_OFF, OrderState.AWAITING_LSP_SIGNOFF,
OrderState.BOOKED_IN, OrderState.FREIGHT_RECEIVED, SUPPLIER_BOOKING_REQUESTED, CARGO_READY, SHIPMENT_CREATED);
public final static Collection<OrderState> PAYABLE_STATES = Arrays.asList(OrderState.SIGNED_OFF, OrderState.AWAITING_LSP_SIGNOFF,
OrderState.BOOKED_IN, OrderState.FREIGHT_RECEIVED, FINALISED, STOCK_RECEIVED, TOLERANCE_EXCEEDED, SHIPMENT_CREATED, CANCEL_BOOKING,
STOCK_PARTIALLY_RECEIVED);
@Transient
protected String reason;
protected boolean confirmed;
/**
* Unique system generated number. The format for this is configured in the
* client setup.
*
* @see #NUMBER_SEQUENCE
*/
@XmlID
@XmlAttribute(required = true)
@NaturalId
@NotNull(message = "Number is required")
@Size(max = 255)
protected String number;
/**
* The client's ERP order number.
* XML id used for setting parent order in child lineitem
*/
@XmlID
@XmlAttribute(required = true)
@NotNull(message = "Reference is required")
@Size(max = 255)
protected String orderReference;
@XmlTransient
@Size(max = 255)
@JsonIgnore
protected String oldOrderReference;
/**
* The organisational unit for which the buyer or seller places the order.
*/
@ManyToOne(fetch = FetchType.LAZY)
@XmlElement(name = "OrganisationalUnit", required = true)
@NotNull(message = "Organisational Unit is required")
protected OrganisationalUnit organisationalUnit;
/**
* The currency of the order. This should default to the the supplier's
* currency but if no default exists there then the currency configured in
* the client setup will be used.
*/
@ManyToOne
@XmlElement(name = "Currency", required = true)
@NotNull(message = "Currency is required")
protected Currency currency;
/**
* The payment method of the order for example LC, DRAFT, CASH etc. This
* should default to the the supplier's payment method. If there is no
* payment method provided for the supplier then the payment method
* configured in the client setup will be used.
*/
@ManyToOne
@XmlElement(name = "PaymentMethod", required = true)
@NotNull(message = "Payment Method is required")
protected PaymentMethod paymentMethod;
/**
* The payment term on the order for example 30 day, 90 day etc. This should
* default to the the supplier's payment term. If there is no payment term
* provided for the supplier then the payment term configured in the client
* setup will be used.
*/
@ManyToOne
@XmlElement(name = "PaymentTerm", required = true)
@NotNull(message = "Payment Term is required")
protected PaymentTerm paymentTerm;
/**
* Set of line Items contained on the order. There is no LineItem service,
* they are managed only as part of the order
*/
@XmlElementWrapper(name = "LineItems")
@XmlElement(name = "LineItem")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", orphanRemoval = true, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SELECT)
@OrderBy("position,addedToOrderDate,code")
@JsonManagedReference
protected Set<LineItem> lineItems = new LinkedHashSet<LineItem>();
/**
* Set of planned settlements contained on the order. There is no Planned Settlement service,
* they are managed only as part of the order
*/
@XmlElementWrapper(name = "PlannedSettlements")
@XmlElement(name = "PlannedSettlement")
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true,mappedBy = "order")
@OrderBy("settlementDate")
protected Set<PlannedSettlement> plannedSettlements = new HashSet<PlannedSettlement>();
/**
* The consignment that this order is associated with.
*/
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "consignment_id")
@XmlTransient
@JsonIgnore
protected Consignment consignment;
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "subShipment_id")
@XmlTransient
@JsonIgnore
protected SubShipment subShipment;
/**
* Various dates relating to the order.
*/
@Embedded
@XmlElement(name = "OrderDates")
protected OrderDates orderDates = new OrderDates();
/**
* All shipping information for the order.
*/
@XmlElement(name = "ShippingInformation")
@OneToOne(cascade = CascadeType.ALL)
protected ShippingInformation shippingInformation = new ShippingInformation();
/**
* The total value of all the items on the order, it should match the value
* specified on the pro-forma invoice.
*/
@XmlAttribute
protected BigDecimal totalInvoiceValue;
/**
* Indicates that the LC can be drawn for X% more than the face value of the
* LC. Should not be less than 0 and more than 10.
*
* This should default to the the supplier's lcToleranceAbove value. If
* there is no lcToleranceAbove provided for the supplier then the
* lcToleranceAbove configured in the client setup will be used.
*/
@XmlAttribute
protected BigDecimal lcToleranceAbove;
/**
* Indicates that the LC can be drawn for X% less than the face value of the
* LC. Should not be less than 0 and more than 10.
*
* This should default to the the supplier's lcToleranceBelow value. If
* there is no lcToleranceBelow provided for the supplier then the
* lcToleranceBelow configured in the client setup will be used.
*/
@XmlAttribute
protected BigDecimal lcToleranceBelow;
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "orders_freetextcomments", joinColumns = {@JoinColumn(name = "order_id", unique = false)})
@Column(name = "reason", unique = true)
@ForeignKey(name = "fk_orders")
@XmlElementWrapper(name = "FreeTextComments")
@XmlElement(name = "FreeTextComment")
@Fetch(value = FetchMode.SELECT)
protected List<AddedComment> comments = new ArrayList<AddedComment>();
/**
* The reference displayed on the proforma invoice received from the
* supplier.
*/
@XmlAttribute
@Size(max = 255)
protected String proFormaReference;
/**
* Indicates if the unit price on an invoice includes or excludes additional
* costs (e.g.inland freight). Available options are: Factory unit price and
* Total unit price. This should default to the the supplier's unit price
* per item. If there is no unit price per item provided for the supplier
* then the unit price per item configured in the client setup will be used.
*/
@Enumerated(value = EnumType.STRING)
@XmlAttribute
protected UnitPricePerItem unitPricePerItem;
/**
* Fields about the letter of credit the order needs.
*/
@XmlElement(name = "OrderLetterOfCredit")
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@ForeignKey(name = "fk_orderletterofcredit")
protected OrderLetterOfCredit orderLetterOfCredit;
/**
* The booking reference received from the LSP.
*/
@XmlAttribute
@Size(max = 255)
protected String lspBookingReference;
/**
* The name of the vessel that the goods are loaded on.
*/
@XmlAttribute
@Size(max = 255)
protected String vesselName;
@Enumerated(EnumType.STRING)
@XmlElement(name = "ShipmentType")
protected ShipmentType shipmentType;
/**
* OrderState INITIALISED after object initialisation. (This is an internal
* state only)
*/
@NotNull(message = "State is required")
// @XmlAttribute
@Enumerated(EnumType.STRING)
protected OrderState state = OrderState.UNFINALISED;
@NotNull(message = "Business State is required")
@Enumerated(EnumType.STRING)
protected BusinessState businessState = BusinessState.ON_ORDER;
/**
* The purchase order events, used to keep track of the history.
*/
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "orders_ordersevent", joinColumns = {@JoinColumn(name = "orders_id")},
inverseJoinColumns = {@JoinColumn(name = "events_id")})
@Fetch(value = FetchMode.SELECT)
@XmlElementWrapper(name = "OrderEvents")
@XmlElement(name = "OrderEvent")
@OrderBy("createDateTime")
protected List<OrdersEvent> events = new LinkedList<OrdersEvent>();
@XmlAttribute
@Column
protected Date originalDocumentsReceivedDate;
/**
* Indicates if order was created via integration interface.
*/
@XmlAttribute
protected boolean integrated;
protected boolean uploaded = false;
@XmlAttribute
@Size(max = 255)
protected String deletedReason;
@XmlAttribute
@Temporal(TemporalType.TIMESTAMP)
protected Date addedToConsignmentDate;
/**
* Indicates whether a deal in TTM should be created for this order.
*/
@XmlAttribute
protected boolean exposureRequired = true;
@Transient
@XmlTransient
EstimateCostSummary costingSummary;
private boolean elc;
@ManyToOne(fetch = FetchType.LAZY)
@JoinFormula("(SELECT MAX(orders_activitylogs.activitylogs_id) " +
"FROM orders_activitylogs " +
"WHERE orders_activitylogs.orders_id = id)")
private ActivityLog lastActivity;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@Fetch(value = FetchMode.SELECT)
@XmlElementWrapper(name = "ICPOrderEvents")
@XmlElement(name = "ICPOrderEvent")
@OrderBy("createDateTime")
@JoinTable(name = "orders_activitylogs", joinColumns = {
@JoinColumn(name = "orders_id", unique = false)},
inverseJoinColumns = {
@JoinColumn(name = "activitylogs_id", unique = false)})
protected List<ActivityLog> activityLogs = new LinkedList<>();
// @OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY)
// @JoinTable(name = "orders_tradefinance", joinColumns = {@JoinColumn(name = "orders_id")},
// inverseJoinColumns = {@JoinColumn(name = "tradefinance_id")})
// @JsonIgnore
// private List<TradeFinance> tradeFinance;
@ManyToOne(cascade = {CascadeType.MERGE})
private SpecialRequirementConfig specialRequirementConfig;
private String specialRequirementOtherDescription;
@OneToMany(cascade = {CascadeType.ALL}, mappedBy = "order", orphanRemoval = true, fetch = FetchType.LAZY)
private Set<GoodsReceivedReceipt> goodsReceivedReceipts = new HashSet<>();
@ManyToOne(fetch = FetchType.LAZY)
@XmlElement(name = "supplierContact")
private Contact supplierContact;
@Transient
private boolean totalsInUse;
private Date stateDate;
@Enumerated(EnumType.STRING)
TradeAgreementOption defaultTradeAgreementOption = TradeAgreementOption.COUNTRY_OF_ORIGIN;
@Enumerated(EnumType.STRING)
private ItemType defaultItemType = ItemType.GENERAL;
/**
* Indicates whether an order had a booking date before.
*/
@XmlAttribute
protected boolean previouslyBooked = true;
private Long bulkOrderId;
private boolean bulkOrder;
@Basic(fetch = FetchType.LAZY)
@Formula("""
(
SELECT SUM(i.unitquantity)
FROM lineitem i
WHERE i.order_id = id
)
""")
private BigDecimal orderQuantity;
@Basic(fetch = FetchType.LAZY)
@Formula("""
(
SELECT
CASE
WHEN SUM(i.unitquantity) > 0
THEN SUM(i.sellPriceExclusiveAmount * i.unitquantity) / SUM(i.unitquantity)
ELSE 0
END
FROM lineitem i
WHERE i.order_id = id
)
""")
private BigDecimal weightedSellingPriceExclusive;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@Fetch(value = FetchMode.SELECT)
@JoinTable(name = "orders_AdditionalNotes", joinColumns = @JoinColumn(name = "orders_id"),
inverseJoinColumns = @JoinColumn(name = "notes_id"))
private Set<AdditionalNotes> additionalNotes;
private String quoteReference;
private boolean earlyOrder = false;
@ManyToOne
private ServiceProvider plannedCargoCarrier;
@ManyToOne
@XmlElement(name = "PlannedPlaceOfDischarge")
private PlaceOfDischarge plannedPlaceOfDischarge;
@ManyToOne(fetch = FetchType.LAZY)
private OrganisationalUnit company;
public enum Type {
FULL, ELC
}
public Order() {
}
public Date getStateDate() {
return stateDate;
}
public void setStateDate(Date stateDate) {
this.stateDate = stateDate;
}
public List<ActivityLog> getActivityLogs() {
return activityLogs;
}
public void setActivityLogs(List<ActivityLog> activityLogs) {
this.activityLogs = activityLogs;
}
public ActivityLog getLastActivity() {
if (this.lastActivity == null) {
return Event.getLastEvent(activityLogs);
}
return this.lastActivity;
}
// TODO - This constructor has way too many params.Should use a builder.
public Order(String number, String orderReference, OrganisationalUnit organisationalUnit, Set<LineItem> lineItems, OrderDates orderDates,
ShippingInformation shippingInformation, Currency currency, PaymentMethod paymentMethod, PaymentTerm paymentTerm,
Incoterm incoterm) {
super();
this.number = number;
this.orderReference = orderReference;
this.organisationalUnit = organisationalUnit;
this.lineItems = lineItems;
this.orderDates = orderDates;
this.shippingInformation = shippingInformation;
this.currency = currency;
this.paymentMethod = paymentMethod;
this.paymentTerm = paymentTerm;
getShippingInformation().setIncoterm(incoterm);
}
public String getCommentsAsString() {
return AddedCommentI.commentsAsString(getComments());
}
public boolean isLinkedToShipment() {
return this.getConsignment() != null && this.getConsignment().getShipment() != null;
}
public abstract OrderType getType();
@Override
public Boolean getActive() {
return !ObjectUtil.containsAll(this.state.name(), OrderState.DELETED.name(), ARCHIVED.name());
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getOrderReference() {
return orderReference;
}
public void setOrderReference(String orderReference) {
// TODO. Remove this check. Why is it here?
if (oldOrderReference == null) {
oldOrderReference = this.orderReference;
}
this.orderReference = orderReference;
}
public OrganisationalUnit getOrganisationalUnit() {
return organisationalUnit;
}
public void setOrganisationalUnit(OrganisationalUnit organisationalUnit) {
this.organisationalUnit = organisationalUnit;
}
public OrderDates getOrderDates() {
return orderDates;
}
public void setOrderDates(OrderDates orderDates) {
this.orderDates = orderDates;
}
public ShippingInformation getShippingInformation() {
return shippingInformation;
}
public void setShippingInformation(ShippingInformation shippingInformation) {
this.shippingInformation = shippingInformation;
}
@Override
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public BigDecimal getLcToleranceAbove() {
return lcToleranceAbove;
}
public void setLcToleranceAbove(BigDecimal lcToleranceAbove) {
this.lcToleranceAbove = lcToleranceAbove;
}
public BigDecimal getLcToleranceBelow() {
return lcToleranceBelow;
}
public void setLcToleranceBelow(BigDecimal lcToleranceBelow) {
this.lcToleranceBelow = lcToleranceBelow;
}
public Consignment getConsignment() {
return consignment;
}
public void setConsignment(Consignment consignment) {
this.consignment = consignment;
}
public Set<LineItem> getLineItems() {
return lineItems;
}
public void setLineItems(Set<LineItem> lineItems) {
this.lineItems = lineItems;
}
/**
* @deprecated Use getActiveLineItems.
* Needed for a JSF page where we reference the line items directly on an
* order.
*/
@Deprecated
public List<LineItem> getLineItemsList() {
Collections.sort(new ArrayList<LineItem>(lineItems));
return new ArrayList<LineItem>(lineItems);
}
public ServiceProvider getPlannedCargoCarrier() {
return plannedCargoCarrier;
}
public void setPlannedCargoCarrier(ServiceProvider plannedCargoCarrier) {
this.plannedCargoCarrier = plannedCargoCarrier;
}
public PlaceOfDischarge getPlannedPlaceOfDischarge() {
return plannedPlaceOfDischarge;
}
public void setPlannedPlaceOfDischarge(PlaceOfDischarge plannedPlaceOfDischarge) {
this.plannedPlaceOfDischarge = plannedPlaceOfDischarge;
}
public List<LineItem> getActiveLineItems() {
return PersistenceBase.getActiveList(lineItems);
}
public void addLineItem(LineItem lineItem) {
lineItem.setOrder(this);
lineItems.add(lineItem);
// Slight hack. Need to preserve the date in the case of a copy.
// Then then date will be already set.
// Another option would be to have another addLineItem(LineItem, Date)
if (lineItem.getAddedToOrderDate() == null) {
lineItem.setAddedToOrderDate(new Date());
}
calculateTotalInvoiceValue();
}
public void addLineItems(Set<LineItem> lineItems) {
int i = 1;
for (LineItem lineItem : lineItems) {
lineItem.setOrder(this);
this.lineItems.add(lineItem);
if (lineItem.getAddedToOrderDate() == null) {
//new Date(), does not guarantee unique date hence we add nano secs
lineItem.setAddedToOrderDate(DateUtils.addNanoSEcs(new Date(), i++ * 1000000));
}
}
calculateTotalInvoiceValue();
}
public void removeLineItem(LineItem lineItem) {
lineItems.remove(lineItem);
lineItem.setOrder(null);
lineItem.setAddedToOrderDate(null);
calculateTotalInvoiceValue();
}
public void removePlannedSettlement(PlannedSettlement plannedSettlement) {
plannedSettlements.remove(plannedSettlement);
}
public void clearPlannedSettlements() {
this.plannedSettlements.clear();
}
public void addPlannedSettlement(PlannedSettlement plannedSettlement) {
plannedSettlements.add(plannedSettlement);
}
// TODO. Move this out. Make it a query. This is SLOW. It is killing reports.
@Deprecated
public BigDecimal getTotalLineItemWeight() {
BigDecimal totalLineItemWeight = BigDecimal.ZERO;
BigDecimal cargoWeight = BigDecimal.ZERO;
if (consignment != null && consignment.getContainers() != null) {
for (Container container : consignment.getContainers()) {
if (container.getWeightKG() != null)
cargoWeight = cargoWeight.add(container.getWeightKG());
}
}
if (cargoWeight.compareTo(BigDecimal.ZERO) == 0) {
for (LineItem lineItem : lineItems) {
BigDecimal unitQuantity = lineItem.getUnitQuantity();
BigDecimal unitWeight = lineItem.getUnitWeight();
if (unitQuantity != null && unitWeight != null) {
totalLineItemWeight = totalLineItemWeight.add(unitQuantity.multiply(unitWeight));
}
}
} else {
totalLineItemWeight = cargoWeight;
}
return totalLineItemWeight;
}
// TODO. Move this out. Make it a query. This is SLOW. It is killing reports.
@Deprecated
public BigDecimal getTotalLineItemVolume() {
BigDecimal totalLineItemVolume = BigDecimal.ZERO;
BigDecimal cargoVolume = BigDecimal.ZERO;
if (consignment != null && consignment.getContainers() != null) {
for (Container container : consignment.getContainers()) {
if (container.getVolumeM3() != null)
cargoVolume = cargoVolume.add(container.getVolumeM3());
}
}
if (cargoVolume.compareTo(BigDecimal.ZERO) == 0) {
for (LineItem lineItem : lineItems) {
BigDecimal unitQuantity = lineItem.getUnitQuantity();
BigDecimal unitVolume = lineItem.getUnitVolume();
if (unitQuantity != null && unitVolume != null) {
totalLineItemVolume = totalLineItemVolume.add(unitQuantity.multiply(unitVolume));
}
}
} else {
totalLineItemVolume = cargoVolume;
}
return totalLineItemVolume;
}
@Override
public List<AddedComment> getComments() {
return comments;
}
@Override
public void setComments(List<AddedComment> comments) {
this.comments = comments;
}
public String getProFormaReference() {
return proFormaReference;
}
public void setProFormaReference(String proFormaReference) {
this.proFormaReference = proFormaReference;
}
public BigDecimal getTotalInvoiceValue() {
if (totalInvoiceValue == null) {
calculateTotalInvoiceValue();
}
return totalInvoiceValue;
}
public void setTotalInvoiceValue(BigDecimal totalInvoiceValue) {
this.totalInvoiceValue = totalInvoiceValue;
}
@Transient
@Override
public BigDecimal getTotalSettleableValue() {
return getTotalInvoiceValue();
}
@Override
public BigDecimal getGrossValue() {
return getTotalInvoiceValue();
}
// TODO. Move this out. Make it a query.
public void calculateTotalInvoiceValue() {
BigDecimal total = new BigDecimal("0.00");
for (LineItem lineItem : getLineItems()) {
if (!lineItem.isAdditional()) {
// Only include items added at estimate level i.e. where "additional" is false
total = total.add(ObjectUtils.firstNonNull(lineItem.getTotalCost(), BigDecimal.ZERO));
}
}
totalInvoiceValue = total;
}
public UnitPricePerItem getUnitPricePerItem() {
return unitPricePerItem;
}
public void setUnitPricePerItem(UnitPricePerItem unitPricePerItem) {
this.unitPricePerItem = unitPricePerItem;
}
public OrderLetterOfCredit getOrderLetterOfCredit() {
return orderLetterOfCredit;
}
public void setOrderLetterOfCredit(OrderLetterOfCredit orderLetterOfCredit) {
this.orderLetterOfCredit = orderLetterOfCredit;
}
public String getLspBookingReference() {
return lspBookingReference;
}
public void setLspBookingReference(String lspBookingReference) {
this.lspBookingReference = lspBookingReference;
}
public String getVesselName() {
return vesselName;
}
public void setVesselName(String vesselName) {
this.vesselName = vesselName;
}
public ShipmentType getShipmentType() {
return shipmentType;
}
public void setShipmentType(ShipmentType shipmentType) {
this.shipmentType = shipmentType;
}
@Override
public OrderState getState() {
return state;
}
@Override
public void setState(OrderState state) {
if (!this.state.equals(state)) {
this.stateDate = new Date();
}
this.state = state;
}
public BusinessState getBusinessState() {
return businessState;
}
public void setBusinessState(BusinessState businessState) {
this.businessState = businessState;
}
@Override
public String toString() {
return new ToStringBuilder(this).append("reference", orderReference).toString();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!HibernateUtils.proxyClassEquals(this, obj)) {
return false;
}
Order other = (Order) HibernateUtils.initializeAndUnproxy(obj);
return new EqualsBuilder().append(number, other.getNumber()).append(orderReference, other.getOrderReference()).isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder().append(number).append(orderReference).toHashCode();
}
public PaymentMethod getPaymentMethod() {
return paymentMethod;
}
public void setPaymentMethod(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
public PaymentTerm getPaymentTerm() {
return paymentTerm;
}
public void setPaymentTerm(PaymentTerm paymentTerm) {
this.paymentTerm = paymentTerm;
}
public BigDecimal getAmountAtIncoterm() {
// TODO Auto-generated method stub
return null;
}
public Currency getCostingCurrency() {
// TODO Auto-generated method stub
return null;
}
@Override
public Set<PlannedSettlement> getPlannedSettlements() {
return Collections.unmodifiableSet(plannedSettlements);
}
@Override
public void setPlannedSettlements(Set<PlannedSettlement> plannedSettlements) {
this.plannedSettlements = plannedSettlements;
}
public List<PlannedSettlement> getPlannedSettlementList() {
return Collections.unmodifiableList(new ArrayList<PlannedSettlement>(plannedSettlements));
}
public PlannedSettlementHelper getPlannedSettlementHelper() {
return new PlannedSettlementHelper(getPlannedSettlements());
}
@Override
public List<OrdersEvent> getEvents() {
return events;
}
public void setEvents(List<OrdersEvent> events) {
this.events = events;
}
@Override
public OrdersEvent getLastEvent() {
return Event.getLastEvent(events);
}
/**
* Determines whether or not all the line items on this order are tariffed.
*
* Loops through each line item and invokes {@link LineItem#isTariffed()}.
*
* @return if any line item in {@link #lineItems} returns false for
* {@link LineItem#isTariffed()}
*/
@Deprecated
public boolean allItemsTariffed() {
// TODO. Use a query
for (LineItem item : lineItems) {
if (!item.isTariffed()) {
return false;
}
}
return true;
}
@Override
public void accept(CostingVisitor costingVisitor) {
for (LineItem lineItem : getActiveLineItems()) {
lineItem.accept(costingVisitor);
}
costingVisitor.visit(this);
}
/**
* Helper method for the view tier. If the order is in any of these states then we will not
* allow editing of certain fields. Mostly on the Order Details tab and the Shipping tabs.
*/
@Override
public boolean inNonEditableState() {
return NON_EDITABLE_STATES.contains(state) ||
(consignment != null && consignment.getState() == ConsignmentState.AWAITING_TREASURY_RATES);
}
public boolean inNonSalesEditableState() {
return SALE_NON_EDITABLE_STATES.contains(state);
}
/**
* Gets the balance of the invoice gross value minus the current planned settlement total total.
*
* @return
*/
public BigDecimal getBalance() {
if (getTotalInvoiceValue() != null) {
int scale = MathUtils.SCALE_FOUR;
BigDecimal totalInvoiceValue = getTotalInvoiceValue();
totalInvoiceValue = MathUtils.setScale(totalInvoiceValue, scale);
BigDecimal plannedSettlementsTotalValue = getPlannedSettlementHelper().getTotalValue();
plannedSettlementsTotalValue = MathUtils.setScale(plannedSettlementsTotalValue, scale);
return totalInvoiceValue.subtract(plannedSettlementsTotalValue);
}
return null;
}
/**
* add amount given to totalInvoiceValue.
*
* @param additionalCosts- amount to add.
*/
public void addToCalculateTotalInvoiceValue(BigDecimal additionalCosts) {
calculateTotalInvoiceValue();
totalInvoiceValue = getTotalInvoiceValue().add(additionalCosts);
}
@Override
public int compareTo(Order other) {
return other.getCreated().compareTo(getCreated());
}
public Date getOriginalDocumentsReceivedDate() {
return originalDocumentsReceivedDate;
}
public void setOriginalDocumentsReceivedDate(Date originalDocumentsReceivedDate) {
this.originalDocumentsReceivedDate = originalDocumentsReceivedDate;
}
public boolean isIntegrated() {
return integrated;
}
public void setIntegrated(boolean integrated) {
this.integrated = integrated;
}
public String getDeletedReason() {
return this.deletedReason;
}
public void setDeletedReason(String deletedReason) {
this.deletedReason = deletedReason;
}
@Override
public String getKey() {
return new StringBuilder(toString()).append("-").append(hashCode()).toString();
}
public String getOldOrderReference() {
return oldOrderReference;
}
public void setOldOrderReference(String oldOrderReference) {
this.oldOrderReference = oldOrderReference;
}
public boolean orderReferenceChanged() {
return (oldOrderReference != null && orderReference != null && !orderReference.equals(oldOrderReference));
}
public OrdersEvent getFirstEvent(OrderEventType orderEventType) {
return Event.getFirstEvent(events, orderEventType);
}
public OrdersEvent getLastEvent(OrderEventType orderEventType) {
List<OrdersEvent> copyEvents = new ArrayList(events);
Collections.reverse(copyEvents);
return Event.getFirstEvent(copyEvents, orderEventType);
}
public Date getAddedToConsignmentDate() {
return addedToConsignmentDate;
}
public void setAddedToConsignmentDate(Date addedToConsignmentDate) {
this.addedToConsignmentDate = addedToConsignmentDate;
}
/**
* @return buyer or seller depending on the concrete order class.
*/
abstract public Employee getResponsibleEmployee();
abstract public void setResponsibleEmployee(Employee employee);
public boolean isExposureRequired() {
return exposureRequired;
}
public void setExposureRequired(boolean exposureRequired) {
this.exposureRequired = exposureRequired;
}
public boolean isPreviouslyBooked() {
return previouslyBooked;
}
public void setPreviouslyBooked(boolean previouslyBooked) {
this.previouslyBooked = previouslyBooked;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public abstract boolean isPurchaseOrder();
public abstract SupplierCommon getSupplierOrCustomer();
public abstract Employee getBuyer();
public abstract BigDecimal getTotalSalesValue();
public boolean inSignedOffState() {
return SIGNED_OFF_STATES.contains(state);
}
public boolean isConfirmed() {
return confirmed;
}
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
//
// public List<TradeFinance> getTradeFinance() {
// return tradeFinance;
// }
//
// public void setTradeFinance(List<TradeFinance> tradeFinance) {
// this.tradeFinance = tradeFinance;
// }
public SpecialRequirementConfig getSpecialRequirementConfig() {
return specialRequirementConfig;
}
public void setSpecialRequirementConfig(SpecialRequirementConfig specialRequirementConfig) {
this.specialRequirementConfig = specialRequirementConfig;
}
public String getSpecialRequirementOtherDescription() {
return specialRequirementOtherDescription;
}
public void setSpecialRequirementOtherDescription(String specialRequirementOtherDescription) {
this.specialRequirementOtherDescription = specialRequirementOtherDescription;
}
public Set<GoodsReceivedReceipt> getGoodsReceivedReceipts() {
return goodsReceivedReceipts;
}
@Override
public CommentType getCommentType() {
return CommentType.SHIPMENT;
}
public SubShipment getSubShipment() {
return subShipment;
}
public void setSubShipment(SubShipment subShipment) {
this.subShipment = subShipment;
}
public boolean isElc() {
return elc;
}
public void setElc(boolean elc) {
this.elc = elc;
}
public boolean isNotElcOrder() {
return !elc;
}
@Override
public OrganisationalUnit getOrderOrganisationalUnit() {
return organisationalUnit;
}
public EstimateCostSummary getCostingSummary() {
return costingSummary;
}
public void setCostingSummary(EstimateCostSummary costingSummary) {
this.costingSummary = costingSummary;
}
public Type getCostingType() {
return isElc() ? Type.ELC : Type.FULL;
}
public static enum UnlinkedOrdersType {
ELIGIBLE, INELIGIBLE
}
public Contact getSupplierContact() {
return supplierContact;
}
public void setSupplierContact(Contact supplierContact) {
this.supplierContact = supplierContact;
}
public boolean isTotalsInUse() {
return totalsInUse;
}
public void setTotalsInUse(boolean totalsInUse) {
this.totalsInUse = totalsInUse;
}
public TradeAgreementOption getDefaultTradeAgreementOption() {
return defaultTradeAgreementOption;
}
public void setDefaultTradeAgreementOption(TradeAgreementOption defaultTradeAgreementOption) {
this.defaultTradeAgreementOption = defaultTradeAgreementOption;
}
public ItemType getDefaultItemType() {
return defaultItemType;
}
public void setDefaultItemType(ItemType defaultItemType) {
this.defaultItemType = defaultItemType;
}
@Override
public String getDocumentGroupName() {
return DocumentManagementHardCoding.ORDER.name();
}
public String getDMSKey() {
//return new StringBuilder().append(getId()).toString();
return new StringBuilder().append(getOrderReference()).toString();
}
public Long getBulkOrderId() {
return bulkOrderId;
}
public void setBulkOrderId(Long bulkOrderId) {
this.bulkOrderId = bulkOrderId;
}
public boolean isBulkOrder() {
return bulkOrder;
}
public void setBulkOrder(boolean bulkOrder) {
this.bulkOrder = bulkOrder;
}
public BigDecimal getOrderQuantity() {
return orderQuantity;
}
public BigDecimal getWeightedSellingPriceExclusive() {
return weightedSellingPriceExclusive;
}
public Set<AdditionalNotes> getAdditionalNotes() {
if (additionalNotes == null)
additionalNotes = new HashSet<>();
return additionalNotes;
}
public void setAdditionalNotes(Set<AdditionalNotes> additionalNotes) {
this.additionalNotes = additionalNotes;
}
public abstract DocumentGroupState getDocumentGroupStatus();
public abstract void setDocumentGroupStatus(DocumentGroupState documentGroupStatus);
public String getQuoteReference() {
return quoteReference;
}
public void setQuoteReference(String quoteReference) {
this.quoteReference = quoteReference;
}
public boolean isUploaded() {
return uploaded;
}
public void setUploaded(boolean uploaded) {
this.uploaded = uploaded;
}
public boolean isEarlyOrder() {
return earlyOrder;
}
public void setEarlyOrder(boolean earlyOrder) {
this.earlyOrder = earlyOrder;
}
public OrganisationalUnit getCompany() {
return company;
}
public void setCompany(OrganisationalUnit company) {
this.company = company;
}
}