Consignment.java

package com.tradecloud.domain.model.ordermanagement;

import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.comment.AddedComment;
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.consignment.ConsignmentShippingInfo;
import com.tradecloud.domain.container.ConsignmentContainer;
import com.tradecloud.domain.costing.Costable;
import com.tradecloud.domain.costing.CostableCostDefinition;
import com.tradecloud.domain.costing.CostableType;
import com.tradecloud.domain.costing.CostingContextType;
import com.tradecloud.domain.costing.clean.CostingSummary;
import com.tradecloud.domain.costing.clean.CostingVisitor;
import com.tradecloud.domain.dms.DocumentManagementHardCoding;
import com.tradecloud.domain.document.CommercialCreditNote;
import com.tradecloud.domain.document.invoice.CommercialInvoice;
import com.tradecloud.domain.document.invoice.Invoiceable;
import com.tradecloud.domain.document.invoice.PlannedSettlementHelper;
import com.tradecloud.domain.document.invoice.ServiceProviderInvoice;
import com.tradecloud.domain.event.ConsignmentEvent;
import com.tradecloud.domain.event.ConsignmentEventType;
import com.tradecloud.domain.event.Event;
import com.tradecloud.domain.item.LineItem;
import com.tradecloud.domain.model.DMSLinked;
import com.tradecloud.domain.model.litereport.LiteCostingReport;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.model.shipment.ShippingMode;
import com.tradecloud.domain.party.ServiceProvider;
import com.tradecloud.domain.place.Country;
import com.tradecloud.domain.place.FinalDestination;
import com.tradecloud.domain.place.NamedPlace;
import com.tradecloud.domain.settlement.PlannedSettlement;
import com.tradecloud.domain.shipment.Shipment;
import com.tradecloud.domain.state.Stateful;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.ForeignKey;
import org.springframework.stereotype.Component;

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 java.util.stream.Collectors;

/**
 * https://connect.devstream.net/display/Dev/Consignment+Fields.
 */
@SuppressWarnings("serial")
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Component(value = "consignment")
@Table(name = "consignment", uniqueConstraints = {@UniqueConstraint(columnNames = {"number"}), @UniqueConstraint(columnNames = {"reference"})})
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@DiscriminatorColumn(name = "discriminator_value", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("IMPORT_CONSIGNMENT")
@XmlRootElement(name = "Consignment")
public class Consignment extends PersistenceBase implements Commentable<AddedComment>,
        Costable, Invoiceable, Stateful<ConsignmentState, ConsignmentEvent>,
        Exposure, DMSLinked {

    /**
     * The name of the database sequence used for generating part of the
     * consignment number.
     *
     * @see #number
     */
    public static final String NUMBER_SEQUENCE = "consignmentnumber_sequence";

    private final static Collection<ConsignmentState> NON_EDITABLE_STATES = Arrays.asList(ConsignmentState.SIGNED_OFF,
            ConsignmentState.DELETED, ConsignmentState.UNSIGNOFF_REJECTED, ConsignmentState.ARCHIVED,
            ConsignmentState.AWAITING_LSP_SIGNOFF, ConsignmentState.AWAITING_LSP_UNSIGNOFF,
            ConsignmentState.RESENT_TO_LSP, ConsignmentState.SIGNED_OFF_RESENT_TO_LC);

    private final static Collection<ConsignmentState> NON_EDITABLE_STATES_CORE = Arrays.asList(ConsignmentState.FINALISED,
            ConsignmentState.SIGNED_OFF);
    /*
     * CONSIGNMENT SCREEEN FIELDS
     */
    /**
     * One to Many TODO - I'm pretty sure if we want to cascade orders for
     * persist and merge in this situation. Should really be possible to send a
     * shipment and have it cascade down...
     */
    @XmlElementWrapper(name = "Orders")
    @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    @XmlElement(name = "Order")
    private Set<Order> orders = new LinkedHashSet<Order>();

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "shipment_id")
    @XmlTransient
    private Shipment shipment;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "consignment", orphanRemoval = true, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    @XmlElementWrapper(name = "Containers")
    @XmlElement(name = "Container")
    @OrderBy("created")
    private Set<ConsignmentContainer> containers = new LinkedHashSet<ConsignmentContainer>();

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "consignment_freetextcomments", joinColumns = {@JoinColumn(name = "consignment_id", unique = false)})
    @Column(name = "reason", unique = true)
    @ForeignKey(name = "fk_consignment")
    @Fetch(value = FetchMode.SELECT)
    @XmlElementWrapper(name = "FreeTextComments")
    @XmlElement(name = "FreeTextComment")
    private List<AddedComment> comments = new ArrayList<AddedComment>();

    @XmlAttribute
    @NotNull
    @Column(nullable = false)
    @Size(max = 255)
    private String number;

    @XmlAttribute
    @NotNull
    @Size(max = 255)
    private String reference;

    @NotNull
    @XmlElement(name = "ShippingInfo")
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @ForeignKey(name = "fk_shippingInfo")
    private ConsignmentShippingInfo shippingInfo = new ConsignmentShippingInfo();

    //check moved to service layer.
