/// <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); }