LocationVO.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.location.api;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
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 org.ameba.http.AbstractBase;
import org.openwms.common.location.api.TargetVO;

import java.io.Serializable;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.StringJoiner;

import static org.openwms.wms.api.TimeProvider.DATE_TIME_WITH_TIMEZONE;

/**
 * A LocationVO.
 *
 * @author Heiko Scherrer
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
public class LocationVO extends AbstractBase<LocationVO> implements TargetVO, Serializable {

    /** The persistent technical key. */
    @JsonProperty("pKey")
    private String pKey;
    /** Unique natural key. */
    @JsonProperty("locationId")
    private String locationId;
    /** Unique identifier of a {@code LocationGroup}. */
    @JsonProperty("locationGroupName")
    private String locationGroupName;
    /** Signals the incoming state of this {@code Location}. */
    @JsonProperty("incomingActive")
    private Boolean incomingActive;
    /** Signals the outgoing state of this {@code Location}. */
    @JsonProperty("outgoingActive")
    private Boolean outgoingActive;
    /** Whether it is allowed to store different {@code Products} on this {@code Location}. */
    @JsonProperty("mixedProducts")
    private Boolean mixedProducts;
    /** Whether it is allowed to move {@code Products} without {@code TransportUnit} to this {@code Location} directly. */
    @JsonProperty("directBookingAllowed")
    private Boolean directBookingAllowed;
    /** The PLC is able to change the state of a {@code Location}. This property stores the last state, received from the PLC. */
    @JsonProperty("plcState")
    private Integer plcState;
    /** ERP code of the {@code Location}. */
    @JsonProperty("erpCode")
    private String erpCode;
    /** Description of the {@code Location}. */
    @JsonProperty("description")
    private String description;
    /** Sort order index used by Putaway strategies. */
    @JsonProperty("sortOrder")
    private Integer sortOrder;
    /** Maximum number of {@code TransportUnit}s allowed on this {@code Location}. */
    @JsonProperty("noMaxTransportUnits")
    private Integer noMaxTransportUnits;
    /** When picking happened the last time on this {@code Location}. */
    @JsonProperty("lastPickingDate")
    @JsonFormat(pattern = DATE_TIME_WITH_TIMEZONE)
    private ZonedDateTime lastPickingDate;
    /** When was this {@code Location} the last time under stock-taking. */
    @JsonProperty("lastInventoryDate")
    @JsonFormat(pattern = DATE_TIME_WITH_TIMEZONE)
    private ZonedDateTime lastInventoryDate;

    /*~-------------------- constructors --------------------*/
    public LocationVO() {}

    public LocationVO(String locationId) {
        Objects.requireNonNull(locationId);
        this.locationId = locationId;
    }

    public static LocationVO of(String locationId) {
        return new LocationVO(locationId);
    }

    /*~-------------------- methods --------------------*/
    /**
     * Checks whether the Location is blocked for incoming goods.
     *
     * @return {@literal true} if blocked, otherwise {@literal false}
     */
    @JsonIgnore
    public Boolean isInfeedBlocked() {
        return !incomingActive;
    }

    /**
     * Checks whether the Location is blocked for outgoing goods.
     *
     * @return {@literal true} if blocked, otherwise {@literal false}
     */
    @JsonIgnore
    public Boolean isOutfeedBlocked() {
        return !outgoingActive;
    }

    /**
     * Is it allowed to have different {@code Product}s on the {@code Location}.
     *
     * @return {@literal true} if allowed
     */
    @JsonIgnore
    public boolean isMixingProductsAllowed() {
        return this.mixedProducts == Boolean.TRUE;
    }

    public boolean hasNoMaxTransportUnits() {
        return this.noMaxTransportUnits != null;
    }

    public boolean hasErpCode() {
        return erpCode != null && !erpCode.isEmpty();
    }

    public boolean hasLocationId() {
        return locationId != null && !locationId.isEmpty();
    }

    /*~-------------------- accessors --------------------*/
    @Override
    public String getpKey() {
        return pKey;
    }

    public void setpKey(String pKey) {
        this.pKey = pKey;
    }

    public String getLocationId() {
        return locationId;
    }

    public void setLocationId(String locationId) {
        this.locationId = locationId;
    }

    public String getLocationGroupName() {
        return locationGroupName;
    }

    public void setLocationGroupName(String locationGroupName) {
        this.locationGroupName = locationGroupName;
    }

    public Boolean getIncomingActive() {
        return incomingActive;
    }

    public void setIncomingActive(Boolean incomingActive) {
        this.incomingActive = incomingActive;
    }

    public Boolean getOutgoingActive() {
        return outgoingActive;
    }

    public void setOutgoingActive(Boolean outgoingActive) {
        this.outgoingActive = outgoingActive;
    }

    public Boolean getMixedProducts() {
        return mixedProducts;
    }

    public void setMixedProducts(Boolean mixedProducts) {
        this.mixedProducts = mixedProducts;
    }

    public Boolean getDirectBookingAllowed() {
        return directBookingAllowed;
    }

    public void setDirectBookingAllowed(Boolean directBookingAllowed) {
        this.directBookingAllowed = directBookingAllowed;
    }

    public Integer getPlcState() {
        return plcState;
    }

    public void setPlcState(Integer plcState) {
        this.plcState = plcState;
    }

    public String getErpCode() {
        return erpCode;
    }

    public void setErpCode(String erpCode) {
        this.erpCode = erpCode;
    }

    public String getDescription() {
        return description;
    }

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

    public Integer getSortOrder() {
        return sortOrder;
    }

    public void setSortOrder(Integer sortOrder) {
        this.sortOrder = sortOrder;
    }

    public Integer getNoMaxTransportUnits() {
        return noMaxTransportUnits;
    }

    public void setNoMaxTransportUnits(Integer noMaxTransportUnits) {
        this.noMaxTransportUnits = noMaxTransportUnits;
    }

    public ZonedDateTime getLastPickingDate() {
        return lastPickingDate;
    }

    public void setLastPickingDate(ZonedDateTime lastPickingDate) {
        this.lastPickingDate = lastPickingDate;
    }

    public ZonedDateTime getLastInventoryDate() {
        return lastInventoryDate;
    }

    public void setLastInventoryDate(ZonedDateTime lastInventoryDate) {
        this.lastInventoryDate = lastInventoryDate;
    }

    /*~-------------------- overrides --------------------*/
    /**
     * {@inheritDoc}
     */
    @Override
    public String asString() {
        return locationId;
    }

    /**
     * {@inheritDoc}
     *
     * All fields.
     */
    @Override
    public String toString() {
        return new StringJoiner(", ", LocationVO.class.getSimpleName() + "[", "]")
                .add("pKey='" + pKey + "'")
                .add("locationId='" + locationId + "'")
                .add("locationGroupName='" + locationGroupName + "'")
                .add("incomingActive=" + incomingActive)
                .add("outgoingActive=" + outgoingActive)
                .add("mixedProducts=" + mixedProducts)
                .add("directBookingAllowed=" + directBookingAllowed)
                .add("plcState=" + plcState)
                .add("erpCode='" + erpCode + "'")
                .add("description='" + description + "'")
                .add("noMaxTransportUnits=" + noMaxTransportUnits)
                .add("lastPickingDate=" + lastPickingDate)
                .add("lastInventoryDate=" + lastInventoryDate)
                .toString();
    }

    /**
     * {@inheritDoc}
     *
     * All fields.
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof LocationVO)) return false;
        if (!super.equals(o)) return false;
        LocationVO that = (LocationVO) o;
        return Objects.equals(pKey, that.pKey) && Objects.equals(locationId, that.locationId) && Objects.equals(locationGroupName, that.locationGroupName) && Objects.equals(incomingActive, that.incomingActive) && Objects.equals(outgoingActive, that.outgoingActive) && Objects.equals(mixedProducts, that.mixedProducts) && Objects.equals(directBookingAllowed, that.directBookingAllowed) && Objects.equals(plcState, that.plcState) && Objects.equals(erpCode, that.erpCode) && Objects.equals(description, that.description) && Objects.equals(noMaxTransportUnits, that.noMaxTransportUnits) && Objects.equals(lastPickingDate, that.lastPickingDate) && Objects.equals(lastInventoryDate, that.lastInventoryDate);
    }

    /**
     * {@inheritDoc}
     *
     * All fields.
     */
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), pKey, locationId, locationGroupName, incomingActive, outgoingActive, mixedProducts, directBookingAllowed, plcState, erpCode, description, noMaxTransportUnits, lastPickingDate, lastInventoryDate);
    }
}