/// <summary> /// Reset the negotiation to a "in negotiation" state. /// </summary> /// <param name="consumerDebtNegotiations">The the negotiations to reset.</param> internal static void Reject(ConsumerDebtNegotiationInfo[] consumerDebtNegotiations) { // 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 (ConsumerDebtNegotiationInfo consumerDebtNegotiationInfo in consumerDebtNegotiations) { // The blotter is not passed in from the client but is used Guid blotterId = Guid.Empty; Status negotiationStatus; DebtNegotiationInfo debtNegotiationInfo = null; // This is the next negotiation in the batch to be updated. ConsumerDebtNegotiationRow consumerDebtNegotiationRow = DataModel.ConsumerDebtNegotiation.ConsumerDebtNegotiationKey.Find(consumerDebtNegotiationInfo.ConsumerDebtNegotiationId); // 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 <ConsumerDebtNegotiationPaymentMethodTypeInfo> counterItems = new List <ConsumerDebtNegotiationPaymentMethodTypeInfo>(); 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. consumerDebtNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); // The blotter identifier is used for access control and is not passed in by the client. blotterId = consumerDebtNegotiationRow.BlotterId; debtNegotiationInfo = new DebtNegotiationInfo(consumerDebtNegotiationRow); negotiationStatus = StatusMap.FromId(consumerDebtNegotiationRow.StatusId); // 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.")); } MatchRow matchRow = DataModel.Match.MatchKey.Find(debtNegotiationInfo.MatchId); try { matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); debtNegotiationInfo.MatchRowVersion = matchRow.RowVersion; debtNegotiationInfo.ContraMatchId = matchRow.ContraMatchId; } finally { matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(debtNegotiationInfo.ContraMatchId); try { contraMatchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); debtNegotiationInfo.ContraMatchRowVersion = contraMatchRow.RowVersion; } finally { contraMatchRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // 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 consumerDebtNegotiationOfferPaymentMethodRow in consumerDebtNegotiationRow.GetConsumerDebtNegotiationCounterPaymentMethodRows()) { try { // Temporarily lock the record containing the payment method. consumerDebtNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); // This will construct a mask of items that are already part of this negotiation. The mask is used to prevent an item from being // added if it's already there. // This list is used to delete the payment methods that are no longer part of this negotiation. counterItems.Add( new ConsumerDebtNegotiationPaymentMethodTypeInfo( consumerDebtNegotiationOfferPaymentMethodRow.PaymentMethodTypeId, consumerDebtNegotiationOfferPaymentMethodRow.ConsumerDebtNegotiationCounterPaymentMethodId, consumerDebtNegotiationOfferPaymentMethodRow.RowVersion)); } finally { // At this point the payment method isn't needed. consumerDebtNegotiationOfferPaymentMethodRow.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. consumerDebtNegotiationRow.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 newConsureDebtNegotiationId = Guid.NewGuid(); dataModel.CreateConsumerDebtNegotiation( debtNegotiationInfo.AccountBalance, debtNegotiationInfo.BlotterId, newConsureDebtNegotiationId, debtNegotiationInfo.CounterPaymentLength, debtNegotiationInfo.CounterPaymentStartDateLength, debtNegotiationInfo.CounterPaymentStartDateUnitId, debtNegotiationInfo.CounterSettlementUnitId, debtNegotiationInfo.CounterSettlementValue, modifiedTime, modifiedUserId, debtNegotiationInfo.IsRead, debtNegotiationInfo.IsReply, debtNegotiationInfo.MatchId, modifiedTime, modifiedUserId, consumerDebtNegotiationInfo.PaymentLength, consumerDebtNegotiationInfo.PaymentStartDateLength, consumerDebtNegotiationInfo.PaymentStartDateUnitId, consumerDebtNegotiationInfo.SettlementUnitId, consumerDebtNegotiationInfo.SettlementValue, StatusMap.FromCode(Status.Rejected), out debtNegotiationInfo.Version); // This will add the payment methods to the negotiation that are not already there. foreach (Guid paymentMethodTypeId in consumerDebtNegotiationInfo.PaymentMethodTypes) { dataModel.CreateConsumerDebtNegotiationOfferPaymentMethod( blotterId, newConsureDebtNegotiationId, Guid.NewGuid(), paymentMethodTypeId); } //This will delete those payment methods that are no longer part of the negotiation. foreach (ConsumerDebtNegotiationPaymentMethodTypeInfo consumerDebtNegotiationPaymentMethodTypeInfo in counterItems) { dataModel.UpdateConsumerDebtNegotiationCounterPaymentMethod(blotterId, null, new Object[] { consumerDebtNegotiationPaymentMethodTypeInfo.ConsumerDebtNegotiationOfferPaymentMethodId }, newConsureDebtNegotiationId, null, consumerDebtNegotiationPaymentMethodTypeInfo.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[] { debtNegotiationInfo.MatchId }, debtNegotiationInfo.MatchRowVersion, StatusMap.FromCode(Status.ValidMatch), null); //Reset the Contra Match Status Id dataModel.UpdateMatch( null, null, null, null, null, null, null, new object[] { debtNegotiationInfo.ContraMatchId }, debtNegotiationInfo.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; ConsumerDebtNegotiationRow consumerDebtNegotiationRow = null; foreach (ConsumerDebtNegotiationRow versionRow in matchRow.GetConsumerDebtNegotiationRows()) { if (versionRow.Version > maxVersion) { maxVersion = versionRow.Version; consumerDebtNegotiationRow = versionRow; } } // At this point the latest version of the negotiations has been found. Extract the scalar items used in the negotiation of a settlement. this.NegotiationItem = new NegotiationItem(consumerDebtNegotiationRow); // The Offer Payment Methods are a vector and need to be copied iteratively. foreach (ConsumerDebtNegotiationOfferPaymentMethodRow paymentMethod in consumerDebtNegotiationRow.GetConsumerDebtNegotiationOfferPaymentMethodRows()) { this.OfferPaymentMethods.Add(paymentMethod.PaymentMethodTypeId); } // The Conter Offer Payment methods are also a vector. foreach (ConsumerDebtNegotiationCounterPaymentMethodRow paymentMethod in consumerDebtNegotiationRow.GetConsumerDebtNegotiationCounterPaymentMethodRows()) { 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); } } } }