SalesOrder.java

package com.tradecloud.domain.model.ordermanagement;

import com.tradecloud.domain.agent.Agent;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.common.Incoterm;
import com.tradecloud.domain.dms.DocumentGroupState;
import com.tradecloud.domain.document.PaymentState;
import com.tradecloud.domain.document.invoice.UnitPricePerItem;
import com.tradecloud.domain.export.DisplayContact;
import com.tradecloud.domain.export.ExportParty;
import com.tradecloud.domain.item.LineItem;
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.payment.PaymentMethod;
import com.tradecloud.domain.model.payment.PaymentTerm;
import com.tradecloud.domain.party.Consignee;
import com.tradecloud.domain.party.Employee;
import com.tradecloud.domain.party.SaleCustomer;
import com.tradecloud.domain.party.base.Contact;
import com.tradecloud.domain.place.Depot;
import com.tradecloud.domain.settlement.PlannedSettlementType;
import com.tradecloud.domain.shipment.ShippingInformation;
import com.tradecloud.domain.supplier.OrganisationalUnitSupplier;
import org.springframework.stereotype.Component;

import javax.persistence.*;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Set;

@Entity
@DiscriminatorValue("SALES_ORDER")
@Component(value = "salesorder")
@Table(name = "salesorder")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "SalesOrder")
@NamedQueries({@NamedQuery(name = "SalesOrder.findAllUnlinkedWithItems",
        query = "from SalesOrder o where o.state not in ('DELETED') and o.consignment is null and o.lineItems.size > 0"),
        @NamedQuery(name = "SalesOrder.findAllUnlinkedWithItemsForOrganisationalUnit",
                query = "from SalesOrder o where o.state not in ('DELETED') and o.consignment is null and o.lineItems.size > 0 " +
                        "and o.organisationalUnit = :organisationalUnit")})

@NamedEntityGraph(name = "graph.SalesOrderConsignment", attributeNodes = @NamedAttributeNode(value = "consignment"))
public class SalesOrder extends Order {

    private static final long serialVersionUID = 3325149164036096080L;

    @ManyToOne
    @XmlElement(name = "Seller")
    private Employee seller;

    @ManyToOne
    private Currency supplyCurrency;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @XmlElement(name = "DisplayContact")
    private DisplayContact displayContact;

    @ManyToOne(cascade = CascadeType.ALL)
    @XmlElement(name = "SaleCustomer")
    private SaleCustomer saleCustomer;

    @ManyToOne
    private Consignee consignee;

    private String additionalReference;

    @ManyToOne
    @XmlElement(name = "ExportParty")
    private ExportParty exportParty;

    private String customerReference;

    @Temporal(TemporalType.TIMESTAMP)
//    @NotNull(message = "RequiredShipmentDate is a required field")
//    @XmlElement(name = "RequiredShipmentDate", required = true)
    private Date requiredShipmentDate;

    @ManyToOne
    private Depot depot;
    @ManyToOne
    private Agent agent;

    private String packingInstruction;

    @Enumerated(EnumType.STRING)
    private SettlementBasis settlementBasis;
    @OneToOne
    private Contact reportContact;
    @Enumerated(EnumType.STRING)
    private DocumentGroupState documentGroupStatus;

    public SalesOrder() {
    }

    public SalesOrder(String number, String reference) {
        setNumber(number);
        setOrderReference(reference);
    }

    public static SalesOrderBuilder createBuilder() {
        return new SalesOrderBuilder();
    }

    private SalesOrder(String number, String orderReference, OrganisationalUnit organisationalUnit, Set<LineItem> items,
                       OrderDates orderDates, ShippingInformation shippingInformation, Currency currency,
                       PaymentMethod paymentMethod, PaymentTerm paymentTerm, Incoterm incoterm, Employee seller,
                       Date requiredShipmentDate) {
        super(number, orderReference, organisationalUnit, items, orderDates, shippingInformation, currency,
                paymentMethod, paymentTerm, incoterm);
        this.seller = seller;
        this.requiredShipmentDate = requiredShipmentDate;
    }

