ActualOrder.java

package com.tradecloud.domain.document.invoice;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.costing.CostableType;
import com.tradecloud.domain.costing.CostingOrder;
import com.tradecloud.domain.costing.clean.CostingVisitor;
import com.tradecloud.domain.export.ExportCosting;
import com.tradecloud.domain.model.ordermanagement.Order;
import com.tradecloud.domain.model.ordermanagement.OrderFinance;
import com.tradecloud.domain.model.ordermanagement.TradeFinance;
import org.apache.commons.collections4.keyvalue.MultiKey;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Formula;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Entity
@Table(name = "actualorder")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ActualOrder")
@NamedQueries({
        @NamedQuery(name = "findActualOrderByNumber", query = "from ActualOrder o where o.number = :number")})
public class ActualOrder extends BaseActual<ActualConsignment, ActualLineItem> implements Comparable<ActualOrder>, CostingOrder, OrderFinance {

    @Transient
    @XmlTransient
    private Logger log = Logger.getLogger(ActualOrder.class);

    /**
     * The bidirectional link back to the parent {@link ActualConsignment}.
     */
    @ManyToOne(optional = false)
    @XmlIDREF
    private ActualConsignment actualConsignment;

    @NotNull
    @XmlAttribute(required = true)
    @XmlID
    // XML id used for setting parent ActualOrder in child ActualLineItem
    private String number;

    @NotNull
    @XmlAttribute(required = true)
    @XmlID
    // XML id used for setting parent ActualOrder in child ActualLineItem
    private String reference;

