ActualLineItem.java

package com.tradecloud.domain.document.invoice;

import com.tradecloud.common.base.HibernateUtils;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.base.utils.MathUtils;
import com.tradecloud.domain.base.utils.ObjectUtil;
import com.tradecloud.domain.common.Currency;
import com.tradecloud.domain.common.ProductProperty;
import com.tradecloud.domain.configuration.TreasuryConfig;
import com.tradecloud.domain.configuration.clearing.za.PenaltyType;
import com.tradecloud.domain.configuration.clearing.za.Preference;
import com.tradecloud.domain.configuration.clearing.za.TypeOfGoods;
import com.tradecloud.domain.costing.CostableType;
import com.tradecloud.domain.costing.clean.*;
import com.tradecloud.domain.customs.BaseDutyPercentage;
import com.tradecloud.domain.customs.DutyPercentage;
import com.tradecloud.domain.duties.*;
import com.tradecloud.domain.event.ActualLineItemEvent;
import com.tradecloud.domain.event.Event;
import com.tradecloud.domain.event.LineItemEventType;
import com.tradecloud.domain.export.ExportCosting;
import com.tradecloud.domain.item.*;
import com.tradecloud.domain.model.goodsreceivedreceipt.GoodsReceivedReceiptItem;
import com.tradecloud.domain.model.ordermanagement.ProductState;
import com.tradecloud.domain.model.organisationalunit.Brand;
import com.tradecloud.domain.place.Country;
import com.tradecloud.domain.place.NamedPlace;
import com.tradecloud.domain.product.ProductFieldCopyHelper;
import com.tradecloud.domain.sabs.SABSTariff;
import com.tradecloud.domain.shipment.clearing.AdditionalClearingInfo;
import com.tradecloud.domain.state.Stateful;
import com.tradecloud.domain.supplier.OrganisationalUnitSupplier;
import lombok.Getter;
import lombok.Setter;
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.builder.CompareToBuilder;
import org.apache.log4j.Logger;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.ForeignKey;
import org.springframework.stereotype.Component;

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