    public Employee getSeller() {
        return seller;
    }

    public void setSeller(Employee Seller) {
        this.seller = Seller;
    }

    @Override
    public OrderType getType() {
        return OrderType.SALES_ORDER;
    }

    public Currency getSupplyCurrency() {
        return supplyCurrency;
    }

    public DisplayContact getDisplayContact() {
        return displayContact;
    }

    public void setDisplayContact(DisplayContact displayContact) {
        this.displayContact = displayContact;
    }

    public void setSupplyCurrency(Currency supplyCurrency) {
        this.supplyCurrency = supplyCurrency;
    }

    public String getAdditionalReference() {
        return additionalReference;
    }

    public void setAdditionalReference(String additionalReference) {
        this.additionalReference = additionalReference;
    }

    public SaleCustomer getSaleCustomer() {
        return saleCustomer;
    }

    public void setSaleCustomer(SaleCustomer saleCustomer) {
        this.saleCustomer = saleCustomer;
    }

    public Consignee getConsignee() {
        return consignee;
    }

    public void setConsignee(Consignee consignee) {
        this.consignee = consignee;
    }

    @Override
    public Employee getResponsibleEmployee() {
        return getSeller();
    }

    @Override
    public void setResponsibleEmployee(Employee employee) {
        setSeller(employee);
    }

    @Override
    public boolean isExposureRequired() {
        return false;
    }

    public Contact getReportContact() {
        return reportContact;
    }

    public void setReportContact(Contact reportContact) {
        this.reportContact = reportContact;
    }

    @Override
    public String getReference() {
        return orderReference;
    }

    public static class SalesOrderBuilder {

        private String number;
        private String orderReference;
        private OrganisationalUnit organisationalUnit;
        private Currency currency;
        private PaymentMethod paymentMethod;
        private PaymentTerm paymentTerm;
        private Incoterm incoterm;
        private Set<LineItem> items;
        private OrderDates orderDates;
        private ShippingInformation shippingInformation;
        private Employee seller;
        private UnitPricePerItem unitPricePerItem;
        private Date requiredShipmentDate;

        /**
         * Private constructor to prevent instantiation.
         */
        private SalesOrderBuilder() {
        }

        public SalesOrder build() {
            validate();
            return new SalesOrder(number, orderReference, organisationalUnit, items, orderDates, shippingInformation, currency, paymentMethod,
                    paymentTerm, incoterm, seller, requiredShipmentDate);
        }

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

        public SalesOrderBuilder setOrderReference(String orderReference) {
            this.orderReference = orderReference;
            return this;
        }

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

        public SalesOrderBuilder setItems(Set<LineItem> items) {
            this.items = items;
            return this;
        }

        public SalesOrderBuilder setOrderDates(OrderDates orderDates) {
            this.orderDates = orderDates;
            return this;
        }

        public SalesOrderBuilder setShippingInformation(ShippingInformation shippingInformation) {
            this.shippingInformation = shippingInformation;
            return this;
        }

        public SalesOrderBuilder setIncoterm(Incoterm incoterm) {
            this.incoterm = incoterm;
            return this;
        }

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

        public SalesOrderBuilder setPaymentMethod(PaymentMethod paymentMethod) {
            this.paymentMethod = paymentMethod;
            return this;
        }

        public SalesOrderBuilder setPaymentTerm(PaymentTerm paymentTerm) {
            this.paymentTerm = paymentTerm;
            return this;
        }

        public SalesOrderBuilder setSeller(Employee seller) {
            this.seller = seller;
            return this;
        }

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

        private void ensureNotNull(Object object, String name) {
            if (object == null) {
                throw new IllegalArgumentException("A valid SalesOrder requires " + name + " to be set.");
            }
        }

