/// <summary>
        /// Updates the specified <paramref name="orderLine"/> based on business rules
        /// </summary>
        /// <param name="orderLine">The <see cref="T:GIIS.DataLayer.TransferOrderDetail"/> line to be updated</param>
        /// <returns>The <see cref="T:GIIS.DataLayer.TransferOrderDetail"/> which was updated</returns>
        /// <remarks>
        /// <list type="ordered">
        /// <item><description>	Load the current order line for the database using the order line #</description></item>
        /// <item><description>	Instantiate an instance of StockManagementLogic BLL class.</description></item>
        /// <item><description>	If the status of the current order line is:
        ///     <list type="table">
        ///         <listHeader>
        ///             <term>State</term>
        ///             <description>Actions</description>
        ///         </listHeader>
        ///         <item>
        ///             <term>Requested</term>
        ///             <description>
        ///                 <list type="ordered">
        ///                     <item><description>[Guard Condition] Ensure the new state is either “Cancelled”, “Requested” or “Released” otherwise throw an invalid state transition exception</description></item>
        ///                     <item><description>Update the quantity and status of the  order detail item</description></item>
        ///                     <item><description>If the new state is “Released” then call the Allocate function of the StockManagementLogic instance to allocate the specified order detail.</description></item>
        ///                     <item><description>Save the order detail</description></item>
        ///                 </list>
        ///             </description>
        ///         </item>
        ///         <item>
        ///             <term>Released</term>
        ///             <description>
        ///                 <list type="ordered">
        ///                     <item><description>[Guard Condition] Ensure the new state is either “Cancelled”, “Released” or “Packed” otherwise thrown an invalid state transition exception</description></item>
        ///                     <item><description>If the current state is “Released” then
        ///                         <list type="ordered">
        ///                             <item><description>Calculate the difference in quantity from the “old” record and “new” record</description></item>
        ///                             <item><description>Call the Allocate method of the StockManagementLogic instance to perform the additional allocation/de-allocation.</description></item>
        ///                         </list>
        ///                     </description></item>
        ///                     <item><description>	Update the quantity and status of the order detail item.</description></item>
        ///                     <item><description>If the new state is “Cancelled” then call the Allocate method of the StockManagementLogic instance to perform the de-allocation of the item.</description></item>
        ///                     <item><description>Save the order detail</description></item>
        ///                 </list>
        ///             </description>
        ///         </item>
        ///         <item>
        ///             <term>Packed</term>
        ///             <description>
        ///                 <list type="ordered">
        ///                     <item><description>[Guard Condition] Ensure the new state is either “Cancelled”, “Packed” or “Shipped”</description></item>
        ///                     <item><description>Update the quantity and status of the order detail item.</description></item>
        ///                     <item><description>If the new state is “cancelled” then call the Allocate method of the StockManagementLogic instance to perform the de-allocation of the item.</description></item>
        ///                     <item><description>If the new state is “Shipped” then
        ///                         <list type="ordered">
        ///                             <item><description>Call the allocate method of the StockManagementLogic instance to perform the de-allocation of the line item.</description></item>
        ///                             <item><description>Call the Transfer method of the StockManagementLogic instance to perform the transfer transactions between the source and target facilities.</description></item>
        ///                         </list>
        ///                     </description></item>
        ///                     <item><description>Save the order detail</description></item>
        ///                 </list>
        ///             </description>
        ///         </item>
        ///         <item>
        ///             <term>Shipped</term>
        ///             <description>Throw an invalid operation exception as shipped orders (and their lines) cannot be edited</description>
        ///         </item>
        ///         <item>
        ///             <term>Cancelled</term>
        ///             <description>Throw an invalid operation exception as cancelled orders (and their lines) cannot be edited</description>
        ///         </item>
        ///     </list>
        /// </description></item>
        /// </list>
        /// </remarks>
        public TransferOrderDetail UpdateOrderLine(TransferOrderDetail orderLine, Int32 modifiedBy)
        {
            if (orderLine == null)
            {
                throw new ArgumentNullException("orderLine");
            }
            else if (orderLine.OrderDetailNum == default(Int32))
            {
                throw new ArgumentException("Order line is not saved", "orderLine");
            }

            // Load the current order line from the database
            TransferOrderDetail currentOrderLine   = TransferOrderDetail.GetTransferOrderDetailByOrderDetailNum(orderLine.OrderDetailNum);
            TransferOrderHeader currentOrderHeader = TransferOrderHeader.GetTransferOrderHeaderByOrderNum(orderLine.OrderNum);

            // Can't change the GTIN with this function
            if (orderLine.OrderGtin != currentOrderLine.OrderGtin)
            {
                throw new InvalidOperationException("Cannot change the GTIN with this function. Remove the order line first and add another order-line with the new GTIN");
            }

            // New order lot number is null?  We need to get oldest lot
            if (String.IsNullOrEmpty(orderLine.OrderGtinLotnum) || orderLine.OrderGtinLotnum == "*")
            {
                ItemLot itemLot = GetOldestLot(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin); //currentOrderLine.OrderGtinLotnum;
                if (itemLot != null)
                {
                    orderLine.OrderGtinLotnum = itemLot.LotNumber;
                }
            }

            StockManagementLogic stockLogic = new StockManagementLogic();

            // Apply rules
            switch ((OrderStatusType)currentOrderLine.OrderDetailStatus)
            {
            case OrderStatusType.Requested:
                // State transitions
                if (orderLine.OrderDetailStatus != (int)OrderStatusType.Cancelled &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Released &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Requested)
                {
                    throw new IllegalStateException((OrderStatusType)orderLine.OrderDetailStatus, "TransferOrderDetail", "UpdateOrderLine");
                }

                // Allocate the data if this is a transition
                if (orderLine.OrderDetailStatus == (int)OrderStatusType.Released)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, (int)orderLine.OrderQty, orderLine, modifiedBy);
                }

                break;

            case OrderStatusType.Released:

                // Guard conditions
                if (orderLine.OrderDetailStatus != (int)OrderStatusType.Cancelled &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Released &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Packed)
                {
                    throw new IllegalStateException((OrderStatusType)orderLine.OrderDetailStatus, "TransferOrderDetail", "UpdateOrderLine");
                }

                // We need to adjust the allocations?
                if (currentOrderLine.OrderQty != orderLine.OrderQty)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, (int)(orderLine.OrderQty - currentOrderLine.OrderQty), orderLine, modifiedBy);
                }

                // Released -> Cancelled = Deallocate
                if (orderLine.OrderDetailStatus == (int)OrderStatusType.Cancelled)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, -(int)orderLine.OrderQty, orderLine, modifiedBy);
                }

                break;

            case OrderStatusType.Packed:
                // Guard conditions
                if (orderLine.OrderDetailStatus != (int)OrderStatusType.Cancelled &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Packed &&
                    orderLine.OrderDetailStatus != (int)OrderStatusType.Shipped)
                {
                    throw new IllegalStateException((OrderStatusType)orderLine.OrderDetailStatus, "TransferOrderDetail", "UpdateOrderLine");
                }

                // We need to adjust the allocations?
                if (currentOrderLine.OrderQty != orderLine.OrderQty)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, (int)(orderLine.OrderQty - currentOrderLine.OrderQty), orderLine, modifiedBy);
                }

                // Packed -> Cancelled = Deallocate
                if (orderLine.OrderDetailStatus == (int)OrderStatusType.Cancelled)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, -(int)orderLine.OrderQty, orderLine, modifiedBy);
                }
                // Packed -> Shipped = Deallocate then Transfer
                else if (orderLine.OrderDetailStatus == (int)OrderStatusType.Shipped)
                {
                    stockLogic.Allocate(currentOrderHeader.OrderFacilityFromObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, -(int)orderLine.OrderQty, orderLine, modifiedBy);
                    stockLogic.Transfer(currentOrderHeader.OrderFacilityFromObject, currentOrderHeader.OrderFacilityToObject, orderLine.OrderGtin, orderLine.OrderGtinLotnum, orderLine, (int)orderLine.OrderQty, modifiedBy);
                }

                break;

            case OrderStatusType.Shipped:
                throw new InvalidOperationException("Shipped orders cannot be modified " + orderLine.OrderDetailNum.ToString());

            case OrderStatusType.Cancelled:
                throw new InvalidOperationException("Cancelled orders cannot be modified");
            }

            // Update
            orderLine.ModifiedBy = modifiedBy;
            orderLine.ModifiedOn = DateTime.Now;
            TransferOrderDetail.Update(orderLine);

            // Return the order line
            return(orderLine);
        }
        /// <summary>
        /// Add an order line to the order defined by <paramref name="order"/>
        /// </summary>
        /// <param name="order">The order to which the line should be added</param>
        /// <param name="gtin">The global trade identification number of the item in the line</param>
        /// <param name="lot">(Optional) The lot number to be used. Note if null is passed in <paramref name="lot"/> then the oldest lot is used first</param>
        /// <param name="qty">The quantity of the item to be added to the order</param>
        /// <param name="uom">(Optional) The base unit of measure. If <paramref name="uom"/> is null then the default UOM for the item described by <paramref name="gtin"/> is used</param>
        /// <returns>The constructed and saved <see cref="T:GIIS.DataLayer.TransferOrderDetail"/></returns>
        /// <remarks>
        /// The add order line function is responsible for adding a new order line to the order detail. This function operates in the following manner:
        /// <list type="ordered">
        /// <item>
        ///     <description>[Guard Condition] If the order passed into the function IS in the “Packed” or “Shipped” state then throw an invalid state exception (sanity check)</description>
        /// </item>
        /// <item>
        ///     <description>Lookup the item by the GTIN provided in the function call.</description>
        /// </item>
        /// <item>
        ///     <description>[Guard Condition] If the lot number is provided, and the lot number is not a valid lot number for the item provided then throw an error code</description>
        /// </item>
        /// <item>
        ///     <description>If the current status of the order to which the detail is to be attached is “Released” then
        ///         <list type="ordered">
        ///             <item>
        ///                 <description>Instantiate a StockManagementLogic BLL class</description>
        ///             </item>
        ///             <item>Allocate the stock using the Allocate method</item>
        ///         </list>
        ///     </description>
        /// </item>
        /// <item>
        ///     <description>Set the unit of measure, quantity, gtin, etc. fields of the TransferOrderDetail instance to the parameters and fields derived from loaded Item.</description>
        /// </item>
        /// <item>
        ///     <description>Save the order line.</description>
        /// </item>
        ///</list>
        /// </remarks>
        public TransferOrderDetail AddOrderLine(TransferOrderHeader order, String gtin, String lot, Int32 qty, Uom uom, Int32 modifiedBy)
        {
            if (order == null)
            {
                throw new ArgumentNullException("order");
            }
            if (String.IsNullOrEmpty(gtin))
            {
                throw new ArgumentNullException("gtin");
            }

            // Sanity check
            if (order.OrderStatus == (int)OrderStatusType.Shipped ||
                order.OrderStatus == (int)OrderStatusType.Cancelled)
            {
                throw new IllegalStateException((OrderStatusType)order.OrderStatus, "TransferOrderHeader", "AddOrderLine");
            }

            // Lookup item by GTIN and optionally lot
            ItemLot item = null;

            if (!String.IsNullOrEmpty(lot))
            {
                item = ItemLot.GetItemLotByGtinAndLotNo(gtin, lot);
            }
            if (item == null)
            {               // not found - We get the item by lot
                item = ItemLot.GetItemLotByGtin(gtin);
                lot  = "*"; // null;
            }

            // Item still null?
            if (item == null)
            {
                throw new InvalidOperationException(String.Format("Cannot locate item with GTIN {0}", gtin));
            }

            // Construct the order detail
            TransferOrderDetail retVal = new TransferOrderDetail()
            {
                ModifiedBy             = modifiedBy,
                ModifiedOn             = DateTime.Now,
                OrderCustomItem        = false,
                OrderDetailDescription = item.ItemObject.Name,
                OrderDetailStatus      = order.OrderStatus,
                OrderGtin         = gtin,
                OrderGtinLotnum   = lot,
                OrderNum          = order.OrderNum,
                OrderQty          = qty,
                OrderQtyInBaseUom = qty,
                OrderUom          = uom.Name
            };

            // HACK: Overcome lack of transaction processing we have to be careful about how we do this
            ItemTransaction allocateTransaction = null;

            // Current state of order is released? We need to allocate this line item
            if (order.OrderStatus == (int)OrderStatusType.Released)
            {
                StockManagementLogic stockLogic = new StockManagementLogic();
                // We need to release this order ... If the lot was null we'll use the oldest lot number
                if (String.IsNullOrEmpty(lot))
                {
                    item = this.GetOldestLot(order.OrderFacilityFromObject, gtin);
                }

                // Allocation of specified lot
                allocateTransaction = stockLogic.Allocate(order.OrderFacilityFromObject, gtin, item.LotNumber, qty, null, modifiedBy);

                // Update order
                retVal.OrderGtinLotnum = item.LotNumber;
            }

            // Save
            retVal.OrderDetailNum = TransferOrderDetail.Insert(retVal);

            // HACK: Update the allocate transaction. This would be cleaned up with a transaction to back out changes (basically do the order detail then allocate)
            if (allocateTransaction != null)
            {
                allocateTransaction.RefId    = retVal.OrderNum.ToString();
                allocateTransaction.RefIdNum = retVal.OrderDetailNum;
                ItemTransaction.Update(allocateTransaction);
            }

            return(retVal);
        }