ActualCostSummary.java

package com.tradecloud.domain.costing.clean;

import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.costing.CostGroup;
import com.tradecloud.domain.costing.CostLineTemplate;
import com.tradecloud.domain.document.invoice.ActualConsignment;
import com.tradecloud.domain.document.invoice.ActualLineItem;
import com.tradecloud.domain.model.ordermanagement.Order;
import com.tradecloud.domain.model.organisationalunit.OrganisationalUnit;
import com.tradecloud.domain.shipment.Shipment;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.hibernate.annotations.ForeignKey;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static com.tradecloud.domain.document.invoice.UnitPricePerItem.TOTAL_UNIT_PRICE;

@Entity
@DiscriminatorValue("ACTUAL_COST_SUMMARY")
@Table(name = "actualcostsummary")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ActualCostSummary")
@NamedQueries({
        @NamedQuery(name = "findActualCostSummaryById", query = "from ActualCostSummary acs left join fetch " +
                "acs.actualShipment.costLineCosting.costLineCostingCells where acs.id=:id")})
public class ActualCostSummary extends CostingSummary<ActualShipment, Shipment> {

    private static final long serialVersionUID = 1L;

    @NotNull
    @XmlElement(name = "OriginalCostable")
    @OneToOne(optional = false)
    private Shipment originalCostable;

    /**
     * The actual cost 'snapshot' of a Shipment at a point in time.
     */
    @NotNull
    @XmlElement(name = "ActualShipment")
    @OneToOne(optional = false)
    @ForeignKey(name = "fk_actualshipment")
    private ActualShipment actualShipment;

    @NotNull
    private Boolean isTotalUnitPrice;
    @NotNull(message = "summary number is required")
    private String number;

    @NotNull(message = "summaryCostType is required")
    @Enumerated(EnumType.STRING)
    private SummaryCostType summaryCostType;

    private boolean clcConfrimed;

    @Transient
    @XmlTransient
    private Map<CostLineTemplate, Currency> currencyMap = new HashMap<>();

    @Override
    public Shipment getShipment() {
        return originalCostable;
    }

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

    @Override
    public ActualShipment getCostable() {
        return actualShipment;
    }

    @Override
    public void setCostable(ActualShipment costable) {
        setActualShipment((ActualShipment) costable);
    }

    public ActualShipment getActualShipment() {
        return actualShipment;
    }

    public void setActualShipment(ActualShipment actualShipment) {
        this.actualShipment = actualShipment;
    }

    @Override
    public void setOriginalCostable(Shipment originalCostable) {
        this.originalCostable = originalCostable;
    }

    /**
     * Returns the actualShipment which reflects the ALC costed structure.
     *
     * @return
     */
    @Override
    public Costed getCostedStructure() {
        return actualShipment;
    }

    @Override
    public Shipment getOriginalCostable() {
        return originalCostable;
    }

    @Override
    public Set<ActualConsignment> getActualConsignmentSet() {
        return getActualShipment().getActualConsignments();
    }

    @Override
    public String toString() {
        if (originalCostable != null) {
            return "ActualCostSummary [id=" + getId() + ", shipment.Id=" + originalCostable.getId() + "]";
        }

        return null;
        // return "ActualCostSummary [id=" + getId() + ", shipment.Id=" +
        // originalCostable != null ? originalCostable.getId() + "" : "null" + "]";
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(originalCostable).append(actualShipment).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;

        if (!(obj instanceof ActualCostSummary)) {
            return false;
        }

        ActualCostSummary other = (ActualCostSummary) obj;
        return new EqualsBuilder().append(originalCostable, other.originalCostable)
                .append(actualShipment, other.actualShipment).isEquals();
    }

    public void setTotalUnitPrice(Boolean totalUnitPrice) {
        isTotalUnitPrice = totalUnitPrice;
    }

    @Override
    public boolean isTotalUnitPrice(Costed costed) {
        if (summaryCostType != null && summaryCostType == SummaryCostType.CLC) {
            if (costed instanceof ActualLineItem) {
                return TOTAL_UNIT_PRICE.equals(((ActualLineItem) costed).getActualOrder().getUnitPricePerItem());
            }
            return false;
        }
        if (summaryCostType != null && summaryCostType == SummaryCostType.WORK_SHEET) {
            return this.getShipment().getActiveCommercialInvoices().stream().filter(c -> c.getUnitPricePerItem().equals(TOTAL_UNIT_PRICE))
                    .findAny().isPresent();
        }
        return isTotalUnitPrice;
    }

    @Override
    public void clearCostApplicationBasisAmounts() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public Map<CostLineTemplate, Currency> getCurrencyMap() {
        return currencyMap;
    }

    @Override
    public OrganisationalUnit findStdRateOrgUnit() {
        Order order = getOriginalCostable().getOrders().stream().findFirst().orElse(null);
        return order != null ? order.getOrganisationalUnit() : null;
    }

    public String getNumber() {
        return number;
    }

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

    @Override
    public SummaryCostType getSummaryCostType() {
        return summaryCostType;
    }

    @Override
    public BigDecimal lookupMatchingItemAmount(ActualLineItem actual, String costLineCode) {
        ActualLineItem matchedItem = actualShipment.getActualLineItems().stream().filter(c -> c.getOriginalId().
                        equals(actual.getOriginalId())).findFirst()
                .orElseThrow(() -> new IllegalStateException("cannot find matching actual lineitem for actual item: " +
                        "" + actual.getCode() + " order: " + actual.getActualOrder().getReference()));
        return matchedItem.getCostLineCosting().getCostingCell(costLineCode).getTransactionAmount();
    }

    public void setSummaryCostType(SummaryCostType summaryCostType) {
        this.summaryCostType = summaryCostType;
    }

    public boolean isClcConfrimed() {
        return clcConfrimed;
    }

    public void setClcConfrimed(boolean clcConfrimed) {
        this.clcConfrimed = clcConfrimed;
    }

    public BigDecimal getTotalDutiableCharges() {
        return actualShipment.getCostedTotals().getDutiableCost();
    }

    public BigDecimal getTotalNonDutiableCharges() {
        BigDecimal dutiableCost = actualShipment.getCostedTotals().getDutiableCost();
        BigDecimal totalCost = lookupTotalCost(actualShipment, false, false, CostGroup.INTERNAL_PROVISIONS, CostGroup.CUSTOMS,
                CostGroup.TRADE_FINANCE);
        return totalCost.subtract(dutiableCost);
    }

}