Exemplo n.º 1
0
        /// <summary>
        /// Changes the state of the Working Order to reflect a filledly filled state.
        /// </summary>
        private static void OnFilledAction(Object[] key, params Object[] parameters)
        {
            // A middle tier context is also required for a transacted update.
            DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

            // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was
            // created.  This is not an error condition.  If there is no Working Order to update, then the operation is just terminated prematurely.
            WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key);

            if (workingOrderRow == null)
            {
                return;
            }
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // The error status on a Working Order cannot be cleared with a fill.
            if (workingOrderRow.StatusId != StatusMap.FromCode(Status.Error))
            {
                // The Working Order is 'Filled' when the quantity executed is the same as the quantity ordered.
                Decimal quantityOrdered  = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                Decimal quantityExecuted = WorkingOrder.GetExecutionQuantity(dataModelTransaction, workingOrderRow);
                if (quantityOrdered == quantityExecuted)
                {
                    UpdateWorkingOrderStatus(workingOrderRow, Status.Filled);
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Changes the state of the Working Order to reflect a filledly filled state.
        /// </summary>
        private static void ClearErrorAction(Object[] key, params Object[] parameters)
        {
            // A middle tier context is also required for a transacted update.
            DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

            // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was
            // created.  This is not an error condition.  If there is no Working Order to update, then the operation is just terminated prematurely.
            WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key);

            if (workingOrderRow == null)
            {
                return;
            }
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            dataModelTransaction.AddLock(workingOrderRow);
            if (workingOrderRow.RowState == DataRowState.Detached)
            {
                return;
            }

            // The 'Error' status is only cleared when all the Destination Orders are valid.
            Boolean isErrorStatus = false;

            foreach (DestinationOrderRow siblingOrderRow in workingOrderRow.GetDestinationOrderRows())
            {
                siblingOrderRow.AcquireReaderLock(dataModelTransaction);
                if (siblingOrderRow.StatusId == StatusMap.FromCode(Status.Error))
                {
                    isErrorStatus = true;
                    break;
                }
            }

            // The proper Working Order status must be evaluated when the error status is cleared.
            if (!isErrorStatus)
            {
                // The aggregates will determine the new state of the Working Order.
                Decimal quantityExecuted = WorkingOrder.GetExecutionQuantity(dataModelTransaction, workingOrderRow);
                Decimal quantityOrdered  = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);

                // This restores the 'New' status when the canceled Destination Order was the only order with any fills.
                if (quantityExecuted == 0.0M && workingOrderRow.StatusId != StatusMap.FromCode(Status.New))
                {
                    UpdateWorkingOrderStatus(workingOrderRow, Status.New);
                }

                // This restores the 'Partially Filled' status when other executions remain.
                if (0.0M < quantityExecuted && quantityExecuted < quantityOrdered && workingOrderRow.StatusId != StatusMap.FromCode(Status.PartiallyFilled))
                {
                    UpdateWorkingOrderStatus(workingOrderRow, Status.PartiallyFilled);
                }

                // This restores the 'Filled' status when the quantity executed is the same as the quantity ordered.
                if (quantityExecuted == quantityOrdered && workingOrderRow.StatusId != StatusMap.FromCode(Status.Filled))
                {
                    UpdateWorkingOrderStatus(workingOrderRow, Status.Filled);
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Handler for validating Source Order records.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        internal static void OnSourceOrderRowValidate(object sender, SourceOrderRowChangeEventArgs e)
        {
            Decimal currentQuantity;
            Decimal destinationOrderQuantity;
            DataModelTransaction dataModelTransaction;
            Decimal         originalQuantity;
            Decimal         sourceOrderQuantity;
            WorkingOrderRow workingOrderRow;

            // The Business Rules will be enforced on this Source Order.  Note that it is locked at the point this handler is called.
            SourceOrderRow sourceOrderRow = e.Row;

            // The action on the row determines which rule to evaluate.
            switch (e.Action)
            {
            case DataRowAction.Change:

                // Reject the operation if the Working Order is overcommitted with a destination.  Note that the order of the evaluation is important for
                // efficiency.  That is, there is no need to sum up the Source and Destination Orders, which requires locking several records, if the Source
                // Order quantity has been incremented as there's no chance it will be over committed.
                originalQuantity = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Original];
                currentQuantity  = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Current];
                if (originalQuantity < currentQuantity)
                {
                    // A middle tier context is required to lock the rows so the quantities can be aggregated.
                    dataModelTransaction = DataModelTransaction.Current;

                    // Once its determined that the quantity has increased, the Working Order row will need to be locked to examine the aggregate values of the
                    // source and Destination Orders.
                    workingOrderRow = e.Row.WorkingOrderRow;
                    workingOrderRow.AcquireReaderLock(dataModelTransaction);

                    // This is an illegal operation if the quantity sent to a destination is greater than the quantity ordered.
                    sourceOrderQuantity      = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                    destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);
                    if (sourceOrderQuantity < destinationOrderQuantity)
                    {
                        throw new FaultException <DestinationQuantityFault>(
                                  new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
                    }
                }
                break;

            case DataRowAction.Delete:

                // A middle tier context is required to lock the rows so the quantities can be aggregated.
                dataModelTransaction = DataModelTransaction.Current;

                // The main idea of this trigger is to prevent the over commitment of a Working Order when a Source Order is deleted.  At this point, the
                // Source Order is deleted, so the original record must be used to find the parent Working Order that is effected.
                sourceOrderRow = e.Row;
                try
                {
                    DataModel.DataLock.EnterReadLock();
                    workingOrderRow = ((WorkingOrderRow)(sourceOrderRow.GetParentRow(DataModel.SourceOrder.WorkingOrderSourceOrderRelation, DataRowVersion.Original)));
                }
                finally
                {
                    DataModel.DataLock.ExitReadLock();
                }

                // Lock the working order row while some aggregate values are calculated.
                workingOrderRow.AcquireReaderLock(dataModelTransaction);

                // Reject the operation if the Working Order is overcommitted with a destination.
                sourceOrderQuantity      = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);
                if (sourceOrderQuantity < destinationOrderQuantity)
                {
                    throw new FaultException <DestinationQuantityFault>(
                              new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
                }

                break;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Handler for validating Destination Order records.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        internal static void OnDestinationOrderRowValidate(object sender, DestinationOrderRowChangeEventArgs e)
        {
            Int32   currentStatusCode;
            Decimal destinationOrderQuantity;
            DataModelTransaction dataModelTransaction;
            Int32           previousStatusCode;
            Decimal         sourceOrderQuantity;
            WorkingOrderRow workingOrderRow;

            // The Business Rules will be enforced on this Destination Order.  Note that it is locked at the point this handler is called.
            DestinationOrderRow destinationOrderRow = e.Row;

            // The action on the row determines which rule to evaluate.
            switch (destinationOrderRow.RowState)
            {
            case DataRowState.Added:

                // This rule will reject the operation if the Working Order is overcommitted with a destination.
                dataModelTransaction = DataModelTransaction.Current;

                // This rule will throw an exception if the quantity sent to a destination is greater than the quantity ordered.  The quantity ordered and
                // quantity sent can only be calcuated from the owning Working Order which must be locked in order to carry out the calculations.
                workingOrderRow = e.Row.WorkingOrderRow;
                workingOrderRow.AcquireReaderLock(dataModelTransaction);
                sourceOrderQuantity      = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);
                if (sourceOrderQuantity < destinationOrderQuantity)
                {
                    throw new FaultException <DestinationQuantityFault>(
                              new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
                }

                break;

            case DataRowState.Modified:

                // Reject the operation if the Working Order is overcommitted with a destination.  Note that the order of the evaluation is important for
                // efficiency.  There is no need to sum up the source and Destination Orders if the quantity has been reduced as there's no chance it will be
                // over committed.
                Decimal originalQuantity = (Decimal)destinationOrderRow[DataModel.DestinationOrder.OrderedQuantityColumn, DataRowVersion.Original];
                Decimal currentQuantity  = (Decimal)destinationOrderRow[DataModel.DestinationOrder.OrderedQuantityColumn, DataRowVersion.Current];
                if (originalQuantity < currentQuantity)
                {
                    // Once it's determined that the order can be overcommitted, a middle tier context is required to lock the rows so the quantities can be
                    // aggregated.
                    dataModelTransaction = DataModelTransaction.Current;

                    // This rule will throw an exception if the quantity sent to a destination is greater than the quantity ordered.  The quantity ordered and
                    // quantity sent can only be calcuated from the owning Working Order which must be locked in order to carry out the calculations.
                    workingOrderRow = e.Row.WorkingOrderRow;
                    workingOrderRow.AcquireReaderLock(dataModelTransaction);
                    sourceOrderQuantity      = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow);
                    destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow);
                    if (sourceOrderQuantity < destinationOrderQuantity)
                    {
                        throw new FaultException <DestinationQuantityFault>(
                                  new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity));
                    }
                }

                // This rule will examine the effects of a state change of the Destination Order.  The stateChangeMatrix contains delegates to methods that
                // will determine what, if any, stats change should be applied to the Working Order due to the change in state of this Destination Order.
                previousStatusCode = Convert.ToInt32(StatusMap.FromId((Guid)destinationOrderRow[DataModel.DestinationOrder.StatusIdColumn, DataRowVersion.Original]));
                currentStatusCode  = Convert.ToInt32(StatusMap.FromId((Guid)destinationOrderRow[DataModel.DestinationOrder.StatusIdColumn, DataRowVersion.Current]));
                if (previousStatusCode != currentStatusCode)
                {
                    DestinationOrder.statusChangeMatrix[previousStatusCode, currentStatusCode](new Object[] { destinationOrderRow.WorkingOrderId });
                }

                break;

            case DataRowState.Deleted:

                // This rule will examine the effects of a state change of the Destination Order.  The stateChangeMatrix contains delegates to methods that
                // will determine what, if any, stats change should be applied to the Working Order due to the change in state of this Destination Order.
                previousStatusCode = Convert.ToInt32(StatusMap.FromId((Guid)destinationOrderRow[DataModel.DestinationOrder.StatusIdColumn, DataRowVersion.Original]));
                currentStatusCode  = (Int32)Status.Deleted;
                Guid workingOrderId = (Guid)destinationOrderRow[DataModel.DestinationOrder.WorkingOrderIdColumn, DataRowVersion.Original];
                DestinationOrder.statusChangeMatrix[previousStatusCode, currentStatusCode](new Object[] { workingOrderId });

                break;
            }
        }