예제 #1
0
        /// <summary>
        /// Reset the negotiation to a "in negotiation" state.
        /// </summary>
        /// <param name="consumerTrustNegotiations">The the negotiations to reset.</param>
        internal static void Reject(ConsumerTrustNegotiationInfo[] consumerTrustNegotiations)
        {
            // An instance of the shared data model is required to use its methods.
            DataModel dataModel = new DataModel();

            // The business logic requires the current time and the user identifier for auditing.
            Guid     createUserId   = TradingSupport.UserId;
            DateTime createDateTime = DateTime.UtcNow;
            DateTime modifiedTime   = createDateTime;
            Guid     modifiedUserId = createUserId;


            // This Web Method comes with an implicit transaction that is linked to its execution.
            DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

            // This method can handle a batch of updates in a single transaction.
            foreach (ConsumerTrustNegotiationInfo consumerTrustNegotiationInfo in consumerTrustNegotiations)
            {
                List <ConsumerTrustNegotiationPaymentMethodTypeInfo> counterItems = new List <ConsumerTrustNegotiationPaymentMethodTypeInfo>();

                // The blotter is not passed in from the client but is used
                Guid   blotterId = Guid.Empty;
                Status negotiationStatus;
                TrustNegotiationInfo trustNegotiationInfo = null;
                // This is the next negotiation in the batch to be updated.
                ConsumerTrustNegotiationRow consumerTrustNegotiationRow =
                    DataModel.ConsumerTrustNegotiation.ConsumerTrustNegotiationKey.Find(consumerTrustNegotiationInfo.ConsumerTrustNegotiationId);

                try
                {
                    // Lock the current negotation record for reading.  The data model doesn't support reader lock promotion, so the programming model is to
                    // lock the database, collect the data, release the locks and then write.  This model is especially important when iterating through a
                    // large batch to prevent the number of locks from growing to large.
                    consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // The blotter identifier is used for access control and is not passed in by the client.
                    blotterId            = consumerTrustNegotiationRow.BlotterId;
                    negotiationStatus    = StatusMap.FromId(consumerTrustNegotiationRow.StatusId);
                    trustNegotiationInfo = new TrustNegotiationInfo(consumerTrustNegotiationRow);

                    // Determine whether the client has the right to modify this record.
                    if (!TradingSupport.HasAccess(dataModelTransaction, blotterId, AccessRight.Write))
                    {
                        throw new FaultException <FluidTrade.Core.SecurityFault>(new SecurityFault("You do not have write access to the selected object."));
                    }

                    // The payment methods are maintained as a vector associated with the negotiation record.  This will lock each of the records and read the
                    // payment methods into a data structure so the locks don't need to be held when it is time to write
                    foreach (var consumerTrustNegotiationOfferPaymentMethodRow
                             in consumerTrustNegotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows())
                    {
                        try
                        {
                            // Temporarily lock the record containing the payment method.
                            consumerTrustNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);


                            // This list is used to delete the payment methods that are no longer part of this negotiation.
                            counterItems.Add(
                                new ConsumerTrustNegotiationPaymentMethodTypeInfo(
                                    consumerTrustNegotiationOfferPaymentMethodRow.PaymentMethodTypeId,
                                    consumerTrustNegotiationOfferPaymentMethodRow.ConsumerTrustNegotiationCounterPaymentMethodId,
                                    consumerTrustNegotiationOfferPaymentMethodRow.RowVersion));
                        }
                        finally
                        {
                            // At this point the payment method isn't needed.
                            consumerTrustNegotiationOfferPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }

                    MatchRow matchRow = DataModel.Match.MatchKey.Find(trustNegotiationInfo.MatchId);
                    try
                    {
                        matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        trustNegotiationInfo.MatchRowVersion = matchRow.RowVersion;
                        trustNegotiationInfo.ContraMatchId   = matchRow.ContraMatchId;
                    }
                    finally
                    {
                        matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(trustNegotiationInfo.ContraMatchId);
                    try
                    {
                        contraMatchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        trustNegotiationInfo.ContraMatchRowVersion = contraMatchRow.RowVersion;
                    }
                    finally
                    {
                        contraMatchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }
                }
                finally
                {
                    // At this point, the negotiation record isn't needed.  It is critical to release the reader locks before attempting a write.
                    consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }


                // At this point, all the data for this operation has been collected and the CRUD operations can be invoked to finish the update.  Note that
                // the counter party information is not modified here, but is done through the Chinese wall.
                Guid newNegotiationId = Guid.NewGuid();
                dataModel.CreateConsumerTrustNegotiation(
                    trustNegotiationInfo.AccountBalance,
                    trustNegotiationInfo.BlotterId,
                    newNegotiationId,
                    trustNegotiationInfo.CounterPaymentLength,
                    trustNegotiationInfo.CounterPaymentStartDateLength,
                    trustNegotiationInfo.CounterPaymentStartDateUnitId,
                    trustNegotiationInfo.CounterSettlementUnitId,
                    trustNegotiationInfo.CounterSettlementValue,
                    createDateTime,
                    createUserId,
                    trustNegotiationInfo.CreditCardId,
                    trustNegotiationInfo.IsRead,
                    trustNegotiationInfo.IsReply,
                    trustNegotiationInfo.MatchId,
                    modifiedTime,
                    modifiedUserId,
                    consumerTrustNegotiationInfo.PaymentLength,
                    consumerTrustNegotiationInfo.PaymentStartDateLength,
                    consumerTrustNegotiationInfo.PaymentStartDateUnitId,
                    consumerTrustNegotiationInfo.SettlementUnitId,
                    consumerTrustNegotiationInfo.SettlementValue,
                    StatusMap.FromCode(Status.Rejected),
                    out trustNegotiationInfo.Version);

                // This will add the payment methods to the negotiation that are not already there.
                foreach (Guid paymentMethodTypeId in consumerTrustNegotiationInfo.PaymentMethodTypes)
                {
                    dataModel.CreateConsumerTrustNegotiationOfferPaymentMethod(
                        blotterId,
                        newNegotiationId,
                        Guid.NewGuid(),
                        paymentMethodTypeId);
                }

                foreach (ConsumerTrustNegotiationPaymentMethodTypeInfo consumerTrustNegotiationPaymentMethodTypeInfo in counterItems)
                {
                    dataModel.UpdateConsumerTrustNegotiationCounterPaymentMethod(
                        blotterId,
                        null,
                        new Object[] { consumerTrustNegotiationPaymentMethodTypeInfo.ConsumerTrustNegotiationOfferPaymentMethodId },
                        newNegotiationId,
                        consumerTrustNegotiationPaymentMethodTypeInfo.PaymentMethodInfoId,
                        consumerTrustNegotiationPaymentMethodTypeInfo.RowVersion);
                }

                //Reset the Match Status Id.  This is required so the match engine will redo the match.  The
                //match engine does not recalculate if it is not in the initial three stages of - Valid, Partial, ValidwithFunds
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new object[] { trustNegotiationInfo.MatchId },
                    trustNegotiationInfo.MatchRowVersion,
                    StatusMap.FromCode(Status.ValidMatch),
                    null);

                //Reset the Contra Match Status Id
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new object[] { trustNegotiationInfo.ContraMatchId },
                    trustNegotiationInfo.ContraMatchRowVersion,
                    StatusMap.FromCode(Status.ValidMatch),
                    null);
            }
        }
예제 #2
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;
            }
        }