/// <summary> /// Update a Consumer Trust Negotiation Record. /// </summary> internal static void Update(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) { // The payment methods available to this negotiation is a vector. Rather than delete everything and re-add it anytime an update is made, a // list of changes is constructed: new payment methods are added, obsolete payment methods are deleted and the ones that haven't changed are // left alone. These list help to work out the differences. List <ConsumerTrustNegotiationPaymentMethodTypeInfo> counterItems = new List <ConsumerTrustNegotiationPaymentMethodTypeInfo>(); // The blotter is not passed in from the client but is used Guid blotterId = Guid.Empty; TrustNegotiationInfo trustNegotiationInfo = null; // This is the next negotiation in the batch to be updated. ConsumerTrustNegotiationRow consumerTrustNegotiationRow = DataModel.ConsumerTrustNegotiation.ConsumerTrustNegotiationKey.Find(consumerTrustNegotiationInfo.ConsumerTrustNegotiationId); Guid matchId = Guid.Empty; Int64 originalVersion = Int64.MinValue; // 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); try { matchId = consumerTrustNegotiationRow.MatchId; originalVersion = consumerTrustNegotiationRow.Version; } finally { consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId); consumerTrustNegotiationRow = null; } //Determine the most recent Negotiation to grab the counter payment methods. Int64 maxVersion = Int64.MinValue; MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId); matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { foreach (ConsumerTrustNegotiationRow versionRow in matchRow.GetConsumerTrustNegotiationRows()) { try { versionRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); if (versionRow.Version > maxVersion) { maxVersion = versionRow.Version; consumerTrustNegotiationRow = versionRow; } } finally { versionRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } } finally { matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { //Check for rowversion if (originalVersion != consumerTrustNegotiationRow.Version) { throw new global::System.ServiceModel.FaultException <FluidTrade.Core.OptimisticConcurrencyFault>( new global::FluidTrade.Core.OptimisticConcurrencyFault("ConsumerTrustNegotiation", new object[] { consumerTrustNegotiationInfo.ConsumerTrustNegotiationId }), new FaultReason("Negotiation is busy. Please try again!")); } // The blotter identifier is used for access control and is not passed in by the client. blotterId = consumerTrustNegotiationRow.BlotterId; 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); } } } 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, consumerTrustNegotiationInfo.StatusId, 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); } //Since we cannot create new counter payments, we will update the existing ones. foreach (ConsumerTrustNegotiationPaymentMethodTypeInfo consumerTrustNegotiationPaymentMethodTypeInfo in counterItems) { dataModel.UpdateConsumerTrustNegotiationCounterPaymentMethod( blotterId, null, new Object[] { consumerTrustNegotiationPaymentMethodTypeInfo.ConsumerTrustNegotiationOfferPaymentMethodId }, newNegotiationId, consumerTrustNegotiationPaymentMethodTypeInfo.PaymentMethodInfoId, consumerTrustNegotiationPaymentMethodTypeInfo.RowVersion); } } }
/// <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); } }
/// <summary> /// Creates a new SettlementInfo instance. /// </summary> public SettlementItem(Guid matchId) { // Initialize the object. this.ChatItemList = new List <ChatItem>(); this.CounterPaymentMethods = new List <Guid>(); this.OfferPaymentMethods = new List <Guid>(); // The data model must be locked in order to navigate the data. The main idea here is to find the chat items and the negotiation elements // associated with this match and send that data to the foreground where it can be displayed. lock (DataModel.SyncRoot) { // This dialog will only handle matches that have this identifier. MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId); if (matchRow == null) { this.Status = Status.Deleted; } else { // The status code drives the state of many of the controls in the console. this.Status = matchRow.StatusRow.StatusCode; // The negotiation table has a historical component. Ever time a change is made to the negotiation on either side a completely new record // is created to record the change. While the earlier versions are useful for a historical context and for reports, this console is only // interested in the current version of the negotiations. Int64 maxVersion = Int64.MinValue; ConsumerTrustNegotiationRow consumerTrustNegotiationRow = null; foreach (ConsumerTrustNegotiationRow versionRow in matchRow.GetConsumerTrustNegotiationRows()) { if (versionRow.Version > maxVersion) { maxVersion = versionRow.Version; consumerTrustNegotiationRow = versionRow; } } // Extract the scalar items used in the negotiation of a settlement. this.NegotiationItem = new NegotiationItem(consumerTrustNegotiationRow); // The Offer Payment Methods are a vector and need to be copied iteratively. foreach (ConsumerTrustNegotiationOfferPaymentMethodRow paymentMethod in consumerTrustNegotiationRow.GetConsumerTrustNegotiationOfferPaymentMethodRows()) { this.OfferPaymentMethods.Add(paymentMethod.PaymentMethodTypeId); } // The Conter Offer Payment methods are also a vector. foreach (ConsumerTrustNegotiationCounterPaymentMethodRow paymentMethod in consumerTrustNegotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows()) { this.CounterPaymentMethods.Add(paymentMethod.PaymentMethodTypeId); } // When the console is initialized it is populated with every dialog item that has occurred for this match. foreach (ChatRow chatRow in matchRow.GetChatRows()) { ChatItem chatItem = new ChatItem(); chatItem.CreatedTime = chatRow.CreatedTime; chatItem.IsReply = chatRow.IsReply; chatItem.MatchId = matchId; chatItem.Message = chatRow.Message; this.ChatItemList.Add(chatItem); } } } }