PackagingUnitVO.java
/*
* Copyright 2005-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openwms.wms.inventory.api;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import org.ameba.http.AbstractBase;
import org.openwms.core.units.api.Measurable;
import org.openwms.core.units.api.Weight;
import org.openwms.wms.location.api.LocationVO;
import java.beans.ConstructorProperties;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import static org.openwms.wms.api.TimeProvider.DATE_TIME_WITH_TIMEZONE;
/**
* A PackagingUnitVO represents a quantity of a {@code Product} packaged into a single physical unit.
*
* @author Heiko Scherrer
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class PackagingUnitVO extends AbstractBase<PackagingUnitVO> {
/** The persistent key of the {@code PackagingUnit}. */
@JsonProperty("pKey")
@Null(groups = ValidationGroups.CreatePackagingUnit.class)
public String pKey;
/** Some hint where to find the {@code PackagingUnit} within its container. */
@JsonProperty("physicalPosition")
public String physicalPosition;
/** The serial number of the {@code PackagingUnit}. */
@JsonProperty("serialNumber")
public String serialNumber;
/** The business key referring to a defined {@code Lot}. */
@JsonProperty("lotId")
private String lotId;
/** The expiration date of this particular {@code PackagingUnit}. */
@JsonProperty("expiresAt")
@JsonFormat(pattern = DATE_TIME_WITH_TIMEZONE)
private ZonedDateTime expiresAt;
/** The production date of this particular {@code PackagingUnit}. */
@JsonProperty("producedAt")
@JsonFormat(pattern = DATE_TIME_WITH_TIMEZONE)
private ZonedDateTime producedAt;
/** A {@code PackagingUnit} can have arbitrary labels assigned. */
@JsonProperty("labels")
private List<String> labels;
/** Packed {@code Product}, must not be {@literal null}. */
@JsonProperty("product")
public ProductVO product;
/** Described in what kind of UOM the PackagingUnit is stored in. */
@JsonProperty("productUnit")
public UomRelationVO uomRelation;
/** Packed quantity, must not be {@literal null}. */
@JsonProperty("quantity")
@NotNull
public Measurable quantity;
/** Calculated available quantity. */
@JsonProperty("qtyAvailable")
public Measurable qtyAvailable;
/** Availability state of this {@code PackagingUnit}. */
@JsonProperty("state")
private String state;
/** The comprising {@code LoadUnit} the {@code PackagingUnit} is stored in. */
@JsonProperty("loadUnit")
public LoadUnitVO loadUnit;
/** The actual {@code Location} the {@code PackagingUnit} is placed on. */
@JsonProperty("actualLocation")
public LocationVO actualLocation;
/** The current dimension of the {@code PackagingUnit}. */
@JsonProperty("dimension")
public DimensionVO dimension;
/** The current weight of the {@code PackagingUnit}. */
@JsonProperty("weight")
public Weight weight;
/** Any kind of message placed on the {@code PackagingUnit}. */
@JsonProperty("message")
public String message;
/** How are the {@code PackagingUnit}s distributed in a {@code LoadUnit}. */
@JsonProperty("distribution")
public PhysicalDistributionVO loadUnitDistribution;
/** Arbitrary detail information on this {@code PackagingUnit}. */
@JsonProperty("details")
private Map<String, String> details = new HashMap<>();
@Valid
public boolean validate() {
return !(this.product == null && this.uomRelation == null);
}
/*~ -------------- Constructors -------------- */
public PackagingUnitVO() { }
@ConstructorProperties({"product", "quantity"})
public PackagingUnitVO(ProductVO product, Measurable quantity) {
this.product = product;
this.quantity = quantity;
}
/*~ --------------- Methods ---------------- */
@JsonIgnore
@Valid
public boolean isValid() {
return (this.loadUnit == null && this.actualLocation != null) ||
(this.loadUnit != null && this.actualLocation == null);
}
@JsonIgnore
public boolean hasLoadUnit() {
return this.loadUnit != null;
}
@JsonIgnore
public boolean hasActualLocation() {
return this.actualLocation != null;
}
/**
* {@inheritDoc}
*
* Not:
* - details
*/
@Override
public String toString() {
return new StringJoiner(", ", PackagingUnitVO.class.getSimpleName() + "[", "]")
.add("pKey='" + pKey + "'")
.add("physicalPosition='" + physicalPosition + "'")
.add("serialNumber='" + serialNumber + "'")
.add("lotId='" + lotId + "'")
.add("expiresAt=" + expiresAt)
.add("producedAt=" + producedAt)
.add("labels=" + labels)
.add("product=" + product)
.add("quantity=" + quantity)
.add("state='" + state + "'")
.add("loadUnit=" + loadUnit)
.add("actualLocation=" + actualLocation)
.add("dimension=" + dimension)
.add("weight=" + weight)
.add("message='" + message + "'")
.add("loadUnitDistribution=" + loadUnitDistribution)
.toString();
}
/**
* {@inheritDoc}
*
* Not:
* - details
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PackagingUnitVO)) return false;
if (!super.equals(o)) return false;
PackagingUnitVO that = (PackagingUnitVO) o;
return Objects.equals(pKey, that.pKey) && Objects.equals(physicalPosition, that.physicalPosition) && Objects.equals(serialNumber, that.serialNumber)&& Objects.equals(lotId, that.lotId) && Objects.equals(expiresAt, that.expiresAt) && Objects.equals(producedAt, that.producedAt) && Objects.equals(labels, that.labels) && Objects.equals(product, that.product) && Objects.equals(quantity, that.quantity) && Objects.equals(state, that.state) && Objects.equals(loadUnit, that.loadUnit) && Objects.equals(actualLocation, that.actualLocation) && Objects.equals(dimension, that.dimension) && Objects.equals(weight, that.weight) && Objects.equals(message, that.message) && Objects.equals(loadUnitDistribution, that.loadUnitDistribution);
}
/**
* {@inheritDoc}
*
* Not:
* - details
*/
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), pKey, physicalPosition, serialNumber, lotId, expiresAt, producedAt, labels, product, quantity, state, loadUnit, actualLocation, dimension, weight, message, loadUnitDistribution);
}
/*~ --------------- Accessors ---------------- */
public String getpKey() {
return pKey;
}
public void setpKey(String pKey) {
this.pKey = pKey;
}
public String getPhysicalPosition() {
return physicalPosition;
}
public void setPhysicalPosition(String physicalPosition) {
this.physicalPosition = physicalPosition;
}
public String getSerialNumber() {
return serialNumber;
}
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
public String getLotId() {
return lotId;
}
public void setLotId(String lotId) {
this.lotId = lotId;
}
public ZonedDateTime getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(ZonedDateTime expiresAt) {
this.expiresAt = expiresAt;
}
public ZonedDateTime getProducedAt() {
return producedAt;
}
public void setProducedAt(ZonedDateTime producedAt) {
this.producedAt = producedAt;
}
public List<String> getLabels() {
return labels;
}
public void setLabels(List<String> labels) {
this.labels = labels;
}
public ProductVO getProduct() {
return product;
}
public void setProduct(ProductVO product) {
this.product = product;
}
public UomRelationVO getUomRelation() {
return uomRelation;
}
public void setUomRelation(UomRelationVO uomRelation) {
this.uomRelation = uomRelation;
}
public Measurable getQuantity() {
return quantity;
}
public void setQuantity(Measurable quantity) {
this.quantity = quantity;
}
public Measurable getQtyAvailable() {
return qtyAvailable;
}
public void setQtyAvailable(Measurable qtyAvailable) {
this.qtyAvailable = qtyAvailable;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public LoadUnitVO getLoadUnit() {
return loadUnit;
}
public void setLoadUnit(LoadUnitVO loadUnit) {
this.loadUnit = loadUnit;
}
public LocationVO getActualLocation() {
return actualLocation;
}
public void setActualLocation(LocationVO actualLocation) {
this.actualLocation = actualLocation;
}
public DimensionVO getDimension() {
return dimension;
}
public void setDimension(DimensionVO dimension) {
this.dimension = dimension;
}
public Weight getWeight() {
return weight;
}
public void setWeight(Weight weight) {
this.weight = weight;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public PhysicalDistributionVO getLoadUnitDistribution() {
return loadUnitDistribution;
}
public void setLoadUnitDistribution(PhysicalDistributionVO loadUnitDistribution) {
this.loadUnitDistribution = loadUnitDistribution;
}
public Map<String, String> getDetails() {
return details;
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
}