# OrderItem.java

    package org.example.customer;

    /*
     * This is free and unencumbered software released into the public domain.
     * Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software,
     * either in source code form or as a compiled binary, for any purpose, commercial or
     * non-commercial, and by any means.
     *
     * In jurisdictions that recognize copyright laws, the author or authors of this
     * software dedicate any and all copyright interest in the software to the public domain.
     * We make this dedication for the benefit of the public at large and to the detriment of
     * our heirs and successors. We intend this dedication to be an overt act of relinquishment in
     * perpetuity of all present and future rights to this software under copyright law.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
     * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
     * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES
     * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     *
     * For more information, please refer to: https://unlicense.org/
    */

    import java.io.Serializable;

    import org.apache.commons.lang3.builder.EqualsBuilder;
    import org.apache.commons.lang3.builder.HashCodeBuilder;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.example.customer.utility.CustomerEntity;

    /**
     * The OrderItem Entity for the Customer application.
     * <p>
     * This class represents the following DB Table:
     *
     * <pre>
     * CREATE TABLE ORDER_ITEM (
     *      ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
     *      ORDER_ID INTEGER NOT NULL,
     *      PRODUCT_ID INTEGER NOT NULL,
     *      UNIT_PRICE DECIMAL(12,2) NOT NULL,
     *      QUANTITY INTEGER NOT NULL,
     *      CONSTRAINT PK_ORDERITEM PRIMARY KEY (ID)
     *   );
     * </pre>
     *
     * @author Jonathan Earl
     * @version 1.0
     *
     */
    public final class OrderItem extends CustomerEntity
        implements Serializable
    {
        private static final long serialVersionUID = 1L;

        private static final Logger LOG = LogManager.getLogger();

        private int myOrderId;
        private int myProductId;
        private double myUnitPrice;
        private int myQuantity;
        private double mySubTotal;

        /**
         * The default constructor for the OrderItem class.
         * <p>
         * The initial values are:
         * <ul>
         * <li>id: 1</li>
         * <li>orderId: 1</li>
         * <li>productId: 1</li>
         * <li>unitPrice: 0.01</li>
         * <li>quantity: 1</li>
         * <li>subTotal: unitPrice * quantity</li>
         * </ul>
         */
        public OrderItem()
        {
            LOG.debug("Starting the default Constructor");
            final int initialId = 1;
            final int initialOrderId = 1;
            final int initialProductId = 1;
            final double initialUnitPrice = 0.01;
            final int initialQuantity = 1;

            setId(initialId);
            setOrderId(initialOrderId);
            setProductId(initialProductId);
            setUnitPrice(initialUnitPrice);
            setQuantity(initialQuantity);
            computeSubTotal();
        }

        /**
         * Computes the OrderItem subTotal as quantity * unitPrice.
         */
        private void computeSubTotal()
        {
            LOG.debug("Computing the subTotal");
            mySubTotal = myQuantity * myUnitPrice;

        }

        /**
         * Returns the orderId value for the Order.
         *
         * @return the orderId value for the order
         */
        public int getOrderId()
        {
            LOG.debug("returning the OrderId: " + myOrderId);
            return myOrderId;
        }

        /**
         * Sets the orderId value for the OrderItem.
         * <p>
         * The business rules are:
         * <ul>
         *   <li>the orderId must be 1 or greater</li>
         * </ul>
         *
         * @param orderId the value to set into the orderId field
         * @throws IllegalArgumentException if the orderId is invalid
         */
        public void setOrderId(final int orderId)
        {
            LOG.debug("setting the OrderId: " + orderId);
            final int min = 1;

            if (orderId < min)
            {
                LOG.error("OrderId must be greater then zero");
                throw new IllegalArgumentException("OrderId must be greater then zero");
            }
            this.myOrderId = orderId;
        }

        /**
         * Returns the productId value for the OrderItem.
         *
         * @return the productId value for the OrderItem
         */
        public int getProductId()
        {
            LOG.debug("returning the ProductId: " + myProductId);
            return myProductId;
        }

        /**
         * Sets the productId value for the Order.
         * <p>
         * The business rules are:
         * <ul>
         *   <li>the productId must be 1 or greater</li>
         * </ul>
         *
         * @param productId the value to set into the productId field
         * @throws IllegalArgumentException if the productId is invalid
         */
        public void setProductId(final int productId)
        {
            LOG.debug("setting the productId: " + productId);
            final int min = 1;

            if (productId < min)
            {
                LOG.error("productId must be greater then zero");
                throw new IllegalArgumentException("productId must be greater then zero");
            }
            this.myProductId = productId;
        }

        /**
         * Returns the UnitPrice value for the OrderItem.
         *
         * @return the UnitPrice value for the OrderItem
         */
        public double getUnitPrice()
        {
            LOG.debug("returning the UnitPrice: " + myUnitPrice);
            return myUnitPrice;
        }

        /**
         * Sets the UnitPrice value for the OrderItem.
         * <p>
         * The business rules are:
         * <ul>
         *   <li>the UnitPrice must be 0.01 or greater</li>
         * </ul>
         * This will also recompute the subTotal value.
         *
         * @param unitPrice the value to set into the unitPrice field
         * @throws IllegalArgumentException if the UnitPrice is invalid
         */
        public void setUnitPrice(final double unitPrice)
        {
            LOG.debug("setting the unitPrice: " + unitPrice);
            final double min = 0.01;

            if (unitPrice < min)
            {
                LOG.error("unitPrice must be greater then zero");
                throw new IllegalArgumentException("unitPrice must be greater then zero");
            }
            this.myUnitPrice = unitPrice;
            computeSubTotal();
        }

        /**
         * Returns the Quantity value for the OrderItem.
         *
         * @return the Quantity value for the OrderItem
         */
        public int getQuantity()
        {
            LOG.debug("returning the Quantity: " + myQuantity);
            return myQuantity;
        }

        /**
         * Sets the Quantity value for the OrderItem.
         * <p>
         * The business rules are:
         * <ul>
         *   <li>the Quantity must be 1 or greater</li>
         * </ul>
         * This will also recompute the subTotal value.
         *
         * @param quantity the value to set into the Quantity field
         * @throws IllegalArgumentException if the Quantity is invalid
         */
        public void setQuantity(final int quantity)
        {
            LOG.debug("setting the Quantity: " + quantity);
            final int min = 1;

            if (quantity < min)
            {
                LOG.error("Quantity must be greater then zero");
                throw new IllegalArgumentException("Quantity must be greater then zero");
            }
            this.myQuantity = quantity;
            computeSubTotal();
        }

        /**
         * Returns the SubTotal value for the OrderItem.
         *
         * The SunTotal will be recomputed any time the UnitPrice or Quantity changes.
         *
         * @return the SubTotal value for the OrderItem
         */
        public double getSubTotal()
        {
            LOG.debug("returning the SubTotal: " + mySubTotal);
            return mySubTotal;
        }

        /**
         * The hashCode() method of the OrderItem class.
         * <p>
         * <strong>This method uses:</strong>
         * <ul>
         *  <li>id</li>
         *  <li>order id</li>
         *  <li>product id</li>
         *  <li>unit price</li>
         *  <li>quantity</li>
         * </ul>
         *
         * @see java.lang.Object#hashCode()
         * @return the hashCode value for this Order object
         */
        @Override
        public int hashCode()
        {
            LOG.debug("building HashCode");
            return new HashCodeBuilder()
                    .append(getId())
                    .append(myOrderId)
                    .append(myProductId)
                    .append(myUnitPrice)
                    .append(myQuantity)
                    .toHashCode();
        }

        /**
         * The equals() method of the OrderItem class.
         * <p>
         * <strong>This method uses:</strong>
         * <ul>
         *  <li>id</li>
         *  <li>order id</li>
         *  <li>product id</li>
         *  <li>unit price</li>
         *  <li>quantity</li>
         * </ul>
         *
         * @see java.lang.Object#equals(Object obj)
         * @param obj the incoming object to compare against
         * @return true if the fields being compared are equal
         */
        @Override
        public boolean equals(final Object obj)
        {
            LOG.debug("checking equals");
            if (obj instanceof OrderItem)
            {
                final OrderItem other = (OrderItem) obj;
                return new EqualsBuilder()
                        .append(getId(), other.getId())
                        .append(myOrderId, other.myOrderId)
                        .append(myProductId, other.myProductId)
                        .append(myUnitPrice, other.myUnitPrice)
                        .append(myQuantity, other.myQuantity)
                        .isEquals();
            }
            else
            {
                return false;
            }
        }

        /**
         * The toString method for the OrderItem class.
         *
         * this method will return:<br>
         * OrderItem [Id=xxx", OrderId=xxx, ProductId=xxx,
                   UnitPrice=xxx, Quantity=xxx, SubTotal=xxx]
         */
        @Override
        public String toString()
        {
            return "OrderItem [Id=" + getId() + ", OrderId=" + myOrderId
                    + ", ProductId=" + myProductId
                    + ", UnitPrice=" + myUnitPrice + ", Quantity="
                    + myQuantity + ", SubTotal=" + mySubTotal + "]";
        }

    }