    @XmlElementWrapper(name = "ActualLineItems")
    @XmlElement(name = "ActualLineItem")
    @ForeignKey(name = "fk_actualorder")
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "actualOrder", orphanRemoval = true, fetch = FetchType.LAZY)
    @OrderBy("clcPosition,addedToOrderDate,code")
    @Fetch(value = FetchMode.SELECT)
    private List<ActualLineItem> actualLineItems = new ArrayList<ActualLineItem>();

    @NotNull
    @Column(name = "totalvalue")
    private BigDecimal totalInvoiceValue = new BigDecimal("0.00");

    @Temporal(TemporalType.TIMESTAMP)
    private Date addedToConsignmentDate;
    //estimate order currency
    @ManyToOne
    @XmlElement(name = "Currency", required = true)
    private com.tradecloud.domain.common.Currency currency;

    private String shippingReference;

    private static final long serialVersionUID = 1L;


    @Basic(fetch = FetchType.LAZY)
    @Formula(value = "(SELECT sum(actuallineitem.invoiceQuantity) FROM actuallineitem left join actualorder on " +
            "actualorder.id = actuallineitem.actualorder_id WHERE " +
            "actualorder.id = id)")
    private BigDecimal invoiceQuantity;

    @Basic(fetch = FetchType.LAZY)
    @Formula(value = "(SELECT sum(actuallineitem.orderQuantity) FROM actuallineitem left join actualorder on " +
            "actualorder.id = actuallineitem.actualorder_id WHERE " +
            "actualorder.id = id)")
    private BigDecimal orderQuantity;

    @XmlElement
    protected BigDecimal customsRateOfExchange;

    @XmlElement
    private boolean customsRateOfExchangeOverridden;

    @Transient
    private BigDecimal rate;

    @Enumerated(value = EnumType.STRING)
    @XmlAttribute
    private UnitPricePerItem unitPricePerItem;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JsonIgnore
    private List<TradeFinance> tradeFinance = new ArrayList<>();

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private ExportCosting exportCosting = new ExportCosting();

    @Basic(fetch = FetchType.LAZY)
    @Formula(value = "(SELECT sum(actuallineitem.invoiceQuantity*actuallineitem.sellPriceExclusiveAmount) FROM actuallineitem " +
            "left join actualorder on " +
            "actualorder.id = actuallineitem.actualorder_id WHERE " +
            "actualorder.id = id)")
    private BigDecimal retailValueOfOrder;

    public ActualOrder() {
    }

    public ActualOrder(String number, String reference, Long originalId, Date addedToConsignmentDate, String shippingReference) {
        super(originalId);
        this.number = number;
        this.reference = reference;
        this.addedToConsignmentDate = addedToConsignmentDate;
        this.shippingReference = shippingReference;
    }

    public ActualOrder(Order order) {
        this(order.getNumber(), order.getOrderReference(), order.getId(), order.getAddedToConsignmentDate(),
                order.getShippingInformation().getShippingReference());

    }

    public ActualOrder(ActualOrder order) {
        this(order.getNumber(), order.getReference(), order.getOriginalId(), order.addedToConsignmentDate,
                order.getShippingReference());
    }

    public ActualLineItem getLineItemWithCode(String code) {
        for (ActualLineItem lineItem : getActualLineItems()) {
            if (lineItem.getCode().equals(code)) {
                return lineItem;
            }
        }
        return null;
    }

    public String getNumber() {
        return number;
    }

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

    public String getReference() {
        return reference;
    }

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

    public List<ActualLineItem> getActualLineItems() {
        return actualLineItems;
    }

    public List<ActualLineItem> getActualLineItemList() {
        return new ArrayList<ActualLineItem>(actualLineItems);
    }

    public void setActualLineItems(List<ActualLineItem> actualLineItems) {
        this.actualLineItems = actualLineItems;
    }

    public void addActualLineItem(ActualLineItem actualLineItem) {
        actualLineItems.add(actualLineItem);
        actualLineItem.setActualOrder(this);
    }

    public ActualConsignment getActualConsignment() {
        return actualConsignment;
    }

    public void setActualConsignment(ActualConsignment consignment) {
        this.actualConsignment = consignment;
    }

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof ActualOrder)) {
            return false;
        }
        ActualOrder other = (ActualOrder) obj;
        return new EqualsBuilder().append(number, other.number)
                .append(reference, other.reference)
                .append(getParent(), other.getParent()).isEquals();
    }

    @Override
    public String toString() {
        return "ActualOrder [number=" + number + ", reference=" + reference + "]";
    }

    @Override
    public BigDecimal getOrderQuantity() {
        //if value is not set by hibernate then traverse code
        if (orderQuantity == null) {
            orderQuantity = BigDecimal.ZERO;
            for (ActualLineItem lineItem : getActualLineItems()) {
                BigDecimal lineItemOrderQuantity = lineItem.getOrderQuantity();
                if (lineItemOrderQuantity != null) {
                    orderQuantity = orderQuantity.add(lineItemOrderQuantity);
                }
            }
        }
        return orderQuantity;
    }

    @Override
    public BigDecimal getInvoiceQuantity() {
        //if value is not set by hibernate then traverse code
        if (invoiceQuantity == null) {
            invoiceQuantity = BigDecimal.ZERO;
            for (ActualLineItem lineItem : getActualLineItems()) {
                BigDecimal lineItemInvoiceQuantity = lineItem.getInvoiceQuantity();
                if (lineItemInvoiceQuantity != null) {
                    invoiceQuantity = invoiceQuantity.add(lineItemInvoiceQuantity);
                }
            }
        }
        return invoiceQuantity;
    }

    @Override
    public void setOrderQuantity(BigDecimal orderQuantity) {
        // TODO Auto-generated method stub

    }

    //for test cases
    public void _setInvoiceQuantity(BigDecimal invoiceQuantity) {
        this.invoiceQuantity = invoiceQuantity;
    }

    @Override
    public void setInvoiceQuantity(BigDecimal invoiceQuantity) {
        // TODO Auto-generated method stub

    }

    @Override
    public BigDecimal getTotalInvoiceValue() {
        return totalInvoiceValue;
    }

    @Override
    public void setTotalInvoiceValue(BigDecimal totalValue) {
        this.totalInvoiceValue = totalValue;
    }

    @Override
    public void accept(CostingVisitor costingVisitor) {
        for (ActualLineItem actualLineItem : actualLineItems) {
            actualLineItem.accept(costingVisitor);
        }

        if (costingVisitor != null) {
            costingVisitor.visit(this);
        } else {
            log.error("Null CostingVisitor passed to actualorder: " + getId() + ", " + getReference());
        }
    }

    @Override
    public void acceptVisitParentFirst(CostingVisitor costingVisitor) {
        costingVisitor.visit(this);
        for (ActualLineItem actualLineItem : actualLineItems) {
            actualLineItem.accept(costingVisitor);
        }

    }

    @Override
    public CostsInvoice getCostsInvoice() {
        return actualConsignment.getCostsInvoice();
    }

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

    @Override
    public ActualConsignment getParent() {
        return actualConsignment;
    }

    @Override
    public List<ActualLineItem> getCostedChildren() {
        return new ArrayList<ActualLineItem>(actualLineItems);
        /*
        List<ActualLineItem> results = new ArrayList<ActualLineItem>();
        for (ActualLineItem actualLineItem : getActualLineItems()) {
            results.add(actualLineItem);
        }
        return results;
        */
    }

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

    @Override
    public Object getTraversalKey() {
        return new MultiKey(ActualOrder.class, number);
    }

    public Date getAddedToConsignmentDate() {
        return addedToConsignmentDate;
    }

    public void setAddedToConsignmentDate(Date addedToConsignmentDate) {
        this.addedToConsignmentDate = addedToConsignmentDate;
    }

    @Override
    public int compareTo(ActualOrder o) {
        return addedToConsignmentDate.compareTo(o.addedToConsignmentDate);
    }

    @Override
    public boolean isOrder() {
        return true;
    }

    public Currency getCurrency() {
        return currency;
    }

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

    public String getShippingReference() {
        return shippingReference;
    }

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

    @Override
    public String getReferenceWithShippingRef() {

        return StringUtils.isEmpty(shippingReference) ? getReference() : getReference() + " - " + shippingReference;
    }

    public BigDecimal getSumUnitSellingPrice() {
        BigDecimal sumAllItems = BigDecimal.ZERO;
        for (ActualLineItem actualLineItem : getActualLineItems()) {
            if (actualLineItem.getSellPriceExclusiveAmount() != null) {
                sumAllItems = sumAllItems.add(actualLineItem.getSellPriceExclusiveAmount());
            }
        }
        return sumAllItems;
    }

    public BigDecimal getSumUnitSellingPriceInclVAT() {
        BigDecimal sumAllItems = BigDecimal.ZERO;
        for (ActualLineItem actualLineItem : getActualLineItems()) {
            if (actualLineItem.getSellPriceInclusiveAmount() != null) {
                sumAllItems = sumAllItems.add(actualLineItem.getSellPriceInclusiveAmount());
            }
        }
        return sumAllItems;
    }

    public BigDecimal getCustomsRateOfExchange() {
        return customsRateOfExchange;
    }

    public void setCustomsRateOfExchange(BigDecimal customsRateOfExchange) {
        this.customsRateOfExchange = customsRateOfExchange;
    }

    public BigDecimal getRate() {
        return rate;
    }

    public void setRate(BigDecimal rate) {
        this.rate = rate;
    }

    public UnitPricePerItem getUnitPricePerItem() {
        return unitPricePerItem;
    }

    public void setUnitPricePerItem(UnitPricePerItem unitPricePerItem) {
        this.unitPricePerItem = unitPricePerItem;
    }

    @Override
    public String getOrderReference() {
        return reference;
    }

    public List<TradeFinance> getTradeFinance() {
        return tradeFinance;
    }

    public void setTradeFinance(List<TradeFinance> tradeFinance) {
        this.tradeFinance.clear();
        if (tradeFinance != null) {
            this.tradeFinance.addAll(tradeFinance);
        }
    }

    public boolean isCustomsRateOfExchangeOverridden() {
        return customsRateOfExchangeOverridden;
    }

    public void setCustomsRateOfExchangeOverridden(boolean customsRateOfExchangeOverridden) {
        this.customsRateOfExchangeOverridden = customsRateOfExchangeOverridden;
    }

    @Override
    public ExportCosting getExportCosting() {
        return exportCosting;
    }

    public void setExportCosting(ExportCosting exportCosting) {
        this.exportCosting = exportCosting;
    }

    public BigDecimal getRetailValueOfOrder() {
        return retailValueOfOrder;
    }
}