CreditorBillingTransaction.java

package com.tradecloud.domain.creditorbilling.transaction;

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.container.ShipmentContainer;
import com.tradecloud.domain.costing.clean.CostLineTemplateValue;
import com.tradecloud.domain.creditorbilling.rule.CreditorBillingRule;
import com.tradecloud.domain.event.CreditorBillingTransactionEvent;
import com.tradecloud.domain.event.Event;
import com.tradecloud.domain.party.ServiceProvider;
import com.tradecloud.domain.state.Stateful;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.ForeignKey;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * https://connect.devstream.net/display/Dev/Creditor+Billing+Transaction+Fields.
 *
 * @author jon
 */
@Entity
@Table(name = "creditorbillingtransaction", uniqueConstraints = {
        @UniqueConstraint(columnNames = {"transactiontype", "shipmentreference", "state", "containerreference",
                "carrier_id", "rule_id", "isreversal"})})
@NamedQueries({
        @NamedQuery(name = "cbtransaction.findByShipment",
                query = "SELECT cbt FROM CreditorBillingTransaction cbt JOIN cbt.container c " +
                        "WHERE c.shipment = :shipment and cbt.isReversal = false"),
        @NamedQuery(name = "cbtransaction.findByContainer",
                query = "SELECT cbt FROM CreditorBillingTransaction cbt WHERE cbt.container = :container and cbt.isReversal = false"),
        @NamedQuery(name = "cbtransactionIncReversal.findByContainer",
                query = "SELECT cbt FROM CreditorBillingTransaction cbt WHERE cbt.container = :container"),
        @NamedQuery(name = "cbtransaction.countByContainer",
                query = "SELECT count(*) FROM CreditorBillingTransaction cbt WHERE cbt.container = :container and cbt.isReversal = false")})
