CommercialInvoice.java

package com.tradecloud.domain.document.invoice;

import com.tradecloud.domain.configuration.clearing.za.ClearingPaymentTerm;
import com.tradecloud.domain.configuration.clearing.za.PermitType;
import com.tradecloud.domain.document.DocumentState;
import com.tradecloud.domain.document.DocumentType;
import com.tradecloud.domain.document.PaymentState;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.settlement.PlannedSettlement;
import com.tradecloud.domain.settlement.PlannedSettlementType;
import com.tradecloud.domain.supplier.OrganisationalUnitSupplier;
import org.apache.commons.collections4.keyvalue.MultiKey;
import org.springframework.stereotype.Component;

import javax.persistence.*;
import javax.xml.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;

/**
 * The commercial invoice.
 * Used for capturing direct or supply costs from suppliers
 *
 * @author ronan
 */
@Entity
@Component(value = "commercialinvoice")
@Table(name = "commercialinvoice")
@NamedQueries({
        @NamedQuery(name = "commercialInvoice.byShipment",
                query = "from CommercialInvoice ci where ci.shipment.id = :id and ci.state != 'DELETED'"),
        @NamedQuery(name = "commercialInvoice.byReference",
                query = "from CommercialInvoice ci where ci.reference = :reference"),
        @NamedQuery(name = "commercialInvoice.byReferenceAndSupplier",
                query = "from CommercialInvoice ci where ci.reference = :reference and ci.supplier = :supplier"),
        @NamedQuery(name = "commercialInvoice.byIdWithPlannedSettlementsLoaded",
                query = "from CommercialInvoice ci left join fetch ci.plannedSettlements where ci.id=:id")})
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "CommercialInvoice")
public class CommercialInvoice extends BaseCommercialInvoice {

    private static final long serialVersionUID = 1L;
    @XmlAttribute
    private boolean closedOff;
    private String permitNumber;
    @Enumerated(EnumType.STRING)
    private PermitType permitType;

    public final static Collection<DocumentState> PAYABLE_STATES = Arrays.asList(DocumentState.SIGNED_OFF, DocumentState.SENT_TO_ERP,
            DocumentState.AWAITING_TREASURY_RATES, DocumentState.COMPLETE, DocumentState.FINALISED,
            DocumentState.PAYMENT_INITIATED, DocumentState.REJECTED_BY_ERP, DocumentState.ACCEPTED_BY_ERP);

    /**
     * Set of planned settlements contained on the invoice.
     */
    @XmlElementWrapper(name = "PlannedSettlements")
    @XmlElement(name = "PlannedSettlement")
    // left out CascadeType.MERGE, do manual merge or fix CascadeType.MERGE
    // issues.when saving CI.
    @OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true,
            fetch = FetchType.LAZY,mappedBy = "invoice")
    @OrderBy("settlementDate, amount")
    private Set<PlannedSettlement> plannedSettlements = new HashSet<>();
    @Enumerated(EnumType.STRING)
    private ClearingPaymentTerm clearingPaymentTerm;
    @Transient
    private PlannedSettlementHelper plannedSettlementHelper;

    public boolean isClosedOff() {
        return closedOff;
    }

    public void setClosedOff(boolean closedOff) {
        this.closedOff = closedOff;
    }

    @Override
    public Set<PlannedSettlement> getPlannedSettlements() {
        return plannedSettlements;
    }

    public CommercialInvoice() {
    }

    public CommercialInvoice(OrganisationalUnit organisationalUnit, OrganisationalUnitSupplier supplier, BigDecimal quantity,
                             UnitPricePerItem unitPricePerItem, Set<PlannedSettlement> plannedSettlements) {
        super(organisationalUnit, supplier, quantity, unitPricePerItem);
        this.plannedSettlements = plannedSettlements;

    }

    /**
     * Wraps the Set with some useful helper methods.
     *
     * @return
     */
    @Override
    public PlannedSettlementHelper getPlannedSettlementHelper() {
        if (plannedSettlementHelper == null) {
            plannedSettlementHelper = new PlannedSettlementHelper(getPlannedSettlements());
        }
        // reset the planned settlements every time this helper is retrieved
        plannedSettlementHelper.setPlannedSettlements(plannedSettlements);
        return plannedSettlementHelper;
    }

    @Override
    public List<PlannedSettlement> getPlannedSettlementList() {
        return new ArrayList<>(plannedSettlements);
    }

    @Override
    public void setPlannedSettlements(Set<PlannedSettlement> plannedSettlements) {
        this.plannedSettlements = plannedSettlements;
    }

    @Override
    public DocumentType getDocumentType() {
        return DocumentType.COMMERCIAL_INVOICE;
    }

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

    public void addPlannedSettlement(PlannedSettlement plannedSettlement) {
        plannedSettlements.add(plannedSettlement);
    }

    public void removePlannedSettlement(PlannedSettlement plannedSettlement) {
        plannedSettlements.remove(plannedSettlement);
    }

    @Override
    public void clearPlannedSettlements() {
        plannedSettlements.clear();
    }

    @Override
    public BigDecimal getWeightedAverageForwardRateOfExchange() {
        return getPlannedSettlementHelper().getWeightedAverageForwardRateOfExchange();
    }

    @Override
    public BigDecimal getWeightedAverageSpotRateOfExchange() {
        return getPlannedSettlementHelper().getWeightedAverageSpotRateOfExchange();
    }

    @Override
    public BigDecimal getCostingCurrencyTotalValue() {
        return getPlannedSettlementHelper().getCostingCurrencyTotalValue();
    }

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

    @Override
    public PaymentState getPaymentState() {
        return PaymentState.UNSETTLED;
    }

    @Override
    public PlannedSettlementType getPlannedSettlementType() {
        return PlannedSettlementType.COMMERCIAL_INVOICE;
    }

    @Transient
    @Override
    public String getType() {
        return "CI";
    }

    public String getPermitNumber() {
        return permitNumber;
    }

    public void setPermitNumber(String permitNumber) {
        this.permitNumber = permitNumber;
    }

    public PermitType getPermitType() {
        return permitType;
    }

    public void setPermitType(PermitType permitType) {
        this.permitType = permitType;
    }

    public ClearingPaymentTerm getClearingPaymentTerm() {
        return clearingPaymentTerm;
    }

    public void setClearingPaymentTerm(ClearingPaymentTerm clearingPaymentTerm) {
        this.clearingPaymentTerm = clearingPaymentTerm;
    }
}