@Entity
@Getter
@Setter
@Component(value = "actuallineitem")
@Table(name = "actuallineitem")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ActualLineItem")
@NamedQueries({@NamedQuery(name = "actualLineItem.findByCode", query = "from ActualLineItem ali where ali.code = :code")})
public class ActualLineItem extends BaseActual<ActualOrder, Costed> implements AdditionalItem, Comparable<ActualLineItem>,
        CostingItem, ItemInterface, Stateful<LineItemState, ActualLineItemEvent> {

    private static final Logger log = Logger.getLogger(ActualLineItem.class);
    private static final long serialVersionUID = 1L;

    public static List<LineItemState> DUTY_DRAWBACK_STATES = Arrays.asList(LineItemState.DUTY_DRAWBACK_ISSUE,
            LineItemState.DUTY_DRAWBACK_SUCCESS, LineItemState.NO_DUTY_DRAWBACK, LineItemState.DUTY_DRAWBACK_EXCEEDED);
    /**
     * The bidirectional link back to the parent {@link ActualOrder}.
     */
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @XmlIDREF
    private ActualOrder actualOrder;

    @NotNull(message = "Item reference is required")
    @Basic(optional = false)
    private String code;

    @NotNull
    @Basic(optional = false)
    private String description;
    private String merchandiseCategory;

    @Basic(optional = false)
    private String tariffHeading;

    /**
     * If this is true we know the original line item was added at actual level, otherwise it was an estimate level line item.
     */
    @Basic(optional = false)
    private boolean additional;

    private boolean freeOfCharge;

    private BigDecimal valueForCustom;
    @NotNull(message = "organisation is a required field")
    private String organisation;

    @Basic(optional = false)
    private String barcode;

    // CI has current invoice quantity, SPI has sum of all CIs quantity
    private BigDecimal invoiceQuantity;

    // flag to say if the quantity is overridden; needed else the quantity always defaults from the packing list
    private boolean invoiceQuantityOverridden;

    // flag to say if the invoice price is overridden;
    private boolean invoicePriceOverridden;

    // used to 'clear' the overridden quantity, on clear, we set to this value.
    private BigDecimal initialInvoiceQuantity;

    // used to 'clear' the overridden invoice price, on clear, we set to this value.
    private BigDecimal initialInvoicePrice;

    // CI has current invoice price, SPI has weighted average of the price across CIs
    // i.e. on a ServiceProviderInvoice: invoiceQuantity * invoicePrice = totalValueAcrossCIs
    // this value is updated when the SPI is opened
    private BigDecimal invoicePrice;

    // Not null for CI. Null for SPI
    private BigDecimal orderQuantity;

    // Not null for CI. Null for SPI
    private BigDecimal orderPrice;

    @Column(name = "totalvalue")
    private BigDecimal totalInvoiceValue = BigDecimal.ZERO;

    private BigDecimal volume;

    private BigDecimal weight;

    private int exportLineItemNumber;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "weightunitofmeasure")
    @ForeignKey(name = "fk_weightunitofmeasure")
    protected WeightUnitOfMeasure weightUnitOfMeasure;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "volumeunitofmeasure")
    @ForeignKey(name = "fk_volumeunitofmeasure")
    private VolumeUnitOfMeasure volumeUnitOfMeasure;

    @ManyToOne
    @JoinColumn(name = "countryoforigin_code")
    @ForeignKey(name = "fk_countryoforigin")
    protected Country countryOfOrigin;
    //keep for costing efficiency
    private BigDecimal customsDutyPercentage = BigDecimal.ZERO;

    private BigDecimal adValoremPercentage = BigDecimal.ZERO;

    private BigDecimal antiDumpingPercentage = BigDecimal.ZERO;

    private BigDecimal counterVailingPercentage = BigDecimal.ZERO;

    // used for clearing the customs %
    private BigDecimal initialAdValoremPercentage = BigDecimal.ZERO;
    private BigDecimal initialAntiDumpingPercentage = BigDecimal.ZERO;
    private BigDecimal initialCounterVailingPercentage = BigDecimal.ZERO;
    private BigDecimal initialCustomsDutyPercentage = BigDecimal.ZERO;

    private boolean adValoremPercentageOverridden;
    private boolean antiDumpingPercentageOverridden;
    private boolean counterVailingPercentageOverridden;
    private boolean customsDutyPercentageOverridden;
    private int billOfEntryLineNumber;
    private BigDecimal unitLandedCost = BigDecimal.ZERO;
    private boolean tradeStatistics = true;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "transactioncurrency_code")
    @ForeignKey(name = "fk_transactioncurrency")
    @XmlElement
    @NotNull
    protected Currency transactionCurrency;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "costingcurrency_code")
    @ForeignKey(name = "fk_costingcurrency")
    @XmlElement
    @NotNull
    protected Currency costingCurrency;

    @ManyToOne(fetch = FetchType.LAZY)
    @ForeignKey(name = "fk_sabstariff")
    @XmlElement(name = "SABSTariff")
    protected SABSTariff sabsTariff;

    private BigDecimal dutiableCost;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "packagetype_code")
    @ForeignKey(name = "fk_packagetype")
    @XmlElement
    private PackageType packageType;

    @ManyToOne(fetch = FetchType.LAZY)
    @ForeignKey(name = "fk_unittype")
    private UnitType unitType;
    private String mrnNumber;
    private String lrnNumber;
    private String cpcCode;
    private Date billOfEntryDate;
    private BigDecimal customsValue;

    public BigDecimal getCustomsValue() {
        return customsValue;
    }

    public void setCustomsValue(BigDecimal customsValue) {
        this.customsValue = customsValue;
    }

    @Enumerated(EnumType.STRING)
    private AdditionalLineItemType freeStockType;

    public UnitType getUnitType() {
        return unitType;
    }

    public void setUnitType(UnitType unitType) {
        this.unitType = unitType;
    }

    @Temporal(TemporalType.TIMESTAMP)
    private Date addedToOrderDate;

    @Enumerated(EnumType.STRING)
    @XmlAttribute(name = "ItemType")
    private ItemType itemType = ItemType.GENERAL;
    private Integer invoiceLineNumber;
    //from order
    protected Integer lineNumber;

    private transient BigDecimal varianceAgainstEstimateQuantity = BigDecimal.ZERO;

    private transient BigDecimal varianceAgainstEstimateUnitPrice = BigDecimal.ZERO;

    private transient BigDecimal varianceAgainstEstimateTotal = BigDecimal.ZERO;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    @XmlElement(name = "Schedule1Part1A")
    protected Schedule1Part1A schedule1Part1A;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule1Part2A")
    protected Schedule1Part2A schedule1Part2A;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule1Part2B")
    protected Schedule1Part2B schedule1Part2B;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule2Part1")
    protected Schedule2Part1 schedule2Part1;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule2Part2")
    protected Schedule2Part2 schedule2Part2;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule1Part3E")
    protected Schedule1Part3E schedule1Part3E;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule1Part7")
    protected Schedule1Part7 schedule1Part7;

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule3Part1")
    protected Schedule3Part1 schedule3Part1 = new Schedule3Part1();

    @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @XmlElement(name = "Schedule4Part1")
    protected Schedule4Part1 schedule4Part1 = new Schedule4Part1();

    private String tariffDeterminationNumber;

    private String hashTariff;

    private String sarsTariffUpdateReason;
    private String supplierReference;
    protected BigDecimal unitWidth;
    protected BigDecimal unitHeight;
    protected BigDecimal unitLength;
    protected BigDecimal unitsPerPackage;

    @Enumerated(EnumType.STRING)
    @XmlAttribute(name = "State")
    private LineItemState state = LineItemState.UNTARIFFED;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "valuedeterminationnumber_id")
    @XmlTransient
    protected ValueDeterminationNumber valueDeterminationNumber = new ValueDeterminationNumber();

    @Enumerated(value = EnumType.STRING)
    protected Preference preference = Preference.NONE;

    private boolean tariffOverridden;

    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "itacPermit_id")
    @XmlTransient
    protected ItacPermit itacPermit = new ItacPermit();

    private boolean overriddenVolume;
    private boolean overriddenWeight;
    private BigDecimal penaltyAmount;

    protected String styleReference;

    protected String styleDescription;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "supplier_id")
    protected OrganisationalUnitSupplier supplier;

    @ElementCollection(fetch = FetchType.EAGER)
    private Map<String, String> additionalNotes = new HashMap<>();

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

    private BigDecimal linkedDutyDrawBackAmount;

    @Enumerated(EnumType.STRING)
    protected TypeOfGoods typeOfGoods = TypeOfGoods.NEW_GOODS;

    @Enumerated(EnumType.STRING)
    protected PenaltyType penaltyType;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "actuallineitem_events", joinColumns = {@JoinColumn(name = "actuallineitem_id")},
            inverseJoinColumns = {@JoinColumn(name = "events_id")})
    @Fetch(value = FetchMode.SELECT)
    @OrderBy("createDateTime")
    private List<ActualLineItemEvent> events = new LinkedList<>();
    @ManyToOne
    private NamedPlace factory;

    private boolean useSADCCertificate;//todo depend on TRM-6341
    private String templateDescription;

    private Long templateId;

    protected Integer clcPosition;

    @Embedded
    private StatisticalUnit statisticalUnit = new StatisticalUnit();

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AdditionalClearingInfo> additionalClearingInfo = new HashSet<>();

    @ManyToOne
    protected Brand brand;

    private String invoiceLineDescription;

    public ActualLineItem() {
    }

    public LineItem getLineItem() {
        return null;
    }

    public ActualLineItem(ActualLineItem actualLineItem) {
        super(actualLineItem.getOriginalId());

        this.code = actualLineItem.code;
        this.description = actualLineItem.description;
        this.invoiceQuantity = actualLineItem.invoiceQuantity;
        this.invoicePrice = actualLineItem.invoicePrice;
        this.unitLandedCost = actualLineItem.unitLandedCost;
        this.transactionCurrency = actualLineItem.transactionCurrency;
        this.costingCurrency = actualLineItem.costingCurrency;
        this.customsDutyPercentage = actualLineItem.getCustomsDutyPercentage();
        this.adValoremPercentage = actualLineItem.getAdValoremPercentage();
        this.antiDumpingPercentage = actualLineItem.getAntiDumpingPercentage();
        this.counterVailingPercentage = actualLineItem.getCounterVailingPercentage();
        this.initialCustomsDutyPercentage = actualLineItem.getInitialCustomsDutyPercentage();
        this.initialAdValoremPercentage = actualLineItem.getInitialAdValoremPercentage();
        this.initialAntiDumpingPercentage = actualLineItem.getInitialAntiDumpingPercentage();
        this.initialCounterVailingPercentage = actualLineItem.getInitialCounterVailingPercentage();
        this.tariffHeading = actualLineItem.tariffHeading;
        this.barcode = actualLineItem.barcode;
        this.additional = actualLineItem.additional;
        this.preference = actualLineItem.getPreference() != null ? actualLineItem.getPreference() : Preference.NONE;
        this.weight = actualLineItem.getWeight();
        this.volume = actualLineItem.getVolume();
        this.orderQuantity = actualLineItem.getOrderQuantity();
        this.orderPrice = actualLineItem.getOrderPrice();
        this.weightUnitOfMeasure = actualLineItem.getWeightUnitOfMeasure();
        this.volumeUnitOfMeasure = actualLineItem.getVolumeUnitOfMeasure();
        this.packageType = actualLineItem.getPackageType();
        this.addedToOrderDate = actualLineItem.addedToOrderDate;
        this.countryOfOrigin = actualLineItem.getCountryOfOrigin();
        this.freeOfCharge = actualLineItem.isFreeOfCharge();
        this.valueForCustom = actualLineItem.getValueForCustom();
        this.unitType = actualLineItem.getUnitType();
        this.itemType = actualLineItem.getItemType();
        this.setSellPriceExclusiveAmount(actualLineItem.getSellPriceExclusiveAmount());
        this.setSellPriceInclusiveAmount(actualLineItem.getSellPriceInclusiveAmount());
        this.organisation = actualLineItem.getOrganisation();
        this.unitHeight = actualLineItem.getUnitHeight();
        this.unitLength = actualLineItem.getUnitLength();
        this.unitLength = actualLineItem.getUnitLength();
        this.unitsPerPackage = actualLineItem.getUnitsPerPackage();
        this.tariffDeterminationNumber = actualLineItem.tariffDeterminationNumber;
        this.sarsTariffUpdateReason = actualLineItem.getSarsTariffUpdateReason();
        this.supplierReference = actualLineItem.getSupplierReference();
        this.hashTariff = actualLineItem.getHashTariff();
        this.state = actualLineItem.getState();
        this.styleReference = actualLineItem.getStyleReference();
        this.styleDescription = actualLineItem.getStyleDescription();
        this.templateDescription = actualLineItem.getTemplateDescription();
        this.supplier = actualLineItem.getSupplier();
        this.additionalNotes = Optional.ofNullable(this.additionalNotes).orElse(new HashMap<>());
        this.additionalNotes.putAll(actualLineItem.getAdditionalNotes());
        this.typeOfGoods = Optional.ofNullable(actualLineItem.typeOfGoods).orElse(TypeOfGoods.NEW_GOODS);
        this.clcPosition = actualLineItem.getClcPosition();
        this.lineNumber = actualLineItem.lineNumber;
        //clone to prevent duplicate references to exportcosting table
        this.exportCosting = (ExportCosting) actualLineItem.getExportCosting().clone();

        ProductFieldCopyHelper.copyDuties(actualLineItem, this);

        setDistributableVolume(actualLineItem);
        setDistributableWeight(actualLineItem);
        this.freeStockType = actualLineItem.getFreeStockType();
        this.brand = actualLineItem.getBrand();
    }

    private void setDistributableVolume(ActualLineItem actualLineItem) {
        if (volume != null) {
            actualLineItem.setDistributableByVolume(true);
            if (actualLineItem.getActualOrder() != null) {
                actualLineItem.getActualOrder().setDistributableByVolume(true);
                if (actualLineItem.getActualOrder().getActualConsignment() != null) {
                    actualLineItem.getActualOrder().getActualConsignment().setDistributableByVolume(true);
                    if (actualLineItem.getActualOrder().getActualConsignment().getActualShipment() != null) {
                        actualLineItem.getActualOrder().getActualConsignment().getActualShipment().setDistributableByVolume(true);
                    }
                    if (actualLineItem.getActualOrder().getActualConsignment().getCostsInvoice() != null) {
                        actualLineItem.getActualOrder().getActualConsignment().getCostsInvoice().setDistributableByVolume(true);
                    }
                }
            }
        }
    }

    private void setDistributableWeight(ActualLineItem actualLineItem) {
        if (weight != null) {
            actualLineItem.setDistributableByWeight(true);
            if (actualLineItem.getActualOrder() != null) {
                actualLineItem.getActualOrder().setDistributableByWeight(true);
                if (actualLineItem.getActualOrder().getActualConsignment() != null) {
                    actualLineItem.getActualOrder().getActualConsignment().setDistributableByWeight(true);
                    if (actualLineItem.getActualOrder().getActualConsignment().getActualShipment() != null) {
                        actualLineItem.getActualOrder().getActualConsignment().getActualShipment().setDistributableByWeight(true);
                    }

                    if (actualLineItem.getActualOrder().getActualConsignment().getCostsInvoice() != null) {
                        actualLineItem.getActualOrder().getActualConsignment().getCostsInvoice().setDistributableByWeight(true);
                    }
                }
            }
        }
    }

    public void setState(ProductState productState) {
    }

    // Used for testing at the moment. Phase out
    @Deprecated
    public ActualLineItem(LineItem lineItem) {
        this(lineItem, new Currency(TreasuryConfig.getDefaultLocalCurrency().getCurrencyCode()));
    }

    public ActualLineItem(LineItem lineItem, Currency costingCurrency) {
        super(lineItem.getId());

        this.code = lineItem.getCode();
        this.description = lineItem.getDescription();
        if (lineItem.isAdditional()) {
            // See https://jira.devstream.net/browse/TCA-371 point 4 in the description.
            this.invoiceQuantity = lineItem.getUnitQuantity();
            this.orderQuantity = BigDecimal.ZERO;
        } else {
            // This starts at 0. It will be defaulted later to the amount not allocated by other invoices.
            this.invoiceQuantity = BigDecimal.ZERO;
            this.orderQuantity = lineItem.getUnitQuantity();
        }

        //for test item cases with no order default to imports settings
        if (lineItem.getOrder() != null && !lineItem.getOrder().isPurchaseOrder()) {
            this.invoicePrice = lineItem.getUnitSellingPrice();
            orderPrice = lineItem.getUnitSellingPrice();
        } else {
            this.invoicePrice = lineItem.getUnitPrice();
            orderPrice = lineItem.getUnitPrice();
        }

        this.transactionCurrency = lineItem.getCurrency();
        this.costingCurrency = costingCurrency;
        updatePercentages(lineItem);
        this.tariffHeading = getTariffHeading(lineItem);
        this.additional = lineItem.isAdditional();
        this.weightUnitOfMeasure = lineItem.getWeightUOM();
        this.volumeUnitOfMeasure = lineItem.getVolumeUOM();
        this.weight = lineItem.getUnitWeight();
        this.volume = lineItem.getUnitVolume();
        this.sabsTariff = lineItem.getSabsTariff();
        this.addedToOrderDate = lineItem.getAddedToOrderDate();
        this.setCountryOfOrigin(lineItem.getCountryOfOrigin());
        this.setSellPriceExclusiveAmount(lineItem.getSellPriceExclusiveAmount());
        this.setSellPriceInclusiveAmount(lineItem.getSellPriceInclusiveAmount());
        this.initialCustomsDutyPercentage = customsDutyPercentage;
        this.initialAdValoremPercentage = adValoremPercentage;
        this.initialAntiDumpingPercentage = antiDumpingPercentage;
        this.initialCounterVailingPercentage = counterVailingPercentage;
        this.unitType = lineItem.getUnitType();
        this.itemType = lineItem.getItemType();
        this.unitHeight = lineItem.getUnitHeight();
        this.unitLength = lineItem.getUnitLength();
        this.unitLength = lineItem.getUnitLength();
        this.unitsPerPackage = lineItem.getUnitsPerPackage();
        this.tariffDeterminationNumber = lineItem.getTariffDeterminationNumber();
        this.sarsTariffUpdateReason = lineItem.getSarsTariffUpdateReason();
        this.supplierReference = lineItem.getSupplierReference();
        this.hashTariff = lineItem.getHashTariff();
        this.state = lineItem.getState();
        this.styleReference = lineItem.getStyleReference();
        this.styleDescription = lineItem.getStyleDescription();
        this.templateDescription = lineItem.getItemTemplateDescription();
        this.templateId = lineItem.getTemplateId();
        this.supplier = lineItem.getSupplier();
        this.clcPosition = lineItem.getPosition();
        ProductFieldCopyHelper.copyDuties(lineItem, this);
        if (lineItem.getOrganisationalUnit() != null) {
            this.setOrganisation(lineItem.getOrganisationalUnit().getCode());
        }
        this.typeOfGoods = Optional.ofNullable(lineItem.getTypeOfGoods()).orElse(TypeOfGoods.NEW_GOODS);
        this.factory = lineItem.getFactory();
        this.freeStockType = lineItem.getFreeStockType();
        this.brand = lineItem.getBrand();
        this.lineNumber = lineItem.getLineNumber();
    }

    public void updateDuties(ActualLineItem lineItem) {
        //ProductFieldCopyHelper.copyDuties(lineItem, this);
        this.hashTariff = lineItem.getHashTariff();
        this.tariffDeterminationNumber = lineItem.getTariffDeterminationNumber();
        this.sarsTariffUpdateReason = lineItem.getSarsTariffUpdateReason();
        //keep for costing efficiency
        updateCostingFields(lineItem);
        //this.tariffHeading = getTariffHeading(this);
    }

    public void updateCostingFields(ActualLineItem lineItem) {
        updatePercentages(lineItem);
        setTariffHeading(lineItem.getSchedule1Part1A().getTariffHeading().getTariff());
    }

    public void updatePercentages(ItemInterface lineItem) {
        this.customsDutyPercentage = getDutyPercent(lineItem.getSchedule1Part1A());
        this.adValoremPercentage = getDutyPercent(lineItem.getSchedule1Part2B());
        this.counterVailingPercentage = getDutyPercent(lineItem.getSchedule2Part2());
        this.antiDumpingPercentage = getDutyPercent(lineItem.getSchedule2Part1());
    }

    protected BigDecimal getDutyPercent(TypedDutySchedule dutySchedule) {
        if (dutySchedule != null) {
            DutyPercentage dutyPercentage = BaseDutyPercentage.getDutyPercentage(dutySchedule.getCostlineCode(), this);
            if (dutyPercentage.percentageOverridden()) {
                return dutyPercentage.getDutyPercentage() != null ? dutyPercentage.getDutyPercentage() : BigDecimal.ZERO;
            }
        }

        return (dutySchedule != null && dutySchedule.getDutyRate() != null) && dutySchedule.getDutyRate().getPercentage() != null ? dutySchedule
                .getDutyRate().getPercentage() : BigDecimal.ZERO;
    }

    protected String getTariffHeading(LineItem lineItem) {
        return (lineItem.getSchedule1Part1A() != null && lineItem.getSchedule1Part1A().getTariffHeading() != null) ? lineItem.getSchedule1Part1A()
                .getTariffHeading().getTariff() : null;
    }

    @Override
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public ValueDeterminationNumber getValueDeterminationNumber() {
        if (valueDeterminationNumber == null) {
            valueDeterminationNumber = new ValueDeterminationNumber();
        }
        return valueDeterminationNumber;
    }

    public void setValueDeterminationNumber(ValueDeterminationNumber valueDeterminationNumber) {
        this.valueDeterminationNumber = valueDeterminationNumber;
    }

    public String getTariffHeading() {
        if (getSchedule1Part1A() != null) {
            return getSchedule1Part1A().getTariffHeading().getTariff();
        }
        return tariffHeading;
    }

    public void setTariffHeading(String tariffHeading) {
        this.tariffHeading = tariffHeading;
    }

    @Override
    public boolean isAdditional() {
        return additional;
    }

    public void setAdditional(boolean additional) {
        this.additional = additional;
    }

    public String getBarcode() {
        return barcode;
    }

    @Override
    public void setUnitPrice(BigDecimal unitPrice) {
        this.invoicePrice = unitPrice;
    }

    @Override
    public BigDecimal getUnitPrice() {
        return invoicePrice;
    }

    @Override
    public Currency getCurrency() {
        return transactionCurrency;
    }

    public void setBarcode(String barcode) {
        this.barcode = barcode;
    }

    public ActualOrder getActualOrder() {
        return actualOrder;
    }

    public void setActualOrder(ActualOrder actualOrder) {
        this.actualOrder = actualOrder;
    }

    public BigDecimal getUnitLandedCost() {
        return unitLandedCost;
    }

    public void setUnitLandedCost(BigDecimal unitLandedCost) {
        this.unitLandedCost = unitLandedCost;
    }

    public Currency getTransactionCurrency() {
        return transactionCurrency;
    }

    public void setTransactionCurrency(Currency transactionCurrency) {
        this.transactionCurrency = transactionCurrency;
    }

    public Currency getCostingCurrency() {
        return costingCurrency;
    }

    public void setCostingCurrency(Currency costingCurrency) {
        this.costingCurrency = costingCurrency;
    }

    public BigDecimal getOrderPrice() {
        return orderPrice;
    }

    public void setOrderPrice(BigDecimal orderPrice) {
        this.orderPrice = orderPrice;
    }

    @Override
    public BigDecimal getOrderQuantity() {
        return orderQuantity;
    }

    @Override
    public void setOrderQuantity(BigDecimal orderQuantity) {
        this.orderQuantity = orderQuantity;
    }

    @Override
    public BigDecimal getInvoiceQuantity() {
        return invoiceQuantity;
    }

    @Override
    public void setInvoiceQuantity(BigDecimal invoiceQuantity) {
        this.invoiceQuantity = invoiceQuantity;
    }

    public BigDecimal getInvoicePrice() {
        return invoicePrice;
    }

    public void setInvoicePrice(BigDecimal invoicePrice) {
        this.invoicePrice = invoicePrice;
    }

    public VolumeUnitOfMeasure getVolumeUnitOfMeasure() {
        return volumeUnitOfMeasure;
    }

    @Override
    public BigDecimal getPrice() {
        return getInvoicePrice();
    }

    public void setVolumeUnitOfMeasure(VolumeUnitOfMeasure volumeUnitOfMeasure) {
        this.volumeUnitOfMeasure = volumeUnitOfMeasure;
    }

    @Override
    public BigDecimal getQuantity() {
        return getInvoiceQuantity();
    }

    @Override
    public Costed getRootParent() {
        ActualConsignment actualConsignment = null;
        ActualShipment actualShipment = null;
        if (actualOrder != null)
            actualConsignment = actualOrder.getActualConsignment();
        if (actualConsignment != null)
            actualShipment = actualConsignment.getActualShipment();
        return actualShipment;
    }

    @Override
    public Costed toCosted() {
        return this;
    }

    @Override
    public BigDecimal getDutyPercentage() {
        return customsDutyPercentage;
    }

    public WeightUnitOfMeasure getWeightUnitOfMeasure() {
        return weightUnitOfMeasure;
    }

    @Override
    public BigDecimal getUnitVolume() {
        return getVolume();
    }

    @Override
    public VolumeUnitOfMeasure getVolumeUOM() {
        return volumeUnitOfMeasure;
    }

    @Override
    public void setVolumeUOM(VolumeUnitOfMeasure volumeUOM) {
        volumeUnitOfMeasure = volumeUOM;
    }

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

    @Override
    public BigDecimal getUnitQuantity() {
        return invoiceQuantity;
    }

    @Override
    public BigDecimal getPackageWeight() {
        return (ObjectUtil.allNotNull(unitsPerPackage, getWeight())) ? getWeight().multiply(unitsPerPackage) : BigDecimal.ZERO;
    }

    @Override
    public BigDecimal getUnitWeight() {
        return getWeight();
    }

    @Override
    public void setSarsTariffUpdateReason(String sarsTariffUpdateReason) {
        this.sarsTariffUpdateReason = sarsTariffUpdateReason;
    }

    @Override
    public String getSarsTariffUpdateReason() {
        return sarsTariffUpdateReason;
    }

    public void setWeightUnitOfMeasure(WeightUnitOfMeasure weightUnitOfMeasure) {
        this.weightUnitOfMeasure = weightUnitOfMeasure;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(code).
                append(actualOrder != null ? actualOrder.getNumber() : null)
                .append(organisation)
                .append(originalId).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof ActualLineItem)) {
            return false;
        }
        ActualLineItem other = (ActualLineItem) obj;
        return new EqualsBuilder().append(code, other.code)
                .append(originalId, other.getOriginalId())
                .append(organisation, other.getOrganisation())
                .append(actualOrder != null ? actualOrder.getNumber() : null,
                        other.getParent() != null ? other.getParent().getNumber() : null).isEquals();
    }

    @Override
    public String toString() {

        StringBuilder displayCostingCurrency = new StringBuilder();
        if (costingCurrency != null) {
            displayCostingCurrency.append(" ");
            displayCostingCurrency.append(costingCurrency.getCode());
        }
        StringBuilder displayString = new StringBuilder("ActualLineItem [code=" + code);

        displayString.append(", Invoice Quantity ").append(getInvoiceQuantity()).append(", unitLandedCost ").
                append(unitLandedCost).append(displayCostingCurrency);

        displayString.append(", totalValue ").append(getTotalInvoiceValue()).append(displayCostingCurrency);
        displayString.append("]");

        return displayString.toString();
    }

    /**
     * Method used by the UI in the ALC summary screen.
     *
     * @return
     */
    public String displayString() {

        StringBuilder displayCostingCurrency = new StringBuilder();
        if (costingCurrency != null) {
            displayCostingCurrency.append(" ");
            displayCostingCurrency.append(costingCurrency.getCode());
        }
        StringBuilder displayString = new StringBuilder("code=" + code);

        displayString.append(", Customs Duty ").append(getCustomsDutyPercentage()).append("%");

        displayString.append(", Ad Valorem ").append(getAdValoremPercentage()).append("%");

        displayString.append(", Invoice Quantity ").append(getInvoiceQuantity()).append(", unitLandedCost ")
                .append(MathUtils.setDisplayScale(unitLandedCost)).append(displayCostingCurrency);

        BigDecimal totalValue = getTotalsDistribution().get(TotalsDistributionType.COST_ZAR_EXCL_VAT);
        displayString.append(", totalValue ").append(MathUtils.setDisplayScale(totalValue)).append(displayCostingCurrency);

        return displayString.toString();
    }

    public BigDecimal getVolume() {
        return volume;
    }

    public void setVolume(BigDecimal volume) {
        this.volume = volume;
    }

    public BigDecimal getWeight() {
        return weight;
    }

    public void setWeight(BigDecimal weight) {
        this.weight = weight;
    }

    public BigDecimal getCustomsDutyPercentage() {
        return customsDutyPercentage;
    }

    public void setCustomsDutyPercentage(BigDecimal customsDutyPercentage) {
        this.customsDutyPercentage = customsDutyPercentage;
    }

    public BigDecimal getAdValoremPercentage() {
        return adValoremPercentage;
    }

    public void setAdValoremPercentage(BigDecimal adValoremPercentage) {
        this.adValoremPercentage = adValoremPercentage;
    }

    @Override
    public void accept(CostingVisitor costingVisitor) {
        if (costingVisitor != null) {
            costingVisitor.visit(this);
        } else {
            log.error("Null CostingVisitor passed to actuallineitem: " + getId() + ", " + getReference());
        }
    }

    @Override
    public void acceptVisitParentFirst(CostingVisitor costingVisitor) {
        costingVisitor.visit(this);
    }

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

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

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

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

    @Override
    public ActualOrder getParent() {
        return actualOrder;
    }

    @Override
    public List<Costed> getCostedChildren() {
        return new ArrayList<>();
    }

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

    @Override
    public MultiKey getTraversalKey() {
        return new MultiKey(ActualLineItem.class, code, actualOrder.getNumber(), organisation);
    }

    @Override
    public boolean isSample() {
        return additional && (AdditionalLineItemType.SAMPLE.getName().equals(code) || freeStockType == AdditionalLineItemType.SAMPLE);
    }

    @Override
    public boolean isSparePart() {
        return additional && (AdditionalLineItemType.SPARE_PART.getName().equals(code) || freeStockType == AdditionalLineItemType.SPARE_PART);
    }

    public boolean match(CostedLineItem costedLineItem) {
        return costedLineItem.getCode().equals(getCode()) && costedLineItem.getCostedOrder().getNumber().equals(getActualOrder().getNumber())
                && (organisation != null && costedLineItem.getLineItem() != null && costedLineItem.getLineItem().getOrganisationalUnit() != null ?
                organisation.equals(costedLineItem.getLineItem().getOrganisationalUnit().getCode()) : true);
    }

    public SABSTariff getSabsTariff() {
        return sabsTariff;
    }

    public void setSabsTariff(SABSTariff sabsTariff) {
        this.sabsTariff = sabsTariff;
    }

    public BigDecimal getInitialAdValoremPercentage() {
        return initialAdValoremPercentage;
    }

    public void setInitialAdValoremPercentage(BigDecimal initialAdValoremPercentage) {
        this.initialAdValoremPercentage = initialAdValoremPercentage;
    }

    public BigDecimal getInitialCustomsDutyPercentage() {
        return initialCustomsDutyPercentage;
    }

    public void setInitialCustomsDutyPercentage(BigDecimal initialCustomsDutyPercentage) {
        this.initialCustomsDutyPercentage = initialCustomsDutyPercentage;
    }

    @Override
    public BigDecimal getAntiDumpingPercentage() {
        return antiDumpingPercentage;
    }

    public void setAntiDumpingPercentage(BigDecimal antiDumpingPercentage) {
        this.antiDumpingPercentage = antiDumpingPercentage;
    }

    @Override
    public BigDecimal getCounterVailingPercentage() {
        return counterVailingPercentage;
    }

    public void setCounterVailingPercentage(BigDecimal counterVailingPercentage) {
        this.counterVailingPercentage = counterVailingPercentage;
    }

    public BigDecimal getInitialAntiDumpingPercentage() {
        return initialAntiDumpingPercentage;
    }

    public void setInitialAntiDumpingPercentage(BigDecimal initialAntiDumpingPercentage) {
        this.initialAntiDumpingPercentage = initialAntiDumpingPercentage;
    }

    public BigDecimal getInitialCounterVailingPercentage() {
        return initialCounterVailingPercentage;
    }

    public void setInitialCounterVailingPercentage(BigDecimal initialCounterVailingPercentage) {
        this.initialCounterVailingPercentage = initialCounterVailingPercentage;
    }

    public Date getAddedToOrderDate() {
        return addedToOrderDate;
    }

    @Override
    public String getOrganisationalUnitCode() {
        return organisation;
    }

    public void setAddedToOrderDate(Date addedToOrderDate) {
        this.addedToOrderDate = addedToOrderDate;
    }

    @Override
    public int compareTo(ActualLineItem o) {
//        return addedToOrderDate.compareTo(o.addedToOrderDate);
        CompareToBuilder compareToBuilder = new CompareToBuilder();
        return compareToBuilder.append(clcPosition, o.getClcPosition())
                .append(addedToOrderDate, o.addedToOrderDate).append(code, o.getCode()).toComparison();

    }

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

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

    public boolean isInvoiceQuantityOverridden() {
        return invoiceQuantityOverridden;
    }

    public void setInvoiceQuantityOverridden(boolean invoiceQuantityOverridden) {
        this.invoiceQuantityOverridden = invoiceQuantityOverridden;
    }

    public BigDecimal getInitialInvoiceQuantity() {
        return initialInvoiceQuantity;
    }

    public void setInitialInvoiceQuantity(BigDecimal initialInvoiceQuantity) {
        this.initialInvoiceQuantity = initialInvoiceQuantity;
    }

    public PackageType getPackageType() {
        return packageType;
    }

    @Override
    public void setItacPermit(ItacPermit itacPermit) {
        this.itacPermit = itacPermit;
    }

    @Override
    public ItacPermit getItacPermit() {
        if (itacPermit == null) {
            itacPermit = new ItacPermit();
        }
        return itacPermit;
    }

    public void setPackageType(PackageType packageType) {
        this.packageType = packageType;
    }

    @Override
    public String getNumber() {
        return null;
    }

    public Country getCountryOfOrigin() {
        return countryOfOrigin;
    }

    public void setCountryOfOrigin(Country countryOfOrigin) {
        this.countryOfOrigin = countryOfOrigin;
    }

    public int getExportLineItemNumber() {
        return exportLineItemNumber;
    }

    public void setExportLineItemNumber(int exportLineItemNumber) {
        this.exportLineItemNumber = exportLineItemNumber;
    }

    @Override
    public ItemType getItemType() {
        return itemType;
    }

    @Override
    public void setItemType(ItemType itemType) {
        this.itemType = itemType;
        getItacPermit().setRebateSchedule(itemType);
    }

    public String getOrganisation() {
        return organisation;
    }

    public void setOrganisation(String organisation) {
        this.organisation = organisation;
    }

    public BigDecimal getVarianceAgainstEstimateQuantity() {
        return varianceAgainstEstimateQuantity;
    }

    public void setVarianceAgainstEstimateQuantity(BigDecimal varianceAgainstEstimateQuantity) {
        this.varianceAgainstEstimateQuantity = varianceAgainstEstimateQuantity;
    }

    public BigDecimal getVarianceAgainstEstimateUnitPrice() {
        return varianceAgainstEstimateUnitPrice;
    }

    public void setVarianceAgainstEstimateUnitPrice(BigDecimal varianceAgainstEstimateUnitPrice) {
        this.varianceAgainstEstimateUnitPrice = varianceAgainstEstimateUnitPrice;
    }

    public BigDecimal getVarianceAgainstEstimateTotal() {
        return varianceAgainstEstimateTotal;
    }

    public void setVarianceAgainstEstimateTotal(BigDecimal varianceAgainstEstimateTotal) {
        this.varianceAgainstEstimateTotal = varianceAgainstEstimateTotal;
    }

    @Override
    public boolean isBondedSplitType() {
        return itemType == ItemType.BONDED;
    }

    public boolean isInvoicePriceOverridden() {
        return invoicePriceOverridden;
    }

    public void setInvoicePriceOverridden(boolean invoicePriceOverridden) {
        this.invoicePriceOverridden = invoicePriceOverridden;
    }

    public BigDecimal getInitialInvoicePrice() {
        return initialInvoicePrice;
    }

    public void setInitialInvoicePrice(BigDecimal initialInvoicePrice) {
        this.initialInvoicePrice = initialInvoicePrice;
    }

    public Schedule1Part1A getSchedule1Part1A() {
        return schedule1Part1A;
    }

    public void setSchedule1Part1A(Schedule1Part1A schedule1Part1A) {
        this.schedule1Part1A = schedule1Part1A;
    }

    public Schedule1Part2A getSchedule1Part2A() {
        return schedule1Part2A;
    }

    public void setSchedule1Part2A(Schedule1Part2A schedule1Part2A) {
        this.schedule1Part2A = schedule1Part2A;
    }

    public Schedule1Part2B getSchedule1Part2B() {
        return schedule1Part2B;
    }

    public void setSchedule1Part2B(Schedule1Part2B schedule1Part2B) {
        this.schedule1Part2B = schedule1Part2B;
    }

    public Schedule2Part1 getSchedule2Part1() {
        return schedule2Part1;
    }

    public void setSchedule2Part1(Schedule2Part1 schedule2Part1) {
        this.schedule2Part1 = schedule2Part1;
    }

    public Schedule2Part2 getSchedule2Part2() {
        return schedule2Part2;
    }

    public void setSchedule2Part2(Schedule2Part2 schedule2Part2) {
        this.schedule2Part2 = schedule2Part2;
    }

    public Schedule1Part3E getSchedule1Part3E() {
        return schedule1Part3E;
    }

    public void setSchedule1Part3E(Schedule1Part3E schedule1Part3E) {
        this.schedule1Part3E = schedule1Part3E;
    }

    public Schedule1Part7 getSchedule1Part7() {
        return schedule1Part7;
    }

    @Override
    public WeightUnitOfMeasure getWeightUOM() {
        return weightUnitOfMeasure;
    }

    @Override
    public void setWeightUOM(WeightUnitOfMeasure weightUOM) {
        this.weightUnitOfMeasure = weightUOM;
    }

    public void setSchedule1Part7(Schedule1Part7 schedule1Part7) {
        this.schedule1Part7 = schedule1Part7;
    }

    @Override
    public boolean isIntegrated() {
        return false;//to check with claus
    }

    public BigDecimal getDutiableCost() {
        return dutiableCost;
    }

    public void setDutiableCost(BigDecimal dutiableCost) {
        this.dutiableCost = dutiableCost;
    }

    public String getTariffDeterminationNumber() {
        return tariffDeterminationNumber;
    }

    public void setTariffDeterminationNumber(String tariffDeterminationNumber) {
        this.tariffDeterminationNumber = tariffDeterminationNumber;
    }

    public String getHashTariff() {
        return hashTariff;
    }

    public void setHashTariff(String hashTariff) {
        this.hashTariff = hashTariff;
    }

    public String getSupplierReference() {
        return supplierReference;
    }

    public void setSupplierReference(String supplierReference) {
        this.supplierReference = supplierReference;
    }

    public OrganisationalUnitSupplier getSupplier() {
        return supplier;
    }

    public void setSupplier(OrganisationalUnitSupplier supplier) {
        this.supplier = supplier;
    }

    public BigDecimal getValueForCustom() {
        return valueForCustom;
    }

    public void setValueForCustom(BigDecimal valueForCustom) {
        this.valueForCustom = valueForCustom;
    }

    public boolean isFreeOfCharge() {
        return freeOfCharge;
    }

    public void setFreeOfCharge(boolean freeOfCharge) {
        this.freeOfCharge = freeOfCharge;
    }

    public BigDecimal getUnitWidth() {
        return unitWidth;
    }

    public void setUnitWidth(BigDecimal unitWidth) {
        this.unitWidth = unitWidth;
    }

    public BigDecimal getUnitHeight() {
        return unitHeight;
    }

    public void setUnitHeight(BigDecimal unitHeight) {
        this.unitHeight = unitHeight;
    }

    public BigDecimal getUnitLength() {
        return unitLength;
    }

    public void setUnitLength(BigDecimal unitLength) {
        this.unitLength = unitLength;
    }

    public BigDecimal getUnitsPerPackage() {
        return unitsPerPackage;
    }

    @Override
    public BigDecimal getPackageLength() {
        return null;
    }

    @Override
    public BigDecimal getPackageWidth() {
        return null;
    }

    @Override
    public BigDecimal getPackageHeight() {
        return null;
    }

    @Override
    public BigDecimal getPackageVolume() {
        return (ObjectUtil.allNotNull(unitsPerPackage, getUnitVolume())) ? getUnitVolume().multiply(unitsPerPackage) : BigDecimal.ZERO;
    }

    @Override
    public void setUnitWeight(BigDecimal unitWeight) {
        this.weight = unitWeight;
    }

    @Override
    public void setPackageWeight(BigDecimal packageWeight) {

    }

    @Override
    public void setUnitVolume(BigDecimal unitVolume) {
        this.volume = unitVolume;
    }

    @Override
    public void setPackageVolume(BigDecimal packageVolume) {

    }

    @Override
    public void setPackageLength(BigDecimal packageLength) {

    }

    @Override
    public void setPackageWidth(BigDecimal packageWidth) {

    }

    @Override
    public void setPackageHeight(BigDecimal packageHeight) {

    }

    public void setUnitsPerPackage(BigDecimal unitsPerPackage) {
        this.unitsPerPackage = unitsPerPackage;
    }

    public LineItemState getState() {
        return state;
    }

    public void setState(LineItemState state) {
        this.state = state;
    }

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

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

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

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

    public boolean isTariffOverridden() {
        return tariffOverridden;
    }

    public void setTariffOverridden(boolean tariffOverridden) {
        this.tariffOverridden = tariffOverridden;
    }

    @Override
    public Schedule3Part1 getSchedule3Part1() {
        return schedule3Part1;
    }

    @Override
    public void setSchedule3Part1(Schedule3Part1 schedule3Part1) {
        this.schedule3Part1 = schedule3Part1;
    }

    @Override
    public Schedule4Part1 getSchedule4Part1() {
        return schedule4Part1;
    }

    @Override
    public void setSchedule4Part1(Schedule4Part1 schedule4Part1) {
        this.schedule4Part1 = schedule4Part1;
    }

    public BigDecimal getFactor() {
        return BigDecimal.ZERO;
    }

    public Integer getInvoiceLineNumber() {
        return invoiceLineNumber;
    }

    public void setInvoiceLineNumber(Integer invoiceLineNumber) {
        this.invoiceLineNumber = invoiceLineNumber;
    }

    public int getBillOfEntryLineNumber() {
        return billOfEntryLineNumber;
    }

    public void setBillOfEntryLineNumber(int billOfEntryLineNumber) {
        this.billOfEntryLineNumber = billOfEntryLineNumber;
    }

    public boolean isAdValoremPercentageOverridden() {
        return adValoremPercentageOverridden;
    }

    public void setAdValoremPercentageOverridden(boolean adValoremPercentageOverridden) {
        this.adValoremPercentageOverridden = adValoremPercentageOverridden;
    }

    public boolean isAntiDumpingPercentageOverridden() {
        return antiDumpingPercentageOverridden;
    }

    public void setAntiDumpingPercentageOverridden(boolean antiDumpingPercentageOverridden) {
        this.antiDumpingPercentageOverridden = antiDumpingPercentageOverridden;
    }

    public boolean isCounterVailingPercentageOverridden() {
        return counterVailingPercentageOverridden;
    }

    public void setCounterVailingPercentageOverridden(boolean counterVailingPercentageOverridden) {
        this.counterVailingPercentageOverridden = counterVailingPercentageOverridden;
    }

    public boolean isCustomsDutyPercentageOverridden() {
        return customsDutyPercentageOverridden;
    }

    public void setCustomsDutyPercentageOverridden(boolean customsDutyPercentageOverridden) {
        this.customsDutyPercentageOverridden = customsDutyPercentageOverridden;
    }

    @Override
    public boolean applyItacPermit() {
        return itemType == ItemType.GENERAL_REBATE || itemType == ItemType.INDUSTRIAL_REBATE;
    }

    public boolean isOverriddenVolume() {
        return overriddenVolume;
    }

    public void setOverriddenVolume(boolean overriddenVolume) {
        this.overriddenVolume = overriddenVolume;
    }

    public boolean isOverriddenWeight() {
        return overriddenWeight;
    }

    public void setOverriddenWeight(boolean overriddenWeight) {
        this.overriddenWeight = overriddenWeight;
    }

    public void initSchedules() {
        HibernateUtils.initializeAndUnproxy(this.getSchedule3Part1());
        HibernateUtils.initializeAndUnproxy(this.getSchedule2Part2());
        HibernateUtils.initializeAndUnproxy(this.getSchedule1Part2B());
        HibernateUtils.initializeAndUnproxy(this.getSchedule1Part7());
        HibernateUtils.initializeAndUnproxy(this.getSchedule1Part3E());
        HibernateUtils.initializeAndUnproxy(this.getSchedule1Part1A());
        HibernateUtils.initializeAndUnproxy(this.getSchedule1Part2A());
        HibernateUtils.initializeAndUnproxy(this.getSchedule2Part1());
        HibernateUtils.initializeAndUnproxy(this.getSchedule3Part1());
        HibernateUtils.initializeAndUnproxy(this.getSchedule4Part1());
    }

    public Preference getPreference() {
        return preference;
    }

    public void setPreference(Preference preference) {
        this.preference = preference;
    }

    public BigDecimal getQuantityXPriceValue(ActualLineItem actualLineItem) {
        BigDecimal invoiceQuantity = Optional.ofNullable(actualLineItem.getInvoiceQuantity()).orElse(BigDecimal.ZERO);
        BigDecimal invoicePrice = Optional.ofNullable(actualLineItem.getInvoicePrice()).orElse(BigDecimal.ZERO);
        return MathUtils.multiplyVA(invoiceQuantity, invoicePrice);
    }

    public String getStyleReference() {
        return styleReference;
    }

    public void setStyleReference(String styleReference) {
        this.styleReference = styleReference;
    }

    public String getStyleDescription() {
        return styleDescription;
    }

    public void setStyleDescription(String styleDescription) {
        this.styleDescription = styleDescription;
    }

    public Map<String, String> getAdditionalNotes() {
        return additionalNotes;
    }

    public void setAdditionalNotes(Map<String, String> additionalNotes) {
        this.additionalNotes = additionalNotes;
    }

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

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

    public BigDecimal getLinkedDutyDrawBackAmount() {
        return linkedDutyDrawBackAmount;
    }

    public void setLinkedDutyDrawBackAmount(BigDecimal linkedDutyDrawBackAmount) {
        this.linkedDutyDrawBackAmount = linkedDutyDrawBackAmount;
    }

    public ActualLineItemEvent getFirstEvent(LineItemEventType lineItemEventType) {
        return Event.getFirstEvent(events, lineItemEventType);
    }

    public ActualLineItemEvent getLastEvent(LineItemEventType lineItemEventType) {
        List<ActualLineItemEvent> copyEvents = new ArrayList<>(events);
        Collections.reverse(copyEvents);
        return Event.getFirstEvent(copyEvents, lineItemEventType);
    }

    public boolean isUseSADCCertificate() {
        return useSADCCertificate;
    }

    public void setUseSADCCertificate(boolean useSADCCertificate) {
        this.useSADCCertificate = useSADCCertificate;
    }

    public void setMrnNumber(String mrnNumber) {
        this.mrnNumber = mrnNumber;
    }

    public String getMrnNumber() {
        return mrnNumber;
    }

    public void setLrnNumber(String lrnNumber) {
        this.lrnNumber = lrnNumber;
    }

    public String getLrnNumber() {
        return lrnNumber;
    }

    public void setCpcCode(String cpcCode) {
        this.cpcCode = cpcCode;
    }

    public String getCpcCode() {
        return cpcCode;
    }

    public void setBillOfEntryDate(Date billOfEntryDate) {
        this.billOfEntryDate = billOfEntryDate;
    }

    public Date getBillOfEntryDate() {
        return billOfEntryDate;
    }

    public String getTemplateDescription() {
        return templateDescription;
    }

    public void setTemplateDescription(String templateDescription) {
        this.templateDescription = templateDescription;
    }

    @Override
    public Set<ProductProperty> getProperties() {
        return null;
    }

    public BigDecimal getPenaltyAmount() {
        return penaltyAmount;
    }

    public void setPenaltyAmount(BigDecimal penaltyAmount) {
        this.penaltyAmount = penaltyAmount;
    }

    @Override
    public TypeOfGoods getTypeOfGoods() {
        return typeOfGoods;
    }

    @Override
    public void setTypeOfGoods(TypeOfGoods typeOfGoods) {
        this.typeOfGoods = typeOfGoods;
        if (typeOfGoods != null && !typeOfGoods.equals(TypeOfGoods.NEW_GOODS)) {
            getItacPermit().setItacPermit(ItacPermitOptions.YES);
        }
    }

    @Override
    public PenaltyType getPenaltyType() {
        return penaltyType;
    }

    @Override
    public void setPenaltyType(PenaltyType penaltyType) {
        this.penaltyType = penaltyType;
    }

    @Override
    public Long getTemplateId() {
        return templateId;
    }

    @Override
    public void setTemplateId(Long templateId) {
        this.templateId = templateId;
    }

    public Integer getClcPosition() {
        return clcPosition;
    }

    public void setClcPosition(Integer clcPosition) {
        this.clcPosition = clcPosition;
    }

    @Override
    public boolean inTariffiedState() {
        return state == LineItemState.TARIFFED;
    }

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

    @Override
    public NamedPlace getFactory() {
        return factory;
    }

    public void setFactory(NamedPlace factory) {
        this.factory = factory;
    }

    public AdditionalLineItemType getFreeStockType() {
        return freeStockType;
    }

    public void setFreeStockType(AdditionalLineItemType freeStockType) {
        this.freeStockType = freeStockType;
    }

    public StatisticalUnit getStatisticalUnit() {
        if (statisticalUnit == null) {
            statisticalUnit = new StatisticalUnit();
        }
        return statisticalUnit;
    }

    public void setStatisticalUnit(StatisticalUnit statisticalUnit) {
        this.statisticalUnit = statisticalUnit;
    }

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

    public Set<AdditionalClearingInfo> getAdditionalClearingInfo() {
        return additionalClearingInfo;
    }

    public void setAdditionalClearingInfo(Set<AdditionalClearingInfo> additionalClearingInfo) {
        this.additionalClearingInfo.clear();
        if (additionalClearingInfo != null)
            this.additionalClearingInfo.addAll(additionalClearingInfo);
    }

    public Brand getBrand() {
        return brand;
    }

    public void setBrand(Brand brand) {
        this.brand = brand;
    }

    public String getImplementationType() {
        return "ACTUALITEM";
    }

    public String getInvoiceLineDescription() {
        return invoiceLineDescription;
    }

    public void setInvoiceLineDescription(String invoiceLineDescription) {
        this.invoiceLineDescription = invoiceLineDescription;
    }

    @Override
    public PersistenceBase initialize() {
        if (getSchedule1Part1A() != null)
            setSchedule1Part1A(HibernateUtils.initializeAndUnproxy(getSchedule1Part1A()));
        if (getSchedule1Part2B() != null)
            setSchedule1Part2B(HibernateUtils.initializeAndUnproxy(getSchedule1Part2B()));
        if (getSchedule1Part2A() != null)
            setSchedule1Part2A(HibernateUtils.initializeAndUnproxy(getSchedule1Part2A()));
        if (getSchedule2Part1() != null)
            setSchedule2Part1(HibernateUtils.initializeAndUnproxy(getSchedule2Part1()));
        if (getSchedule2Part2() != null)
            setSchedule2Part2(HibernateUtils.initializeAndUnproxy(getSchedule2Part2()));
        if (getSchedule1Part3E() != null)
            setSchedule1Part3E(HibernateUtils.initializeAndUnproxy(getSchedule1Part3E()));
        if (getSchedule1Part7() != null)
            setSchedule1Part7(HibernateUtils.initializeAndUnproxy(getSchedule1Part7()));
        if (getSchedule3Part1() != null)
            setSchedule3Part1(HibernateUtils.initializeAndUnproxy(getSchedule3Part1()));
        if (getSchedule4Part1() != null)
            setSchedule4Part1(HibernateUtils.initializeAndUnproxy(getSchedule4Part1()));
        return super.initialize();
    }

    public boolean equalsGRRItem(GoodsReceivedReceiptItem item) {
        if (item != null && getCode().equals(item.getReference()) &&
                Objects.equals(lineNumber, item.getLineNumber()) &&
                getOrganisation().equals(item.getOrganisationalUnit().getCode())) {
            return true;
        }
        return false;
    }

}