ContainerUsage.java
package com.tradecloud.domain.container;
import com.tradecloud.common.base.PersistenceBase;
import com.tradecloud.domain.model.ordermanagement.Order;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
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.Optional;
/**
* Container Usage - How a container will be used by an order. The user will be able to specify the order ratio that will be packed into a container.
* If you only have one order linked to a consignment, the order will appear below each container to allow a user to specify the ratio of each order
* into the various container types. If you have multiple orders linked to a consignment, the user will be able to specify the ratio of different
* order that will be packed into a container. 'Order number and Order references'. Display both the order number and the order reference separated by
* a hyphen are highlighted in red in the screenshot below. The container type FCL20GP is filled by 0.29 of order 042438 (system generated number)
* 4300031803 (po ref) and 0.71 of order 042259 (system generated number) 12/0683A (po ref).
*/
@Entity
@Component(value = "containerusage")
@Table(name = "containerusage")
@Access(AccessType.FIELD)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ContainerUsage")
public class ContainerUsage extends PersistenceBase implements Comparable<ContainerUsage> {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@NotNull
@XmlIDREF
@XmlAttribute(name = "OrderNumber")
private Order order;
@ManyToOne
@JoinColumn(name = "container_id")
@XmlTransient
private Container container;
private BigDecimal volumem3;
private BigDecimal weightKG;
private BigDecimal chargeableWeightKG;
private boolean volumeOverridden;
private boolean weightOverridden;
@XmlElement
protected BigDecimal cartonsPerContainer;
public static ContainerUsageBuilder createBuilder() {
return new ContainerUsageBuilder();
}
/**
* The quantity/proportion of the container that will be utilized by each order linked to the consignment.
*/
private BigDecimal numberAtPOD = new BigDecimal("0.0000");
/**
* Indicates if the container will first go to a clearing depot.
*/
private BigDecimal numberAtClearingDepot;
/**
* Indicates if the container will go directly to a final destination and not to a clearing depot.
* <p>
* If the user changed the Number at clearing depot field, the Number directly to Final Destination field
* should be recalculated as follows: Number directly to FD = (Number at POD - Number at Clearing depot)
*/
private BigDecimal numberDirectlyToFinalDestination;
/**
* The days that the container will be held in storage.
*/
private BigDecimal numberOfDaysAtStorage;
public ContainerUsage() {
}
public ContainerUsage(Order order, Container container, BigDecimal numberAtPOD, BigDecimal numberAtClearingDepot,
BigDecimal numberDirectlyToFinalDestination, BigDecimal numberOfDaysAtStorage) {
this.order = order;
this.container = container;
this.numberAtPOD = numberAtPOD;
this.numberAtClearingDepot = numberAtClearingDepot;
this.numberDirectlyToFinalDestination = numberDirectlyToFinalDestination;
this.numberOfDaysAtStorage = numberOfDaysAtStorage;
calculateAndSetCartonsPerContainer();
}
public ContainerUsage(Order order, Container container, BigDecimal numberAtPOD, BigDecimal numberAtClearingDepot,
BigDecimal numberDirectlyToFinalDestination, BigDecimal numberOfDaysAtStorage, BigDecimal volumem3, BigDecimal weightKG,
BigDecimal chargeableWeightKG) {
this.order = order;
this.container = container;
this.numberAtPOD = numberAtPOD;
this.numberAtClearingDepot = numberAtClearingDepot;
this.numberDirectlyToFinalDestination = numberDirectlyToFinalDestination;
this.numberOfDaysAtStorage = numberOfDaysAtStorage;
this.volumem3 = volumem3;
this.weightKG = weightKG;
this.chargeableWeightKG = chargeableWeightKG;
calculateAndSetCartonsPerContainer();
}
public Container getContainer() {
return container;
}
public void setContainer(Container container) {
this.container = container;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public BigDecimal getNumberAtPOD() {
return numberAtPOD;
}
public void setNumberAtPOD(BigDecimal numberAtPOD) {
this.numberAtPOD = numberAtPOD;
if (numberAtClearingDepot != null) {
recalculateNumberDirectlyToFinalDestination(numberAtClearingDepot);
}
}
public BigDecimal getNumberAtClearingDepot() {
return numberAtClearingDepot;
}
/**
* If the user changed the numberAtClearingDepot field, the numberDirectlyToFinalDestination field
* should be recalculated as follows: Number directly to FD = (Number at POD - Number at Clearing depot).
*
* @param numberAtClearingDepot
*/
public void setNumberAtClearingDepot(BigDecimal numberAtClearingDepot) {
if (this.numberAtClearingDepot != null && !this.numberAtClearingDepot.equals(numberAtClearingDepot)) {
recalculateNumberDirectlyToFinalDestination(numberAtClearingDepot);
}
this.numberAtClearingDepot = numberAtClearingDepot;
}
private void recalculateNumberDirectlyToFinalDestination(BigDecimal numberAtClearingDepotParam) {
if (numberAtPOD != null) {
this.numberDirectlyToFinalDestination = numberAtPOD.subtract(numberAtClearingDepotParam);
}
}
public BigDecimal getNumberDirectlyToFinalDestination() {
return numberDirectlyToFinalDestination;
}
public void setNumberDirectlyToFinalDestination(BigDecimal numberDirectlyToFinalDestination) {
this.numberDirectlyToFinalDestination = numberDirectlyToFinalDestination;
}
public void setNumberOfDaysAtStorage(BigDecimal numberOfDaysAtStorage) {
this.numberOfDaysAtStorage = numberOfDaysAtStorage;
}
public BigDecimal getNumberOfDaysAtStorage() {
return numberOfDaysAtStorage;
}
public BigDecimal getVolumem3() {
return volumem3;
}
public void setVolumem3(BigDecimal volumem3) {
if(!volumeOverridden) {
this.volumem3 = volumem3;
}
}
public void setVolumem3NoOverride(BigDecimal volumem3) {
this.volumem3 = volumem3;
}
public BigDecimal getWeightKG() {
return weightKG;
}
public void setWeightKG(BigDecimal weightKG) {
if(!weightOverridden) {
this.weightKG = weightKG;
}
}
public void setWeightKGNoOverride(BigDecimal weightKG) {
this.weightKG = weightKG;
}
public BigDecimal getChargeableWeightKG() {
return chargeableWeightKG;
}
public void setChargeableWeightKG(BigDecimal chargeableWeightKG) {
this.chargeableWeightKG = chargeableWeightKG;
}
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
if (container != null) {
builder.append(container.getId());
}
if (order != null) {
builder.append(order.getId());
}
builder.append(numberAtClearingDepot).append(numberAtPOD).append(numberDirectlyToFinalDestination).append(numberOfDaysAtStorage);
return builder.hashCode();
}
@Override
public boolean equals(Object obj) {
ContainerUsage other = (ContainerUsage) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(order, other.getOrder()).append(container, other.getContainer())
.append(numberAtClearingDepot, other.getNumberAtClearingDepot()).append(numberAtPOD, other.getNumberAtPOD())
.append(numberDirectlyToFinalDestination, other.getNumberDirectlyToFinalDestination())
.append(numberOfDaysAtStorage, other.getNumberOfDaysAtStorage()).append(volumem3, other.getVolumem3())
.append(weightKG, other.getWeightKG()).append(chargeableWeightKG, other.getChargeableWeightKG());
return builder.isEquals();
}
@Override
public String toString() {
return new ToStringBuilder(this).append("container", container).append("numberAtPOD", numberAtPOD)
.append("numberAtClearingDepot", numberAtClearingDepot).append("numberDirectlyToFinalDestination", numberDirectlyToFinalDestination)
.append("numberOfDaysAtStorage", numberOfDaysAtStorage).append("volumem3", volumem3).append("weightKG", weightKG)
.append("chargeableWeightKG", chargeableWeightKG).toString();
}
public static class ContainerUsageBuilder {
private static final String ZERO = "0.0000";
private Order order;
private Container container;
private BigDecimal numberAtPOD;
private BigDecimal numberAtClearingDepot;
private BigDecimal numberDirectlyToFinalDestination;
private BigDecimal numberOfDaysAtStorage;
private BigDecimal volumem3;
private BigDecimal weightKG;
private BigDecimal chargeableWeightKG;
protected BigDecimal cartonsPerContainer;
public ContainerUsage build() {
setDefaults();
return new ContainerUsage(order, container, numberAtPOD, numberAtClearingDepot, numberDirectlyToFinalDestination, numberOfDaysAtStorage,
volumem3, weightKG, chargeableWeightKG);
}
/*
* Do any of the default value setting here
*/
private void setDefaults() {
/*
* If a clearing depot is selected on the order, the quantity will default to the quantity specified in the "Number at POD" field for this
* order. If no clearing depot is selected on the order, the quantity will default to 0.00 and the field will not be editable
*/
if (order.getShippingInformation() != null && order.getShippingInformation().getClearingDepot() != null) {
setNumberAtClearingDepot(numberAtPOD);
setNumberDirectlyToFinalDestination(new BigDecimal(ZERO));
} else {
setNumberAtClearingDepot(new BigDecimal(ZERO));
setNumberDirectlyToFinalDestination(numberAtPOD);
}
// TODO - number of days storage from the client config
}
public ContainerUsageBuilder setOrder(Order order) {
this.order = order;
return this;
}
public ContainerUsageBuilder setContainer(Container container) {
this.container = container;
return this;
}
public ContainerUsageBuilder setNumberAtPOD(BigDecimal numberAtPOD) {
this.numberAtPOD = numberAtPOD;
return this;
}
public ContainerUsageBuilder setNumberAtClearingDepot(BigDecimal numberAtClearingDepot) {
this.numberAtClearingDepot = numberAtClearingDepot;
return this;
}
public ContainerUsageBuilder setNumberDirectlyToFinalDestination(BigDecimal numberDirectlyToFinalDestination) {
this.numberDirectlyToFinalDestination = numberDirectlyToFinalDestination;
return this;
}
public ContainerUsageBuilder setNumberOfDaysAtStorage(BigDecimal numberOfDaysAtStorage) {
this.numberOfDaysAtStorage = numberOfDaysAtStorage;
return this;
}
public ContainerUsageBuilder setVolumem3(BigDecimal volumem3) {
this.volumem3 = volumem3;
return this;
}
public ContainerUsageBuilder setWeightKG(BigDecimal weightKG) {
this.weightKG = weightKG;
return this;
}
public ContainerUsageBuilder setChargeableWeightKG(BigDecimal chargeableWeightKG) {
this.chargeableWeightKG = chargeableWeightKG;
return this;
}
}
public boolean isVolumeOverridden() {
return volumeOverridden;
}
public void setVolumeOverridden(boolean volumeOverridden) {
this.volumeOverridden = volumeOverridden;
}
public boolean isWeightOverridden() {
return weightOverridden;
}
public void setWeightOverridden(boolean weightOverridden) {
this.weightOverridden = weightOverridden;
}
@Override
public int compareTo(ContainerUsage o) {
if (getContainer().getContainerType().getName().compareToIgnoreCase(o.getContainer().getContainerType().getName()) == 0) {
// return getOrder().getNumber().compareTo(o.getOrder().getNumber());
return getOrder().getAddedToConsignmentDate().compareTo(o.getOrder().getAddedToConsignmentDate());
}
return getContainer().getContainerType().getName().compareToIgnoreCase(o.getContainer().getContainerType().getName());
}
public BigDecimal getCartonsPerContainer() {
if (cartonsPerContainer == null) {
calculateAndSetCartonsPerContainer();
}
return cartonsPerContainer;
}
public void setCartonsPerContainer(BigDecimal cartonsPerContainer) {
this.cartonsPerContainer = cartonsPerContainer;
}
public void calculateAndSetCartonsPerContainer() {
if (order != null && !order.inNonEditableState()) {
final BigDecimal sumPQ = order.getLineItems().stream().map(l -> Optional.ofNullable(l.getPackageQuantity()).orElse(BigDecimal.ZERO))
.reduce(BigDecimal.ZERO, BigDecimal::add);
setCartonsPerContainer(sumPQ);
}
}
}