//    @NotNull
    @XmlElement(name = "LatestShipmentDate")
    @Temporal(TemporalType.TIMESTAMP)
    private Date latestShipmentDate;

    //check moved to service layer.
//    @NotNull
    @XmlElement(name = "ArrivalDateAtPlaceOfDischarge")
    @Temporal(TemporalType.TIMESTAMP)
    private Date arrivalDateAtPlaceOfDischarge;

    /**
     * ConsignmentState INITIALISED after object initialisation. (This is an
     * internal state only)
     */
    @NotNull
    @XmlElement(name = "State")
    @Enumerated(EnumType.STRING)
    private ConsignmentState state = ConsignmentState.UNFINALISED;

    //When awaiting rate state is resolved we need to know the state to go to.
    @XmlElement(name = "awaitingRateNextState")
    @Enumerated(EnumType.STRING)
    private ConsignmentState awaitingRateNextState;

    /**
     * The purchase order events, used to keep track of the history.
     */
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    @XmlElementWrapper(name = "ConsignmentEvents")
    @XmlElement(name = "ConsignmentEvent")
    @OrderBy("createDateTime")
    private List<ConsignmentEvent> events = new LinkedList<ConsignmentEvent>();

    /**
     * Payment Information.
     */
    @XmlAttribute
    @Size(max = 255)
    private String paymentReference;

    @XmlAttribute
    @Size(max = 255)
    private String loadingWarehouseReference;

    @ManyToOne
    @XmlElement(name = "OrganisationalUnit")
    private OrganisationalUnit organisationalUnit;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastCostRefresh;

    @XmlAttribute
    private boolean readOnly;

    @XmlAttribute
    private boolean costed;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date costedDate;

    @XmlAttribute
    private boolean completelySignedOff;

    @XmlAttribute
    private boolean signedOffByBuyerSeller;

    @XmlAttribute
    private boolean signedOffByFinSupervisor;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date buyerSellerSignOffDate;

    @XmlAttribute
    @Size(max = 255)
    private String buyerSellerSignOffBy;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date finSupervisorSignOffDate;

    @XmlAttribute
    @Size(max = 255)
    private String finSupervisorSignOffBy;

    @ManyToOne
    @XmlElement(name = "CountryOfOrigin")
    private Country countryOfOrigin;

    @ManyToOne(fetch = FetchType.LAZY)
    @XmlElement(name = "FinalDestination")
    private FinalDestination finalDestination;
    //work around as hibernate does not filter By DiscriminatorColumn on Criteria.
    @SuppressWarnings("unused")
    //we do not want user to modify this value
    @Column(insertable = false, updatable = false)
    private String discriminator_value;

    /**
     * The currency of the linked orders. Needed here to compare with the order in the case where it may have changed since initial creation/linking.
     * This should default to the the currency of the first linked order or the currency configured in
     * the client setup will be used.
     */
    @ManyToOne
    @XmlElement(name = "Currency")
    private Currency currency;

    /**
     * Named Place is an Incoterm terminology as it refers to where risk passes
     * ito various incoterms. It's usually a city name, but not always, eg. it
     * could for instance be an airport or a port. We just need a way to be able
     * to handle places of various types in a single entity/table.
     */
    @ManyToOne
    @XmlElement(name = "NamedPlace")
    private NamedPlace namedPlace;

    // TODO - what?
    private Integer indirectCostAllocationMethod;

    @XmlAttribute
    private boolean signedOffSentToForex;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date creationDate;

    @XmlElement(name = "LogisticsServiceProvider")
    @ManyToOne(fetch = FetchType.LAZY)
    private ServiceProvider logisticsServiceProvider;

    @XmlAttribute
    private boolean sellingPriceExclusive;

    @XmlAttribute
    private boolean letterOfCreditProcessed;

    @XmlAttribute
    @Size(max = 255)
    private String shippingAdvice;

    @XmlAttribute
    private Integer leadTimeInDays;

    // TODO. This should not cascade
    @XmlElementWrapper(name = "Invoices")
    @XmlElement(name = "Invoice")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    private Set<CommercialInvoice> commercialInvoices = new HashSet<CommercialInvoice>();

    // TODO. This should not cascade
    @XmlElementWrapper(name = "CommercialCreditNotes")
    @XmlElement(name = "CommercialCreditNote")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    private Set<CommercialCreditNote> commercialCreditNotes = new HashSet<CommercialCreditNote>();

    // TODO. This should not cascade
    @XmlElementWrapper(name = "ServiceProviderInvoices")
    @XmlElement(name = "ServiceProviderInvoice")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SELECT)
    private Set<ServiceProviderInvoice> serviceProviderInvoices = new HashSet<ServiceProviderInvoice>();

    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true, fetch = FetchType.LAZY)
    @ForeignKey(name = "fk_costablecostdefinition")
    @XmlElement(name = "ConsignmentCostableCostDefinition")
    private CostableCostDefinition costableCostDefinition;

    @XmlAttribute
    @Temporal(TemporalType.TIMESTAMP)
    private Date addedToShipmentDate;

    private boolean liteConsignment;

    private transient String consignmentReportUrl;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private LiteCostingReport liteCostingReport;

    private String forexOptionSelected;

    private boolean elc;

    private transient BigDecimal quantities;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Package> packages;

    private transient String shippingReference = "";

    private transient CostingSummary estimateCostSummary;

    /**
     * Simple constructor.
     */
    public Consignment() {
    }

    public Consignment(String number, String reference) {
        this.number = number;
        this.reference = reference;
    }

    @Override
    public Boolean getActive() {
        return state != ConsignmentState.DELETED;
    }

    /**
     * Convenience method that adds the supplied container into the member
     * collection of containers. The consignment reference is set onto this
     * container also.
     *
     * @param container The container to add to the collection
     */
    public void addContainer(ConsignmentContainer container) {
        container.setConsignment(this);
        containers.add(container);
    }

    /**
     * Convenience method that removes the supplied container from the member
     * collection of containers. The consignment reference on the container is
     * set to null and then the container is removed from the member collection.
     *
     * @param container The container to remove from the member collection
     */
    public void removeContainer(ConsignmentContainer container) {
        container.setConsignment(null);
        containers.remove(container);
    }

    /**
     * Convenience method that adds the supplied service provider invoice into
     * the member collection of invoices. The consignment reference is set onto
     * this invoice also.
     *
     * @param serviceProviderInvoice The invoice to add to the member collection
     */
    public void addServiceProviderInvoice(ServiceProviderInvoice serviceProviderInvoice) {
        serviceProviderInvoice.setConsignment(this);
        serviceProviderInvoices.add(serviceProviderInvoice);
    }

    /**
     * Convenience method that removes the supplied service provider invoice
     * from the member collection of invoices. The consignment reference on the
     * invoice is set to null and then the invoice is removed from the member
     * collection.
     *
     * @param serviceProviderInvoice The invoice to remove from the member collection
     */
    public void removeServiceProviderInvoice(ServiceProviderInvoice serviceProviderInvoice) {
        serviceProviderInvoice.setConsignment(null);
        serviceProviderInvoices.remove(serviceProviderInvoice);
    }

    public void removeCommercialInvoice(CommercialInvoice commercialInvoice) {
        commercialInvoice.setConsignment(null);
        commercialInvoices.remove(commercialInvoice);
    }

    public void addCommercialInvoice(CommercialInvoice commercialInvoice) {
        commercialInvoice.setConsignment(this);
        commercialInvoices.add(commercialInvoice);
    }

    public void removeCommercialCreditNote(CommercialCreditNote commercialCreditNote) {
        commercialCreditNote.setConsignment(null);
        commercialCreditNotes.remove(commercialCreditNote);
    }

    public void addCommercialCreditNote(CommercialCreditNote commercialCreditNote) {
        commercialCreditNote.setConsignment(this);
        commercialCreditNotes.add(commercialCreditNote);
    }

    public Set<Order> getOrders() {
        return orders;
    }

    public List<Order> getOrdersList() {
        return new ArrayList<Order>(orders);
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

    public List<Order> getActiveOrders() {
        return PersistenceBase.getActiveList(orders);
    }

    @Override
    public Set<ConsignmentContainer> getContainers() {
        return containers;
    }

    public void setContainers(Set<ConsignmentContainer> containers) {
        this.containers = containers;
    }

    public String getBuyerSellerSignOffBy() {
        return buyerSellerSignOffBy;
    }

    public void setBuyerSellerSignOffBy(String buyerSellerSignOffBy) {
        this.buyerSellerSignOffBy = buyerSellerSignOffBy;
    }

    public Date getBuyerSellerSignOffDate() {
        return buyerSellerSignOffDate;
    }

    public void setBuyerSellerSignOffDate(Date buyerSellerSignOffDate) {
        this.buyerSellerSignOffDate = buyerSellerSignOffDate;
    }

    public boolean isCompletelySignedOff() {
        return completelySignedOff;
    }

    public boolean getCompletelySignedOff() {
        return completelySignedOff;
    }

    public void setCompletelySignedOff(boolean completelySignedOff) {
        this.completelySignedOff = completelySignedOff;
    }

    public boolean isCosted() {
        return costed;
    }

    public void setCosted(boolean costed) {
        this.costed = costed;
    }

    public Date getCostedDate() {
        return costedDate;
    }

    public void setCostedDate(Date costedDate) {
        this.costedDate = costedDate;
    }

    public Country getCountryOfOrigin() {
        return countryOfOrigin;
    }

    public void setCountryOfOrigin(Country countryOfOrigin) {
        this.countryOfOrigin = countryOfOrigin;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @Override
    public OrganisationalUnit getOrganisationalUnit() {
        return organisationalUnit;
    }

    public void setOrganisationalUnit(OrganisationalUnit organisationalUnit) {
        this.organisationalUnit = organisationalUnit;
    }

    @Override
    public Date getArrivalDateAtPlaceOfDischarge() {
        return arrivalDateAtPlaceOfDischarge;
    }

    public void setArrivalDateAtPlaceOfDischarge(Date arrivalDateAtPlaceOfDischarge) {
        this.arrivalDateAtPlaceOfDischarge = arrivalDateAtPlaceOfDischarge;
    }

    public NamedPlace getNamedPlace() {
        return this.namedPlace;
    }

    public void setNamedPlace(NamedPlace namedPlace) {
        this.namedPlace = namedPlace;
    }

    public String getFinSupervisorSignOffBy() {
        return finSupervisorSignOffBy;
    }

    public void setFinSupervisorSignOffBy(String finSupervisorSignOffBy) {
        this.finSupervisorSignOffBy = finSupervisorSignOffBy;
    }

    public Date getFinSupervisorSignOffDate() {
        return finSupervisorSignOffDate;
    }

    public void setFinSupervisorSignOffDate(Date finSupervisorSignOffDate) {
        this.finSupervisorSignOffDate = finSupervisorSignOffDate;
    }

    @Override
    public Incoterm getIncoterm() {
        return getShippingInfo().getIncoterm();
    }

    public int getIndirectCostAllocationMethod() {
        return indirectCostAllocationMethod;
    }

    public void setIndirectCostAllocationMethod(int indirectCostAllocationMethod) {
        this.indirectCostAllocationMethod = indirectCostAllocationMethod;
    }

    public Date getLastCostRefresh() {
        return lastCostRefresh;
    }

    public void setLastCostRefresh(Date lastCostRefresh) {
        this.lastCostRefresh = lastCostRefresh;
    }

    public boolean isLetterOfCreditProcessed() {
        return letterOfCreditProcessed;
    }

    public void setLetterOfCreditProcessed(boolean letterOfCreditProcessed) {
        this.letterOfCreditProcessed = letterOfCreditProcessed;
    }

    public String getShippingAdvice() {
        return shippingAdvice;
    }

    public void setShippingAdvice(String shippingAdvice) {
        this.shippingAdvice = shippingAdvice;
    }

    public String getLoadingWarehouseReference() {
        return loadingWarehouseReference;
    }

    public void setLoadingWarehouseReference(String loadingWarehouse) {
        this.loadingWarehouseReference = loadingWarehouse;
    }

    public Integer getLeadTimeInDays() {
        return leadTimeInDays;
    }

    public void setLeadTimeInDays(Integer leadTimeInDays) {
        this.leadTimeInDays = leadTimeInDays;
    }

    public ServiceProvider getLogisticsServiceProvider() {
        return logisticsServiceProvider;
    }

    public void setLogisticsServiceProvider(ServiceProvider logisticsServiceProvider) {
        this.logisticsServiceProvider = logisticsServiceProvider;
    }

    public String getPaymentReference() {
        return paymentReference;
    }

    public void setPaymentReference(String paymentReference) {
        this.paymentReference = paymentReference;
    }

    public boolean isReadOnly() {
        return readOnly;
    }

    public void setReadOnly(boolean readOnly) {
        this.readOnly = readOnly;
    }

    public boolean isSellingPriceExclusive() {
        return sellingPriceExclusive;
    }

    public void setSellingPriceExclusive(boolean sellingPriceExclusive) {
        this.sellingPriceExclusive = sellingPriceExclusive;
    }

    public Shipment getShipment() {
        return shipment;
    }

    public void setShipment(Shipment shipment) {
        this.shipment = shipment;
    }

    @Override
    public ShippingMode getShippingMode() {
        return getShippingInfo().getShippingMode();
    }

    @Override
    public ShippingMode getMultiModalShippingMode() {
        return getShippingInfo().getMultiModalShippingMode();
    }

    public boolean isSignedOffByConsigneeSeller() {
        return signedOffByBuyerSeller;
    }

    public void setSignedOffByConsigneeSeller(boolean signedOffByBuyerSeller) {
        this.signedOffByBuyerSeller = signedOffByBuyerSeller;
    }

    public boolean isSignedOffByFinSupervisor() {
        return signedOffByFinSupervisor;
    }

    public void setSignedOffByFinSupervisor(boolean signedOffByFinSupervisor) {
        this.signedOffByFinSupervisor = signedOffByFinSupervisor;
    }

    public boolean isSignedOffSentToForex() {
        return signedOffSentToForex;
    }

    public void setSignedOffSentToForex(boolean signedOffSentToForex) {
        this.signedOffSentToForex = signedOffSentToForex;
    }

    public boolean isSignedOffByBuyerSeller() {
        return signedOffByBuyerSeller;
    }

    public void setSignedOffByBuyerSeller(boolean signedOffByBuyerSeller) {
        this.signedOffByBuyerSeller = signedOffByBuyerSeller;
    }

    public String getReference() {
        return reference;
    }

    public void setReference(String reference) {
        this.reference = reference;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    @Override
    public List<AddedComment> getComments() {
        return comments;
    }

    @Override
    public void setComments(List<AddedComment> comments) {
        this.comments = comments;
    }

    public OrganisationalUnit getDivision() {
        return organisationalUnit;
    }

    public void setDivision(OrganisationalUnit organisationalUnit) {
        this.organisationalUnit = organisationalUnit;
    }

    public FinalDestination getFinalDestination() {
        return finalDestination;
    }

    public void setFinalDestination(FinalDestination finalDestination) {
        this.finalDestination = finalDestination;
    }

    public void setIndirectCostAllocationMethod(Integer indirectCostAllocationMethod) {
        this.indirectCostAllocationMethod = indirectCostAllocationMethod;
    }

    public void addOrder(Order order) {
        order.setConsignment(this);
        orders.add(order);
        // TODO: Work around the copy case
        if (order.getAddedToConsignmentDate() == null) {
            order.setAddedToConsignmentDate(new Date());
        }
        this.elc = order.isElc();
    }

    public void addOrders(Collection<? extends Order> orders) {
        for (Order order : orders) {
            addOrder(order);
        }
    }

    public void removeOrder(Order order) {
        order.setConsignment(null);
        order.setAddedToConsignmentDate(null);
        orders.remove(order);
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .append(number)
                .append(reference)
                .append(state)
                .toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!HibernateUtils.proxyClassEquals(this, obj)) {
            return false;
        }
        Consignment other = (Consignment) obj;
        return new EqualsBuilder()
                .append(number, other.getNumber())
                .append(reference, other.getReference())
                .append(state, other.getState())
                .isEquals();
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("reference", reference).toString();
    }

    @Override
    public CostableType getCostableType() {
        return CostableType.CONSIGNMENT;
    }

    /**
     * Costable method required to calculate the customs duty total.
     */
    @Override
    public List<LineItem> getLineItems() {
        List<LineItem> lineItems = new ArrayList<LineItem>();
        for (Order order : getOrders()) {
            lineItems.addAll(order.getLineItems());
        }
        return lineItems;
    }

    @Override
    public Set<CommercialInvoice> getCommercialInvoices() {
        return Collections.unmodifiableSet(commercialInvoices);
    }

    @Override
    public void setCommercialInvoices(Set<CommercialInvoice> commercialInvoices) {
        this.commercialInvoices = commercialInvoices;
    }

    public List<CommercialInvoice> getActiveCommercialInvoices() {
        return PersistenceBase.getActiveList(commercialInvoices);
    }

    /**
     * @return
     * @deprecated Use getActiveCommercialCreditNotes.
     */
    @Deprecated
    public List<CommercialCreditNote> getCommercialCreditNoteList() {
        return new ArrayList<CommercialCreditNote>(commercialCreditNotes);
    }

    @Override
    public Set<CommercialCreditNote> getCommercialCreditNotes() {
        return Collections.unmodifiableSet(commercialCreditNotes);
    }

    @Override
    public void setCommercialCreditNotes(Set<CommercialCreditNote> commercialCreditNotes) {
        this.commercialCreditNotes = commercialCreditNotes;
    }

    public List<CommercialCreditNote> getActiveCommercialCreditNotes() {
        return PersistenceBase.getActiveList(commercialCreditNotes);
    }

    /**
     * @return
     * @deprecated Use getActiveCommercialInvoices.
     */
    @Deprecated
    public List<CommercialInvoice> getCommercialInvoiceList() {
        return new ArrayList<CommercialInvoice>(commercialInvoices);
    }

    @Override
    public Set<ServiceProviderInvoice> getServiceProviderInvoices() {
        return serviceProviderInvoices;
    }

    @Override
    public void setServiceProviderInvoices(Set<ServiceProviderInvoice> serviceProviderInvoices) {
        this.serviceProviderInvoices = serviceProviderInvoices;
    }

    public List<ServiceProviderInvoice> getActiveServiceProviderInvoices() {
        return PersistenceBase.getActiveList(serviceProviderInvoices);
    }

    /**
     * @return
     * @deprecated Use getActiveServiceProviderInvoices.
     */
    @Deprecated
    public List<ServiceProviderInvoice> getServiceProviderInvoiceList() {
        return new ArrayList<ServiceProviderInvoice>(serviceProviderInvoices);
    }

    public Date getLatestShipmentDate() {
        return latestShipmentDate;
    }

    /**
     * tr-220.  OLSD is the LSD of a consignment when a consignment is FINALISED.
     *
     * @param latestShipmentDate
     */
    public void setLatestShipmentDate(Date latestShipmentDate) {
        this.latestShipmentDate = latestShipmentDate;

    }

    public ConsignmentContainer getContainerWithId(Long containerId) {
        for (ConsignmentContainer container : getContainers()) {
            if (container.getId().equals(containerId)) {
                return container;
            }
        }
        return null;
    }

    @Override
    public ConsignmentState getState() {
        return state;
    }

    @Override
    public void setState(ConsignmentState state) {
        this.state = state;
    }

    @Override
    public List<ConsignmentEvent> getEvents() {
        return events;
    }

    public void setEvents(List<ConsignmentEvent> events) {
        this.events = events;
    }

    @Override
    public ConsignmentEvent getLastEvent() {
        return Event.getLastEvent(events);
    }

    @Override
    public void accept(CostingVisitor costingVisitor) {
        for (Order order : getActiveOrders()) {
            order.accept(costingVisitor);
        }
        costingVisitor.visit(this);
    }

    public void clearAllDocuments() {
        serviceProviderInvoices.clear();
        commercialInvoices.clear();
        commercialCreditNotes.clear();
    }

    public Set<PlannedSettlement> getPlannedSettlements() {
        Set<PlannedSettlement> plannedSettlements = new HashSet<PlannedSettlement>();
        for (Order order : getOrders()) {
            plannedSettlements.addAll(order.getPlannedSettlements());
        }
        return plannedSettlements;
    }

    /**
     * Wraps the Set with some useful helper methods.
     *
     * @return
     */
    public PlannedSettlementHelper getPlannedSettlementHelper() {
        return new PlannedSettlementHelper(getPlannedSettlements());
    }

    public void setShippingInfo(ConsignmentShippingInfo shippingInfo) {
        this.shippingInfo = shippingInfo;
    }

    public ConsignmentShippingInfo getShippingInfo() {
        return shippingInfo;
    }

    public Currency getCurrency() {
        return currency;
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    /**
     * Helper method for the view tier. If the consignment is in any of these states then we will not
     * allow editing of certain fields.
     */
    @Deprecated
    public boolean disabled() {
        return inNonEditableState();
    }

    @Override
    public boolean inNonEditableState() {
        return NON_EDITABLE_STATES.contains(state);
    }

    public boolean inNonEditableStateLite() {
        return NON_EDITABLE_STATES_CORE.contains(state);
    }

    @Override
    public String getKey() {
        return new StringBuilder(toString()).append("-").append(hashCode()).toString();
    }

    public Date getAddedToShipmentDate() {
        return addedToShipmentDate;
    }

    public void setAddedToShipmentDate(Date addedToShipmentDate) {
        this.addedToShipmentDate = addedToShipmentDate;
    }

    @Override
    public CostableCostDefinition getCostableCostDefinition() {
        return costableCostDefinition;
    }

    @Override
    public void setCostableCostDefinition(CostableCostDefinition costableCostDefinition) {
        this.costableCostDefinition = costableCostDefinition;
    }

    @Override
    public CostingContextType getCostingContextType() {
        return getConsignmentType() == ConsignmentType.IMPORT_CONSIGNMENT ? CostingContextType.IMPORT : CostingContextType.EXPORT;
    }

    public ConsignmentState getAwaitingRateNextState() {
        return awaitingRateNextState;
    }

    public void setAwaitingRateNextState(ConsignmentState awaitingRateNextState) {
        this.awaitingRateNextState = awaitingRateNextState;
    }

    public void trimFields() {
        if (reference != null) {
            setReference(getReference().trim());
        }
    }

    public String getConsignmentReportUrl() {
        return consignmentReportUrl;
    }

    public void setConsignmentReportUrl(String consignmentReportUrl) {
        this.consignmentReportUrl = consignmentReportUrl;
    }

    public String getDiscriminator_value() {
        return discriminator_value;
    }

    public ConsignmentType getConsignmentType() {
        if (this.getOrders() != null && this.getOrders().size() > 0) {
            for (Order order : this.getOrders()) {
                if (order instanceof SalesOrder) {
                    return ConsignmentType.EXPORT_CONSIGNMENT;
                } else {
                    return ConsignmentType.IMPORT_CONSIGNMENT;
                }
            }
        }
        return ConsignmentType.IMPORT_CONSIGNMENT;
    }

    public ConsignmentEvent getEvent(ConsignmentEventType consignmentEventType) {
        List<ConsignmentEvent> events = getEvents();
        for (ConsignmentEvent event : events) {
            if (event.getEventType() == consignmentEventType) {
                return event;
            }
        }
        return null;
    }

    public boolean isLiteConsignment() {
        return liteConsignment;
    }

    public void setLiteConsignment(boolean liteConsignment) {
        this.liteConsignment = liteConsignment;
    }

    public LiteCostingReport getLiteCostingReport() {
        return liteCostingReport;
    }

    public void setLiteCostingReport(LiteCostingReport liteCostingReport) {
        this.liteCostingReport = liteCostingReport;
    }

    public String getForexOptionSelected() {
        return forexOptionSelected;
    }

    public void setForexOptionSelected(String forexOptionSelected) {
        this.forexOptionSelected = forexOptionSelected;
    }

    public String getDMSKey() {
        return new StringBuilder().append(getId()).toString();
    }

    @Override
    public CommentType getCommentType() {
        return CommentType.CONSIGNMENT;
    }

    public boolean isElc() {
        return elc;
    }

    public void setElc(boolean elc) {
        this.elc = elc;
    }

    public BigDecimal getQuantities() {
        return quantities;
    }

    public void setQuantities(BigDecimal quantities) {
        this.quantities = quantities;
    }

    public List<Package> getPackages() {
        return packages;
    }

    public void setPackages(List<Package> packages) {
        this.packages = packages;
    }

    @Override
    public Consignment initialize() {
        Consignment initialize = (Consignment) super.initialize();
        HibernateUtils.initializeAndUnproxy(initialize.getServiceProviderInvoices());
        HibernateUtils.initializeAndUnproxy(initialize.getCommercialInvoices());
        HibernateUtils.initializeAndUnproxy(initialize.getCommercialCreditNotes());
        HibernateUtils.initializeAndUnproxy(initialize.getContainers());
        return initialize;
    }

    @Override
    public String getDocumentGroupName() {
        switch (getShippingMode()) {
            case AIR:
                return DocumentManagementHardCoding.CONSIGNMENT_AIR.getDocumentManagementHardCodedName();
            case SEA:
                return DocumentManagementHardCoding.CONSIGNMENT_SEA.getDocumentManagementHardCodedName();
            case ROAD:
                return DocumentManagementHardCoding.CONSIGNMENT_ROAD.getDocumentManagementHardCodedName();
            default:
                return null;
        }
    }

    public String getShippingReference() {
        if (shippingReference == null || shippingReference.isEmpty()) {
            shippingReference = orders.stream().filter(order -> order.getShippingInformation()
                            .getShippingReference() != null).map(order -> order.getShippingInformation().getShippingReference())
                    .collect(Collectors.joining(";"));
        }
        return shippingReference;
    }

    public void setShippingReference(String shippingReference) {
        this.shippingReference = shippingReference;
    }

    public boolean hasOneOrder() {
        return orders.size() == 1;
    }

    public boolean hasManyOrders() {
        return orders.size() > 1;
    }

    public CostingSummary getEstimateCostSummary() {
        return estimateCostSummary;
    }

    public void setEstimateCostSummary(CostingSummary estimateCostSummary) {
        this.estimateCostSummary = estimateCostSummary;
    }
}