        public SalesOrderBuilder setRequiredShipmentDate(Date requiredShipmentDate) {
            this.requiredShipmentDate = requiredShipmentDate;
            return this;
        }

        private void validate() {
            ensureNotNull(number, "number");
            ensureNotNull(orderReference, "orderReference");
            ensureNotNull(organisationalUnit, "organisationalUnit");
            ensureNotNull(items, "items");
            ensureNotNull(currency, "currency");
            ensureNotNull(paymentMethod, "paymentMethod");
            ensureNotNull(paymentTerm, "paymentTerm");
        }
    }

    // @Override
    public ExportParty getExportParty() {
        return exportParty;
    }

    public void setExportParty(ExportParty exportParty) {
        this.exportParty = exportParty;
    }

    @Override
    public boolean isPurchaseOrder() {
        return false;
    }

    @Override
    public ExportParty getSupplierOrCustomer() {
        return exportParty;
    }

    @Override
    public EstimatedPaymentBasis getEstimatedPaymentBasis() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public EstimatedPaymentBasis getEstimatedPaymentBasis2() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public ActualPaymentBasis getActualPaymentBasis() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public PlannedSettlementType getPlannedSettlementType() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public PaymentState getPaymentState() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public OrganisationalUnitSupplier getSupplier() {
        // TODO Auto-generated method stub
        return null;
    }

    public String getCustomerReference() {
        return customerReference;
    }

    public void setCustomerReference(String customerReference) {
        this.customerReference = customerReference;
    }

    public Date getRequiredShipmentDate() {
        return requiredShipmentDate;
    }

    public void setRequiredShipmentDate(Date requiredShipmentDate) {
        this.requiredShipmentDate = requiredShipmentDate;
    }

    public Depot getDepot() {
        return depot;
    }

    public void setDepot(Depot depot) {
        this.depot = depot;
    }

    public SettlementBasis getSettlementBasis() {
        return settlementBasis;
    }

    public void setSettlementBasis(SettlementBasis settlementBasis) {
        this.settlementBasis = settlementBasis;
    }

    public Agent getAgent() {
        return agent;
    }

    public void setAgent(Agent agent) {
        this.agent = agent;
    }

    public String getPackingInstruction() {
        return packingInstruction;
    }

    public void setPackingInstruction(String packingInstruction) {
        this.packingInstruction = packingInstruction;
    }

    @Override
    public Employee getBuyer() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public BigDecimal getBalance() {
        return BigDecimal.ZERO;
    }

    @Override
    public void calculateTotalInvoiceValue() {
        BigDecimal total = new BigDecimal("0.00");
        for (LineItem lineItem : getLineItems()) {
            if (!lineItem.isAdditional() && lineItem.getTotalSalesValue() != null) {
                // Only include items added at estimate level i.e. where "additional" is false
                total = total.add(lineItem.getTotalSalesValue());
            }
        }
        totalInvoiceValue = total;
    }

    @Override
    public BigDecimal getTotalSalesValue() {
        // todo store in db
        Set<LineItem> lineItems = getLineItems();
        BigDecimal sum = BigDecimal.ZERO;
        for (LineItem lineItem : lineItems) {
            sum = sum.add(lineItem.getTotalSalesValue());
        }
        return sum;
    }

    public BigDecimal getTotalCost() {
        Set<LineItem> lineItems = getLineItems();
        BigDecimal sum = BigDecimal.ZERO;
        for (LineItem lineItem : lineItems) {
            BigDecimal totalCost = lineItem.getTotalCost();
            if (totalCost != null) {
                sum = sum.add(totalCost);
            }
        }
        return sum;
    }

    public DocumentGroupState getDocumentGroupStatus() {
        return documentGroupStatus;
    }

    public void setDocumentGroupStatus(DocumentGroupState documentGroupStatus) {
        this.documentGroupStatus = documentGroupStatus;
    }
}