public class CreditorBillingTransaction extends PersistenceBase implements
        Stateful<CreditorBillingTransactionState, CreditorBillingTransactionEvent>,
        Commentable<AddedComment> {

    @ForeignKey(name = "fk_container")
    @ManyToOne
    @JoinColumn(name = "container_id")
    private ShipmentContainer container;

    @NotNull
    private String shipmentReference;

    @NotNull
    private String shipmentNumber;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(name = "effectivedatetype")
    private CreditorBillingEffectiveDate effectiveDateType;

    private String voyageNumber;

    private String vesselName;

    private String billOfLadingReference;

    @Temporal(TemporalType.TIMESTAMP)
    private Date billOfLadingDate;

    @Temporal(TemporalType.TIMESTAMP)
    private Date actualDateOfDeparture;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "actualarrivalatpod")
    private Date actualArrivalDateAtPlaceOfDischarge;

    @ForeignKey(name = "fk_carrier")
    @ManyToOne
    @JoinColumn(name = "carrier_id")
    private ServiceProvider carrier;

    @ForeignKey(name = "fk_carrierUpdate")
    @ManyToOne
    @JoinColumn(name = "carrierUpdate_id")
    private ServiceProvider carrierUpdate;

    @NotNull
    protected String billNumber;

    protected String reversalBillNumber;

    @NotNull
    @Enumerated(EnumType.STRING)
    protected CreditorBillingTransactionState state = CreditorBillingTransactionState.UNSIGNED_OFF;

    protected boolean hasReversal;
    protected boolean isReversal;

    @Temporal(TemporalType.TIMESTAMP)
    protected Date signedOffDate;

    @Temporal(TemporalType.TIMESTAMP)
    protected Date settlementDate;

    @Temporal(TemporalType.TIMESTAMP)
    protected Date deletedDate;

    @NotNull
    @Enumerated(EnumType.STRING)
    @Column(name = "transactiontype")
    protected CreditorBillingTransactionType creditorBillingTransactionType;

    @ForeignKey(name = "fk_cbrule")
    @ManyToOne
    @JoinColumn(name = "rule_id")
    private CreditorBillingRule creditorBillingRule;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @Fetch(value = FetchMode.SUBSELECT)
    @ForeignKey(name = "fk_cbtransaction", inverseName = "fk_cbtransactionevent")
    @JoinTable(name = "cbtransaction_cbtransactionevent",
            joinColumns = @JoinColumn(name = "cbtransaction_id"),
            inverseJoinColumns = @JoinColumn(name = "cbtransactionevents_id"))
    @XmlElementWrapper(name = "CreditorBillingTransactionEvents")
    @XmlElement(name = "CreditorBillingTransactionEvent")
    @OrderBy("createDateTime")
    private List<CreditorBillingTransactionEvent> events = new LinkedList<CreditorBillingTransactionEvent>();

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "cbtransaction_costlinevalues", joinColumns = {@JoinColumn(name = "cbtransaction_id", unique = false)})
    @ForeignKey(name = "fk_cbtransaction")
    @Fetch(value = FetchMode.SUBSELECT)
    @OrderBy("amount.currency")
    private List<CostLineTemplateValue> costLineValues = new ArrayList<CostLineTemplateValue>();

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

    @Embedded
    private CbTransactionContainer transactionContainer = new CbTransactionContainer();

    @NotNull
    @XmlElement(name = "ShippingInfo")
    @OneToOne(cascade = CascadeType.ALL)
    @ForeignKey(name = "fk_shippingInfo")
    private CreditorBillingTransactionShippingInfo shippingInfo = new CreditorBillingTransactionShippingInfo();

    @XmlElement(name = "reversalTransaction")
    @OneToOne(cascade = CascadeType.ALL)
    @ForeignKey(name = "fk_reversalTransaction")
    @JoinColumn(name = "reversal_id")
    private CreditorBillingTransaction reversalCBTransaction;

    @Transient
    private boolean transactionNotZeroRated;

    public CreditorBillingTransaction() {
    }

    public CreditorBillingTransaction(ShipmentContainer container, String billNumber,
                                      CreditorBillingTransactionType creditorBillingTransactionType,
                                      CreditorBillingRule creditorBillingRule) {

        this.container = container;
        this.billNumber = billNumber;
        this.creditorBillingTransactionType = creditorBillingTransactionType;
        this.creditorBillingRule = creditorBillingRule;
    }

    public ServiceProvider getCarrier() {
        return carrier;
    }

    public void setCarrier(ServiceProvider carrier) {
        this.carrier = carrier;
    }

    public String getBillNumber() {
        return billNumber;
    }

    public void setBillNumber(String billNumber) {
        this.billNumber = billNumber;
    }

    public boolean isHasReversal() {
        return hasReversal;
    }

    public void setHasReversal(boolean hasReversal) {
        this.hasReversal = hasReversal;
    }

    public boolean isReversal() {
        return isReversal;
    }

    public String isReversalPretty() {
        return isReversal() ? "Yes" : "No";
    }

    public String hasReversalPretty() {
        return isHasReversal() ? "Yes" : "No";
    }

    public void setReversal(boolean reversal) {
        isReversal = reversal;
    }

    public Date getSignedOffDate() {
        return signedOffDate;
    }

    public void setSignedOffDate(Date signedOffDate) {
        this.signedOffDate = signedOffDate;
    }

    public Date getSettlementDate() {
        return settlementDate;
    }

    public void setSettlementDate(Date settlementDate) {
        this.settlementDate = settlementDate;
    }

    public CreditorBillingTransactionType getCreditorBillingTransactionType() {
        return creditorBillingTransactionType;
    }

    public void setCreditorBillingTransactionType(CreditorBillingTransactionType creditorBillingTransactionType) {
        this.creditorBillingTransactionType = creditorBillingTransactionType;
    }

    public CreditorBillingRule getCreditorBillingRule() {
        return creditorBillingRule;
    }

    public void setCreditorBillingRule(CreditorBillingRule creditorBillingRule) {
        this.creditorBillingRule = creditorBillingRule;
    }

    public String getReversalBillNumber() {
        return reversalBillNumber;
    }

    public void setReversalBillNumber(String reversalBillNumber) {
        this.reversalBillNumber = reversalBillNumber;
    }

    public String getShipmentReference() {
        return shipmentReference;
    }

    public void setShipmentReference(String shipmentReference) {
        this.shipmentReference = shipmentReference;
    }

    public String getShipmentNumber() {
        return shipmentNumber;
    }

    public void setShipmentNumber(String shipmentNumber) {
        this.shipmentNumber = shipmentNumber;
    }

    public String getVoyageNumber() {
        return voyageNumber;
    }

    public void setVoyageNumber(String voyageNumber) {
        this.voyageNumber = voyageNumber;
    }

    public String getVesselName() {
        return vesselName;
    }

    public void setVesselName(String vesselName) {
        this.vesselName = vesselName;
    }

    public String getBillOfLadingReference() {
        return billOfLadingReference;
    }

    public void setBillOfLadingReference(String billOfLadingReference) {
        this.billOfLadingReference = billOfLadingReference;
    }

    public Date getBillOfLadingDate() {
        return billOfLadingDate;
    }

    public void setBillOfLadingDate(Date billOfLadingDate) {
        this.billOfLadingDate = billOfLadingDate;
    }

    public Date getActualDateOfDeparture() {
        return actualDateOfDeparture;
    }

    public void setActualDateOfDeparture(Date actualDateOfDeparture) {
        this.actualDateOfDeparture = actualDateOfDeparture;
    }

    public Date getActualArrivalDateAtPlaceOfDischarge() {
        return actualArrivalDateAtPlaceOfDischarge;
    }

    public void setActualArrivalDateAtPlaceOfDischarge(Date actualArrivalDateAtPlaceOfDischarge) {
        this.actualArrivalDateAtPlaceOfDischarge = actualArrivalDateAtPlaceOfDischarge;
    }

    public CreditorBillingEffectiveDate getEffectiveDateType() {
        return effectiveDateType;
    }

    public void setEffectiveDateType(CreditorBillingEffectiveDate effectiveDateType) {
        this.effectiveDateType = effectiveDateType;
    }

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

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

    @Override
    public int hashCode() {
        return new HashCodeBuilder()
                .appendSuper(super.hashCode())
                .append(billNumber)
                .toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof CreditorBillingTransaction)) {
            return false;
        }
        CreditorBillingTransaction other = (CreditorBillingTransaction) obj;
        return new EqualsBuilder()
                .appendSuper(super.equals(obj))
                .append(billNumber, other.billNumber)
                .isEquals();
    }

    public ShipmentContainer getContainer() {
        return container;
    }

    public void setContainer(ShipmentContainer container) {
        this.container = container;
    }

    public CbTransactionContainer getTransactionContainer() {
        return transactionContainer;
    }

    public void setTransactionContainer(CbTransactionContainer transactionContainer) {
        this.transactionContainer = transactionContainer;
    }

    public CreditorBillingTransactionShippingInfo getShippingInfo() {
        return shippingInfo;
    }

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

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

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

    public List<CostLineTemplateValue> getCostLineValues() {
        return costLineValues;
    }

    public void setCostLineValues(List<CostLineTemplateValue> costLineValues) {
        this.costLineValues = costLineValues;
    }

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

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

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

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

    public CreditorBillingTransaction getReversalCBTransaction() {
        return reversalCBTransaction;
    }

    public void setReversalCBTransaction(CreditorBillingTransaction reversalCBTransaction) {
        this.reversalCBTransaction = reversalCBTransaction;
    }

    public Date getDeletedDate() {
        return deletedDate;
    }

    public void setDeletedDate(Date deletedDate) {
        this.deletedDate = deletedDate;
    }

    public boolean isTransactionNotZeroRated() {
        return transactionNotZeroRated;
    }

    public void setTransactionNotZeroRated(boolean transactionNotZeroRated) {
        this.transactionNotZeroRated = transactionNotZeroRated;
    }

    @Override
    public String toString() {
        return "CreditorBillingTransaction{" +
                "container=" + container +
                ", shipmentReference='" + shipmentReference + '\'' +
                ", shipmentNumber='" + shipmentNumber + '\'' +
                ", effectiveDateType=" + effectiveDateType +
                ", voyageNumber='" + voyageNumber + '\'' +
                ", vesselName='" + vesselName + '\'' +
                ", billOfLadingReference='" + billOfLadingReference + '\'' +
                ", billOfLadingDate=" + billOfLadingDate +
                ", actualDateOfDeparture=" + actualDateOfDeparture +
                ", actualArrivalDateAtPlaceOfDischarge=" + actualArrivalDateAtPlaceOfDischarge +
                ", carrier=" + carrier +
                ", carrierUpdate=" + carrierUpdate +
                ", billNumber='" + billNumber + '\'' +
                ", reversalBillNumber='" + reversalBillNumber + '\'' +
                ", state=" + state +
                ", hasReversal=" + hasReversal +
                ", isReversal=" + isReversal +
                ", signedOffDate=" + signedOffDate +
                ", settlementDate=" + settlementDate +
                ", deletedDate=" + deletedDate +
                ", creditorBillingTransactionType=" + creditorBillingTransactionType +
                ", creditorBillingRule=" + creditorBillingRule +
                ", events=" + events +
                ", costLineValues=" + costLineValues +
                ", comments=" + comments +
                ", transactionContainer=" + transactionContainer +
                ", shippingInfo=" + shippingInfo +
                ", reversalCBTransaction=" + reversalCBTransaction +
                ", transactionNotZeroRated=" + transactionNotZeroRated +
                '}';
    }

    public ServiceProvider getCarrierUpdate() {
        return carrierUpdate;
    }

    public void setCarrierUpdate(ServiceProvider carrierUpdate) {
        this.carrierUpdate = carrierUpdate;
    }

    public boolean hasAmount() {
        List<CostLineTemplateValue> costLineValues = this.getCostLineValues();

        for (CostLineTemplateValue costLineTemplateValue : costLineValues) {
            if ((costLineTemplateValue.getAmount() != null && costLineTemplateValue.getAmount().getValue().intValue() > 0)
                    || (this.isReversal() && costLineTemplateValue.getAmount() != null)) {
                return true;
            }
        }

        return false;
    }

    public boolean isDeleted() {
        return this.getState().equals(CreditorBillingTransactionState.DELETED);
    }

    public boolean isSuspended() {
        return this.getState().equals(CreditorBillingTransactionState.SUSPENDED);
    }

    public boolean isSignedOff() {
        return this.getState().equals(CreditorBillingTransactionState.SIGNED_OFF);
    }

    public boolean isSettled() {
        return this.getState().equals(CreditorBillingTransactionState.SETTLED);
    }

    public boolean isUnsignedOff() {
        return this.getState().equals(CreditorBillingTransactionState.UNSIGNED_OFF);
    }

    @Override
    public CommentType getCommentType() {
        return null;
    }
}