Example #1
0
        /// <summary>
        /// Marshals the data needed refuse a chance to negotiate a trade.
        /// </summary>
        /// <param name="parameter">The thread initialization data.</param>
        private void DeclineNegotiationThread(Object parameter)
        {
            // Extract the thread parameters
            Guid matchId = (Guid)parameter;

            try
            {
                // Lock the data model while the tables are read.
                Monitor.Enter(DataModel.SyncRoot);

                // Find the Match record.
                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
            }
            finally
            {
                // Allow other threads to access the data model.
                Monitor.Exit(DataModel.SyncRoot);
            }

            // If the command batch was built successfully, then execute it.
            try
            {
                // Call the web server to rename the object on the database.  Note that this method must be called when there
                // are no locks to prevent deadlocking.  That is why it appears in it's own 'try/catch' block.
            }
            catch (Exception exception)
            {
                // Write any server generated error messages to the event log.
                EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);
            }
        }
        /// <summary>
        /// Handle the grid requesting tooltip content
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnShowToolTipHandler(object sender, ReportGridtToolTipEventArgs e)
        {
            if (e.ReportCell.ReportColumn.ColumnId == "HeatIndexColumn")
            {
                if (this.matchToolTipContent == null)
                {
                    this.matchToolTipContent = new FluidTrade.Guardian.Windows.Controls.MatchPartsUserControl();
                }

                IContent      iContent      = e.ReportCell.ReportRow.IContent;
                CreditCardRow creditCardRow = iContent.Key as CreditCardRow;

                if (creditCardRow == null)
                {
                    return;
                }

                foreach (ConsumerTrustNegotiationRow consumerTrustNegotiationRow in creditCardRow.GetConsumerTrustNegotiationRows())
                {
                    if (creditCardRow.CreditCardId == consumerTrustNegotiationRow.CreditCardId)
                    {
                        MatchRow matchRow = consumerTrustNegotiationRow.MatchRow;
                        if (matchRow != null &&
                            matchRow.IsHeatIndexDetailsNull() == false)
                        {
                            this.matchToolTipContent.SetDetails(matchRow.HeatIndexDetails);
                            e.ToolTip.Content = this.matchToolTipContent;
                        }

                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Get a match
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public override Records.Match Get(Guid id)
        {
            MatchRow row = DataModel.Match.MatchKey.Find(id);

            Records.Match record = new Records.Match();

            if (row != null)
            {
                row.AcquireReaderLock(DataModelTransaction.Current);
                record.BlotterId     = row.BlotterId;
                record.ContraMatchId = row.ContraMatchId;
                record.ContraOrderId = row.ContraOrderId;
                record.HeatIndex     = row.HeatIndex;
                if (row.IsHeatIndexDetailsNull() == false)
                {
                    record.HeatIndexDetails = row.HeatIndexDetails;
                }
                record.MatchedTime    = row.MatchedTime;
                record.RowId          = row.MatchId;
                record.RowVersion     = row.RowVersion;
                record.StatusCodeId   = row.StatusId;
                record.WorkingOrderId = row.WorkingOrderId;
                row.ReleaseLock(DataModelTransaction.Current.TransactionId);
            }
            return(record);
        }
        private void InitializeMatchReport(object state)
        {
            ReportCell reportCell = state as ReportCell;

            if (reportCell != null)
            {
                try
                {
                    lock (DataModel.SyncRoot)
                    {
                        MatchRow matchRow = reportCell.ReportRow.IContent.Key as MatchRow;
                        if (matchRow != null)
                        {
                            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate()
                            {
                                ViewerDebtBlotter.negotiationConsole.MatchId = matchRow.MatchId;
                            }));
                        }
                    }
                }
                catch (Exception exception)
                {
                    // Log any errors trying to select the detail, but don't let these errors kill the application.
                    EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Handlers for the ComboBox class of controls.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="routedEventArgs">The routed event arguments.</param>
        private void OnSelectorSelectionChanged(object sender, RoutedEventArgs routedEventArgs)
        {
            // The main idea of this handler is to sort out the user generated actions from the machine generated actions.  Once
            // its determined that it was a user action, a background thread is called to change the associated field to the value
            // selected by the ComboBox.
            SelectionChangedEventArgs selectionChangedEventArgs = routedEventArgs as SelectionChangedEventArgs;

            // Handle changes to ComboBox elements.
            if (selectionChangedEventArgs.OriginalSource is ComboBox)
            {
                ComboBox comboBox = selectionChangedEventArgs.OriginalSource as ComboBox;
                IContent iContent = comboBox.DataContext as IContent;

                // This filters all the ComboBox events looking for user initiated actions that are bound to the data model.
                if (InputHelper.IsUserInitiated(comboBox, ComboBox.SelectedValueProperty) &&
                    iContent != null && iContent.Key is DataTableCoordinate)
                {
                    // At this point, a ComboBox was modified by the user and it is connected to a data model field.  This will extract
                    // the coordinates of the field in the table.  That, in turn, drives the decision about how to update the shared
                    // data model.
                    DataTableCoordinate dataTableCoordiante = iContent.Key as DataTableCoordinate;
                    MatchRow            matchRow            = dataTableCoordiante.DataRow as MatchRow;
                }
            }
        }
Example #6
0
        /// <summary>
        ///
        /// </summary>
        public static void CleanUnpairedMatches()
        {
            List <KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > > singleMatchWorkingOrderIds = new List <KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > >();

            try
            {
                foreach (MatchRow matchRow in DataModel.Match.Rows)
                {
                    try
                    {
                        if (matchRow.RowState == System.Data.DataRowState.Deleted ||
                            matchRow.RowState == System.Data.DataRowState.Detached)
                        {
                            continue;
                        }

                        Guid     matchId        = (Guid)matchRow[DataModel.Match.MatchIdColumn];
                        Guid     contraMatchId  = (Guid)matchRow[DataModel.Match.ContraMatchIdColumn];
                        MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(contraMatchId);
                        if (contraMatchRow == null ||
                            contraMatchRow.RowState == System.Data.DataRowState.Deleted ||
                            contraMatchRow.RowState == System.Data.DataRowState.Detached)
                        {
                            //make sure we get the matchid even if there is a problem with getting the workingorderIds

                            KeyValuePair <Guid, Guid> orderPair;
                            try
                            {
                                orderPair = new KeyValuePair <Guid, Guid>(
                                    (Guid)matchRow[DataModel.Match.WorkingOrderIdColumn],
                                    (Guid)matchRow[DataModel.Match.ContraOrderIdColumn]);
                            }
                            catch
                            {
                                orderPair = new KeyValuePair <Guid, Guid>();
                            }

                            singleMatchWorkingOrderIds.Add(new KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> >(matchRow, orderPair));
                        }
                    }
                    catch
                    {
                    }
                }                //end foreach

                //this point have collected the match rows to remove and the workingorder rows to rematch
                if (singleMatchWorkingOrderIds.Count > 0)
                {
                    FluidTrade.Core.ThreadPoolHelper.QueueUserWorkItem(new System.Threading.WaitCallback(CleanUnpairedMatchesProc), singleMatchWorkingOrderIds);
                }
            }
            finally
            {
            }
        }
Example #7
0
        private static void DeleteMatch(MatchRow matchRow)
        {
            for (int deadlockRetry = 0; deadlockRetry < deadlockRetiesMax; deadlockRetry++)
            {
                try
                {
                    using (TransactionScope transactionScope = new TransactionScope())
                    {
                        // This provides a context for any transactions.
                        DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                        long rowVersion;
                        Guid matchId;
                        matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        try
                        {
                            if (matchRow.RowState == System.Data.DataRowState.Detached ||
                                matchRow.RowState == System.Data.DataRowState.Deleted)
                            {
                                continue;
                            }

                            rowVersion = matchRow.RowVersion;
                            matchId    = matchRow.MatchId;
                        }
                        finally
                        {
                            matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                        DataModel dataModel = new DataModel();
                        dataModel.DestroyMatch(new object[] { matchId }, rowVersion);

                        transactionScope.Complete();
                        return;
                    }                    //end using
                }
                catch (System.Data.SqlClient.SqlException sqlEx)
                {
                    if (FluidTrade.Core.Utilities.SqlErrorHelper.IsDeadlockException(sqlEx))
                    {
                        if (deadlockRetry == deadlockRetiesMax - 1)
                        {
                            throw;
                        }

                        FluidTrade.Core.EventLog.Warning("Deadlock exception\r\n{0}: {1}\r\n{2}", sqlEx.Message, sqlEx.ToString(), sqlEx.StackTrace);
                    }
                    else
                    {
                        throw;
                    }
                }
            }            //end deadlock retry
        }
Example #8
0
        private static void MatchesFillRow(object obj, out SqlInt32 MatchNumber, out SqlInt32 GroupNumber, out SqlInt32 CaptureNumber,
                                           out SqlBoolean GroupSuccess, [SqlFacet(MaxSize = 255)] out SqlString GroupName, out SqlInt32 Index, out SqlInt32 Length, [SqlFacet(MaxSize = -1)] out SqlString Value)
        {
            MatchRow matchRow = (MatchRow)obj;

            MatchNumber   = new SqlInt32(matchRow.MatchNumber);
            GroupNumber   = new SqlInt32(matchRow.GroupNumber);
            CaptureNumber = new SqlInt32(matchRow.CaptureNumber);
            GroupSuccess  = new SqlBoolean(matchRow.GroupSuccess);
            GroupName     = new SqlString(matchRow.GroupName);
            Index         = matchRow.GroupSuccess ? new SqlInt32(matchRow.Index) : SqlInt32.Null;
            Length        = matchRow.GroupSuccess ? new SqlInt32(matchRow.Length) : SqlInt32.Null;
            Value         = matchRow.GroupSuccess ? new SqlString(matchRow.Value) : SqlString.Null;
        }
        /// <summary>
        /// Evaluates whether a given working order is eligible for a cross with another order.
        /// </summary>
        public static void CrossChat(Object[] key, params Object[] parameters)
        {
            // An instance of the data model is required for CRUD operations.
            DataModel dataModel = new DataModel();

            // The logic below will examine the order and see if a contra order is available for a match.  These values will indicate whether a match is
            // possible after all the locks have been released.
            Guid chatId = (Guid)key[0];

            // A transaction is required to lock the records and change the data model.
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // This variable holds context information for the current transaction.
                DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                // This is the working order that will be tested for a possible buyer or seller (contra party).
                ChatRow chatRow = DataModel.Chat.ChatKey.Find(chatId);
                if (chatRow == null)
                {
                    throw new Exception(string.Format("Chat {0} has been deleted", chatId));
                }
                chatRow.AcquireReaderLock(dataModelTransaction);

                // The match record contains the identifier for the counter party.  The counter party is needed in order to create an
                // entry in the conversation that is private to that user.
                MatchRow matchRow = DataModel.Match.MatchKey.Find(chatRow.MatchId);
                matchRow.AcquireReaderLock(dataModelTransaction);

                // This is the counter party to the match.
                MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(matchRow.ContraMatchId);
                contraMatchRow.AcquireReaderLock(dataModelTransaction);

                // Each side needs a private copy of the conversation in order to pass through the Chinese wall.  This will create an entry in the conversation
                // for the contra side of the conversation.
                Guid     contraChatId = Guid.NewGuid();
                DateTime createdTime  = DateTime.UtcNow;
                dataModel.CreateChat(
                    contraMatchRow.BlotterId,
                    contraChatId,
                    createdTime,
                    true,
                    contraMatchRow.MatchId,
                    chatRow.Message);

                // The working order that triggered this action has completed a scan of the data model and has notified all possible counter parties of the its
                // new status.  Once the transaction is completed, a negotiation session will be started if a new counter party is found.
                transactionScope.Complete();
            }
        }
Example #10
0
        private bool FilterBlotters(ConsumerDebtSettlementRow settlementRow)
        {
            ConsumerDebtNegotiationRow consumerDebtTrustNegotiationRow =
                DataModel.ConsumerDebtNegotiation.ConsumerDebtNegotiationKey.Find(settlementRow.ConsumerDebtNegotiationId);

            ;

            MatchRow matchRow = (consumerDebtTrustNegotiationRow != null) ? DataModel.Match.MatchKey.Find(consumerDebtTrustNegotiationRow.MatchId)
                        : null;

            //if (matchRow != null)
            //    return this.blotterList.BinarySearch(matchRow.BlotterId) >= 0;
            //else
            return(true);
        }
Example #11
0
        /// <summary>
        /// Event handler for a match.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="e">The event arguments.</param>
        private void OnMatchRowChanged(Object sender, MatchRowChangeEventArgs e)
        {
            // When a new, pending match record has been added to the data mode, start a thread that will
            // display the notification window.
            if (e.Action == DataRowAction.Commit && e.Row.RowState != DataRowState.Detached)
            {
                if (e.Row.StatusRow.StatusCode == Status.Active ||
                    e.Row.StatusRow.StatusCode == Status.PartialMatch ||
                    e.Row.StatusRow.StatusCode == Status.ValidMatch ||
                    e.Row.StatusRow.StatusCode == Status.ValidMatchFunds ||
                    e.Row.StatusRow.StatusCode == Status.Declined)
                {
                    NotificationInfo notificationInfo = new NotificationInfo();

                    // The match record, working order, order type and security records are used to construct the title, symbol and
                    // logo used by the notification window.
                    MatchRow        matchRow        = e.Row;
                    WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow;
                    OrderTypeRow    orderTypeRow    = workingOrderRow.OrderTypeRow;
                    SecurityRow     securityRow     = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId;

                    // This is the primary method of identifying a match between two working orders.
                    notificationInfo.MatchId = matchRow.MatchId;

                    // The current status of the match is used to tell whether we're coming or going.
                    notificationInfo.Status = matchRow.StatusRow.StatusCode;

                    // Get the security symbol.
                    notificationInfo.Symbol = securityRow.Symbol;

                    // Create a logo bitmap.
                    notificationInfo.Logo = securityRow.IsLogoNull() ? String.Empty : securityRow.Logo;

                    // Provide a handler for the notification.
                    if (!securityRow.EntityRow.TypeRow.IsNotifyingTypeNull())
                    {
                        notificationInfo.NotifierType = securityRow.EntityRow.TypeRow.NotifyingType;

                        // Construct the title for the notification window.
                        notificationInfo.Message = String.Format("{0} of {1}", workingOrderRow.SideRow.Description, securityRow.Symbol);

                        // Now that the information has been extracted for the data model, the background execution queue can handle the rest of the
                        // notification of the user.
                        this.OnNotification(notificationInfo);
                    }
                }
            }
        }
Example #12
0
        /// <summary>
        /// Handlers for the Toggle button class of controls.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="routedEventArgs">The routed event arguments.</param>
        private void OnToggleButtonChange(object sender, RoutedEventArgs routedEventArgs)
        {
            // The main idea of this handler is to sort out the user generated actions from the machine generated actions.  Once
            // its determined that it was a user action, a background thread is called to change the associated field to the value
            // selected by the ToggleButton.
            ToggleButton toggleButton = routedEventArgs.OriginalSource as ToggleButton;
            IContent     iContent     = toggleButton.DataContext as IContent;

            // This filters all the ToggleButton events looking for user initiated actions that are bound to the data model.
            if (InputHelper.IsUserInitiated(toggleButton, ToggleButton.IsCheckedProperty) &&
                iContent != null && iContent.Key is DataTableCoordinate)
            {
                // At this point, a ToggleButton was modified by the user and it is connected to a data model field.  This will
                // extract the coordinates of the field in the table.  That, in turn, drives the decision about how to update the
                // shared data model.
                DataTableCoordinate dataTableCoordiante = iContent.Key as DataTableCoordinate;
                MatchRow            matchRow            = dataTableCoordiante.DataRow as MatchRow;
            }
        }
Example #13
0
        internal static void Decline(Guid matchId, Int64 rowVersion)
        {
            DataModel dataModel = new DataModel();

            try
            {
                DataModel.DataLock.EnterReadLock();

                // This context is used to keep track of the locks aquired for the ancillary data.
                TransactionScope     transactionScope     = new TransactionScope();
                DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
                if (matchRow != null)
                {
                    // Time stamps and user stamps
                    Guid     modifiedUserId = TradingSupport.UserId;
                    DateTime modifiedTime   = DateTime.UtcNow;

                    // Call the internal method to complete the operation.
                    dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { matchRow.MatchId }, rowVersion, StatusMap.FromCode(Status.Declined), null);

                    // Call the internal method to decline the contra side of this match.
                    foreach (MatchRow contraMatchRow in DataModel.Match.Rows)
                    {
                        if (contraMatchRow.WorkingOrderId == matchRow.ContraOrderId && contraMatchRow.ContraOrderId == matchRow.WorkingOrderId)
                        {
                            rowVersion = contraMatchRow.RowVersion;
                            dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { contraMatchRow.MatchId }, rowVersion, StatusMap.FromCode(Status.Declined), null);
                        }
                    }
                }
            }
            finally
            {
                // Release the tables.
                DataModel.DataLock.ExitReadLock();
            }
        }
        private void DeclineTrade(object parameter)
        {
            DataModelClient dataModelClient = new DataModelClient(FluidTrade.Guardian.Properties.Settings.Default.DataModelEndpoint);

            lock (DataModel.SyncRoot)
            {
                // Find the Match record.
                MatchRow matchRow = DataModel.Match.MatchKey.Find(this.matchId);
                if (matchRow == null)
                {
                    Guid negotiationId = Guid.NewGuid();
                    dataModelClient.CreateNegotiation(
                        matchRow.WorkingOrderRow.BlotterId,
                        null,
                        null,
                        matchRow.MatchId,
                        negotiationId,
                        0.0M,
                        DataModel.Status.StatusKeyStatusCode.Find(Status.Declined).StatusId);
                }
            }
        }
        private void NegotiateTrade(object parameter)
        {
            // Extract the thread parameters
            Decimal quantity = (Decimal)parameter;

            DataModelClient dataModelClient = new DataModelClient(Guardian.Properties.Settings.Default.DataModelEndpoint);

            lock (DataModel.SyncRoot)
            {
                // Open up the negotiations.
                MatchRow matchRow      = DataModel.Match.MatchKey.Find(this.matchId);
                Guid     negotiationId = Guid.NewGuid();
                dataModelClient.CreateNegotiation(
                    matchRow.WorkingOrderRow.BlotterId,
                    null,
                    null,
                    matchRow.MatchId,
                    negotiationId,
                    quantity,
                    DataModel.Status.StatusKeyStatusCode.Find(Status.Pending).StatusId);
            }
        }
        /// <summary>
        /// Initialize the data used in this application.
        /// </summary>
        private void InitializeData(object parameter)
        {
            String           title            = String.Empty;
            String           symbol           = String.Empty;
            String           name             = String.Empty;
            String           logoSource       = null;
            Decimal          leavesQuantity   = 0.0m;
            NegotiationState negotiationState = NegotiationState.None;

            lock (DataModel.SyncRoot)
            {
                // Find the Match record.
                MatchRow        matchRow        = DataModel.Match.MatchKey.Find(this.matchId);
                WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow;
                OrderTypeRow    orderTypeRow    = workingOrderRow.OrderTypeRow;
                SecurityRow     securityRow     = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId;

                symbol         = securityRow.Symbol;
                name           = securityRow.EntityRow.Name;
                logoSource     = securityRow.IsLogoNull() ? String.Empty : securityRow.Logo;
                title          = String.Format("{0} of {1}", orderTypeRow.Description, symbol);
                leavesQuantity = 0.0M;
                foreach (SourceOrderRow sourceOrderRow in workingOrderRow.GetSourceOrderRows())
                {
                    leavesQuantity += sourceOrderRow.OrderedQuantity;
                }
                foreach (DestinationOrderRow destinationOrderRow in workingOrderRow.GetDestinationOrderRows())
                {
                    foreach (ExecutionRow executionRow in destinationOrderRow.GetExecutionRows())
                    {
                        leavesQuantity -= executionRow.ExecutionQuantity;
                    }
                }
                leavesQuantity /= securityRow.QuantityFactor;
            }

            this.Dispatcher.Invoke(DispatcherPriority.Normal, new SetDialogAttributesDelegate(SetDialogAttributes), title, symbol, name, logoSource, leavesQuantity, negotiationState);
        }
        public static void CreateChat(ChatInfo[] chatInfos)
        {
            // A reference to the data model is required for actions that modify it.
            DataModel dataModel = new DataModel();

            // Everything in this transaction will be committed or rolled back as a unit.
            using (TransactionScope transactionScope = new TransactionScope())
            {
                // Extract the ambient transaction.
                DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                // This action handles a batch of chat items in a single transaction.
                foreach (ChatInfo chatInfo in chatInfos)
                {
                    // These values are required for each chat item added.
                    Guid     blotterId   = default(Guid);
                    DateTime createdTime = DateTime.UtcNow;

                    // The Match record contains the blotter identifier which is used for filtering.
                    MatchRow matchRow = DataModel.Match.MatchKey.Find(chatInfo.MatchId);
                    try
                    {
                        matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        blotterId = matchRow.BlotterId;
                    }
                    finally
                    {
                        matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // Once the blotter id has been extracted the internal methods can be called to add the chat item.
                    dataModel.CreateChat(blotterId, chatInfo.ChatId, createdTime, false, chatInfo.MatchId, chatInfo.Message);
                }

                // If we reached this point the transaction was successful.
                transactionScope.Complete();
            }
        }
Example #18
0
        /// <summary>
        /// Marshals the data needed to navigate the client application to the accepted item in the Match blotter.
        /// </summary>
        /// <param name="parameter">The thread initialization data.</param>
        private void AcceptNegotiationThread(Object parameter)
        {
            // Extract the parameters.
            Guid matchId = (Guid)parameter;

            // The main goal of this section of code is to construct an object that can be used to navigate the
            // client container to the selected item in the blotter.
            OpenObjectEventArgs openObjectEventArgs = null;

            lock (DataModel.SyncRoot)
            {
                // The 'BlotterMatchDetail' can be used to open up a Blotter in a viewer and select the Match.
                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
                if (matchRow != null)
                {
                    openObjectEventArgs = new OpenObjectEventArgs(
                        new Blotter(matchRow.WorkingOrderRow.BlotterRow.EntityRow),
                        new Match[] { new Match(matchRow.MatchId) });
                }
            }

            this.negotiationService.OnOpenObject(openObjectEventArgs);
        }
        /// <summary>
        /// Delete a match
        /// </summary>
        /// <returns>True for sucess</returns>
        public override ErrorCode Delete(Records.Match record)
        {
            if (record.RowId == null || DataModel.Match.MatchKey.Find(record.RowId) == null)
            {
                return(ErrorCode.RecordNotFound);
            }

            DataModel            dataModel            = new DataModel();
            MatchRow             matchRow             = DataModel.Match.MatchKey.Find(record.RowId);
            DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

            matchRow.AcquireReaderLock(dataModelTransaction);
            if (!TradingSupport.HasAccess(dataModelTransaction, matchRow.BlotterId, AccessRight.FullControl))
            {
                return(ErrorCode.AccessDenied);
            }
            MatchRow contraMatchRow = DataModel.Match.MatchKey.Find(matchRow.ContraMatchId);

            matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);

            dataModel.DestroyMatch(
                new object[] { record.RowId },
                record.RowVersion);
            matchRow.ReleaseWriterLock(dataModelTransaction.TransactionId);

            // Delete the contra second, in case the record.RowVersion is off.
            if (contraMatchRow != null)
            {
                contraMatchRow.AcquireWriterLock(dataModelTransaction);
                dataModel.DestroyMatch(
                    new object[] { contraMatchRow.MatchId },
                    contraMatchRow.RowVersion);
                contraMatchRow.ReleaseWriterLock(dataModelTransaction.TransactionId);
            }

            return(ErrorCode.Success);
        }
Example #20
0
        /// <summary>
        /// Creates a settlement for a Consumer Trust representative.
        /// </summary>
        /// <param name="consumerTrustNegotiationId">The identifier of the negotiation that has been agreed to by both parties.</param>
        public static void CreateConsumerTrustSettlement(Guid consumerTrustNegotiationId)
        {
            // A reference to the data model is required to query the database within the scope of a transaction.
            DataModel dataModel = new DataModel();

            // The locking model does not provide for recursive reader locks or promoting reader locks to writer locks.  So the data is collected
            // during a phase then the table can be locked determinstically to prevent deadlocks, then the calls to update the data model are made
            // once all the reader locks have been released.  This structure holds the information required for the creation of a settlement record.
            TrustSettlementInfo trustSettlementInfo = new TrustSettlementInfo();

            // Extract the ambient transaction.
            DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

            // These rows will be locked momentarily while the data is collected and released before the actual transaction.
            ConsumerTrustNegotiationRow consumerTrustNegotiationRow = null;
            MatchRow     matchRow         = null;
            MatchRow     contraMatchRow   = null;
            BlotterRow   blotterRow       = null;
            BlotterRow   contraBlotterRow = null;
            DebtClassRow debtClassRow     = null;
            ConsumerDebtNegotiationRow consumerDebtNegotiationRow = null;
            WorkingOrderRow            workingOrderRow            = null;
            SecurityRow      securityRow           = null;
            ConsumerTrustRow consumerTrustRow      = null;
            WorkingOrderRow  contraWorkingOrderRow = null;
            SecurityRow      contraSecurityRow     = null;
            ConsumerDebtRow  consumerDebtRow       = null;
            ConsumerRow      consumerRow           = null;
            CreditCardRow    creditCardRow         = null;

            try
            {
                // The starting point for creating a settlement record is to find the negotiation record that has been agreed to by both parties.
                consumerTrustNegotiationRow = DataModel.ConsumerTrustNegotiation.ConsumerTrustNegotiationKey.Find(consumerTrustNegotiationId);
                consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // This is the record used to match this asset against another.
                matchRow = consumerTrustNegotiationRow.MatchRow;
                matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The next step is to find the counter parties matching information which will lead us to the counter parties asset which, in turn, contains
                // more information for the settlement.
                contraMatchRow = DataModel.Match.MatchKey.Find(matchRow.ContraMatchId);
                contraMatchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The blotter contains a link to the Debt Class which is where the Payee information is found.
                blotterRow = matchRow.BlotterRow;
                blotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The blotter contains a link to the Debt Class which is where the Payee information is found.
                contraBlotterRow = contraMatchRow.BlotterRow;
                contraBlotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The debt class of the debt holder provides information about the Payee.
                debtClassRow = contraBlotterRow.GetDebtClassRows()[0];
                debtClassRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // 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;
                foreach (ConsumerDebtNegotiationRow versionRow in contraMatchRow.GetConsumerDebtNegotiationRows())
                {
                    try
                    {
                        versionRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        if (versionRow.Version > maxVersion)
                        {
                            maxVersion = versionRow.Version;
                            consumerDebtNegotiationRow = versionRow;
                        }
                    }
                    finally
                    {
                        versionRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }
                }
                consumerDebtNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The working order record is part of the object oriented path that will lead to the the asset information.  This info is also needed for the
                // settlement record.
                workingOrderRow = matchRow.WorkingOrderRow;
                workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The Security record will lead us to the asset.
                securityRow = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId;
                securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // This row contains the actual asset that is to be matched.
                consumerTrustRow = securityRow.GetConsumerTrustRows()[0];
                consumerTrustRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // The counter party's asset information is also required.
                contraWorkingOrderRow = contraMatchRow.WorkingOrderRow;
                contraWorkingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // This will lead to the counter party's asset.
                contraSecurityRow = contraWorkingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId;
                contraSecurityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // This is the asset belonging to the counter party that has just agreed to a settlement.
                consumerDebtRow = contraSecurityRow.GetConsumerDebtRows()[0];
                consumerDebtRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // This is the Debt Negotiator's version of the Consumer will be used to settle the account.
                consumerRow = consumerTrustRow.ConsumerRow;
                consumerRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // We also need to know which credit card was settled.
                creditCardRow = consumerDebtRow.CreditCardRow;
                creditCardRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                // These values are extracted from the data model while reader locks are in place on the related records.  Since the locks aren't recursive
                // and reader locks can't be promoted, any locks held for this collection process must be released before the middle tier methods are
                // called to create the record.
                trustSettlementInfo.AccountBalance              = consumerDebtNegotiationRow.AccountBalance;
                trustSettlementInfo.BlotterId                   = contraWorkingOrderRow.BlotterId;
                trustSettlementInfo.ConsumerTrustNegotiationId  = consumerDebtNegotiationRow.ConsumerDebtNegotiationId;
                trustSettlementInfo.ConsumerTrustSettlementId   = Guid.NewGuid();
                trustSettlementInfo.ContraMatchId               = contraMatchRow.MatchId;
                trustSettlementInfo.ContraMatchRowVersion       = contraMatchRow.RowVersion;
                trustSettlementInfo.CreatedTime                 = DateTime.UtcNow;
                trustSettlementInfo.CreatedUserId               = TradingSupport.DaemonUserId;
                trustSettlementInfo.DebtorAccountNumber         = creditCardRow.AccountNumber;
                trustSettlementInfo.DebtorAddress1              = consumerRow.IsAddress1Null() ? null : consumerRow.Address1;
                trustSettlementInfo.DebtorAddress2              = consumerRow.IsAddress2Null() ? null : consumerRow.Address2;
                trustSettlementInfo.DebtorBankAccountNumber     = consumerRow.IsBankAccountNumberNull() ? null : consumerRow.BankAccountNumber;
                trustSettlementInfo.DebtorBankRoutingNumber     = consumerRow.IsBankRoutingNumberNull() ? null : consumerRow.BankRoutingNumber;
                trustSettlementInfo.DebtorFirstName             = consumerRow.IsFirstNameNull() ? null : consumerRow.FirstName;
                trustSettlementInfo.DebtorLastName              = consumerRow.IsLastNameNull() ? null : consumerRow.LastName;
                trustSettlementInfo.DebtorMiddleName            = consumerRow.IsMiddleNameNull() ? null : consumerRow.MiddleName;
                trustSettlementInfo.DebtorOriginalAccountNumber = creditCardRow.OriginalAccountNumber;
                trustSettlementInfo.DebtorSalutation            = consumerRow.IsSalutationNull() ? null : consumerRow.Salutation;
                trustSettlementInfo.DebtorSuffix                = consumerRow.IsSuffixNull() ? null : consumerRow.Suffix;
                trustSettlementInfo.DebtorCity                  = consumerRow.IsCityNull() ? null : consumerRow.City;
                trustSettlementInfo.DebtorProvinceId            = consumerRow.IsProvinceIdNull() ? null : (Object)consumerRow.ProvinceId;
                trustSettlementInfo.DebtorPostalCode            = consumerRow.IsPostalCodeNull() ? null : consumerRow.PostalCode;
                trustSettlementInfo.DebtStatusId                = contraMatchRow.StatusId;
                trustSettlementInfo.MatchId                = matchRow.MatchId;
                trustSettlementInfo.MatchRowVersion        = matchRow.RowVersion;
                trustSettlementInfo.ModifiedTime           = trustSettlementInfo.CreatedTime;
                trustSettlementInfo.ModifiedUserId         = trustSettlementInfo.CreatedUserId;
                trustSettlementInfo.PayeeAddress1          = debtClassRow.IsAddress1Null() ? null : debtClassRow.Address1;
                trustSettlementInfo.PayeeAddress2          = debtClassRow.IsAddress2Null() ? null : debtClassRow.Address2;
                trustSettlementInfo.PayeeBankAccountNumber = debtClassRow.IsBankAccountNumberNull() ? null : debtClassRow.BankAccountNumber;
                trustSettlementInfo.PayeeBankRoutingNumber = debtClassRow.IsBankRoutingNumberNull() ? null : debtClassRow.BankRoutingNumber;
                trustSettlementInfo.PayeeCity              = debtClassRow.IsCityNull() ? null : debtClassRow.City;
                trustSettlementInfo.PayeeCompanyName       = debtClassRow.IsCompanyNameNull() ? null : debtClassRow.CompanyName;
                trustSettlementInfo.PayeeContactName       = debtClassRow.IsContactNameNull() ? null : debtClassRow.ContactName;
                trustSettlementInfo.PayeeDepartment        = debtClassRow.IsDepartmentNull() ? null : debtClassRow.Department;
                trustSettlementInfo.PayeeEmail             = debtClassRow.IsEmailNull() ? null : debtClassRow.Email;
                trustSettlementInfo.PayeeFax               = debtClassRow.IsFaxNull() ? null : debtClassRow.Fax;
                trustSettlementInfo.PayeeForBenefitOf      = debtClassRow.IsForBenefitOfNull() ? null : debtClassRow.ForBenefitOf;
                trustSettlementInfo.PayeePhone             = debtClassRow.IsPhoneNull() ? null : debtClassRow.Phone;
                trustSettlementInfo.PayeeProvinceId        = debtClassRow.IsProvinceIdNull() ? null : (Object)debtClassRow.ProvinceId;
                trustSettlementInfo.PayeePostalCode        = debtClassRow.IsPostalCodeNull() ? null : debtClassRow.PostalCode;
                trustSettlementInfo.PaymentLength          = consumerDebtNegotiationRow.OfferPaymentLength;
                trustSettlementInfo.TrustStatusId          = matchRow.StatusId;

                // The payment methods acceptable for this settlement is the union of the payment methods acceptable to both sides.
                foreach (ConsumerDebtNegotiationOfferPaymentMethodRow consumerDebtNegotiationOfferPaymentMethodRow
                         in consumerDebtNegotiationRow.GetConsumerDebtNegotiationOfferPaymentMethodRows())
                {
                    try
                    {
                        // The payment method needs to be locked while we check the counter party to see what types of payment methods are used there.
                        consumerDebtNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                        // This loop will compare all of the counter party's acceptable payment methods against the current one offered by the
                        // Debt Holder.  If there are any that are compatible, they are moved to a list that is used to generate the settlement.
                        foreach (ConsumerTrustNegotiationOfferPaymentMethodRow consumerTrustNegotiationOfferPaymentMethodRow
                                 in consumerTrustNegotiationRow.GetConsumerTrustNegotiationOfferPaymentMethodRows())
                        {
                            try
                            {
                                // Lock each of the counter party payment methods while a compatible one is found.
                                consumerTrustNegotiationOfferPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                // All compatible payment methods between the parties become part of the settlement information.
                                if (consumerDebtNegotiationOfferPaymentMethodRow.PaymentMethodTypeId ==
                                    consumerTrustNegotiationOfferPaymentMethodRow.PaymentMethodTypeId)
                                {
                                    trustSettlementInfo.PaymentMethods.Add(
                                        new PaymentMethodInfo(Guid.NewGuid(), consumerTrustNegotiationOfferPaymentMethodRow.PaymentMethodTypeId));
                                }
                            }
                            finally
                            {
                                // The counter party payment method is no longer needed.
                                consumerTrustNegotiationOfferPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                            }
                        }
                    }
                    finally
                    {
                        // This payment method is no longer needed.
                        consumerDebtNegotiationOfferPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }
                }

                // This will calculate the amount of time until the first payment based on the amount of time in the negotiation and the time units.
                TimeUnitRow timeUnitRow = DataModel.TimeUnit.TimeUnitKey.Find(consumerDebtNegotiationRow.OfferPaymentStartDateUnitId);
                try
                {
                    timeUnitRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    trustSettlementInfo.PaymentStartDate = CommonConversion.ToDateTime(
                        consumerDebtNegotiationRow.OfferPaymentStartDateLength,
                        timeUnitRow.TimeUnitCode);
                }
                finally
                {
                    timeUnitRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }

                // This will calculate the real value of the settlement from the negotiated parameters.  All settlements are in terms of market value while
                // the negotiations may take place in terms of percentages, market value or basis points.
                SettlementUnitRow settlementUnitRow = consumerDebtNegotiationRow.SettlementUnitRowByFK_SettlementUnit_ConsumerDebtNegotiation_OfferSettlementUnitId;
                try
                {
                    // Lock the SettlementUnit row down while the actual settlement value is calculated.
                    settlementUnitRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // This will calclate the actual settlement value from the negotiated value and the units used to negotiate.
                    switch (settlementUnitRow.SettlementUnitCode)
                    {
                    case SettlementUnit.BasisPoint:

                        trustSettlementInfo.SettlementAmount = Math.Round(
                            consumerDebtNegotiationRow.AccountBalance * consumerDebtNegotiationRow.OfferSettlementValue, 2);
                        break;

                    case SettlementUnit.MarketValue:

                        trustSettlementInfo.SettlementAmount = consumerDebtNegotiationRow.OfferSettlementValue;
                        break;

                    case SettlementUnit.Percent:

                        trustSettlementInfo.SettlementAmount = Math.Round(
                            consumerDebtNegotiationRow.AccountBalance * consumerDebtNegotiationRow.OfferSettlementValue, 2);
                        break;
                    }
                }
                finally
                {
                    // The SettlementUnit row is no longer needed.
                    settlementUnitRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }

                // The 'Accepted' status indicates that one side of the negotiation has accepted the offer.
                StatusRow acceptedStatusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.Accepted);
                try
                {
                    acceptedStatusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    trustSettlementInfo.AcceptedStatusId = acceptedStatusRow.StatusId;
                }
                finally
                {
                    acceptedStatusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }

                // The 'New' status is use for all freshly crated settlements.  This state is used to tell the settlement engine that a settlement document
                // should be created from the parameters.
                StatusRow newStatusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.New);
                try
                {
                    newStatusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    trustSettlementInfo.NewStatusId = newStatusRow.StatusId;
                }
                finally
                {
                    newStatusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }

                // The 'Locked' status indicates that one side of the negotiation has accepted the offer.
                StatusRow offerAcceptedStatusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.OfferAccepted);
                try
                {
                    offerAcceptedStatusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    trustSettlementInfo.OfferAcceptedStatusId = offerAcceptedStatusRow.StatusId;
                }
                finally
                {
                    offerAcceptedStatusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }

                // The 'Pending' status indicates that one side of the negotiation has accepted the offer.
                StatusRow pendingStatusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.Pending);
                try
                {
                    pendingStatusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    trustSettlementInfo.PendingStatusId = pendingStatusRow.StatusId;
                }
                finally
                {
                    pendingStatusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
            }
            finally
            {
                // Release the record locks.
                if (consumerTrustNegotiationRow != null)
                {
                    consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (matchRow != null)
                {
                    matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (contraMatchRow != null)
                {
                    contraMatchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (blotterRow != null)
                {
                    blotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (contraBlotterRow != null)
                {
                    contraBlotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (debtClassRow != null)
                {
                    debtClassRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (consumerDebtNegotiationRow != null)
                {
                    consumerDebtNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (workingOrderRow != null)
                {
                    workingOrderRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (securityRow != null)
                {
                    securityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (consumerTrustRow != null)
                {
                    consumerTrustRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (contraWorkingOrderRow != null)
                {
                    contraWorkingOrderRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (contraSecurityRow != null)
                {
                    contraSecurityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (consumerDebtRow != null)
                {
                    consumerDebtRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (consumerRow != null)
                {
                    consumerRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
                if (creditCardRow != null)
                {
                    creditCardRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
            }

            // Nothing is done if this order has already been settled.
            if (trustSettlementInfo.TrustStatusId == trustSettlementInfo.AcceptedStatusId)
            {
                return;
            }

            // Nothing is done if this side has already accepted the negotiation and is waiting for the other side to respond.
            if (trustSettlementInfo.TrustStatusId == trustSettlementInfo.PendingStatusId)
            {
                return;
            }

            // Busines Rule #1: Don't allow a settlement if the payment methods are not compatible.
            if (trustSettlementInfo.PaymentMethods.Count == 0)
            {
                throw new FaultException <PaymentMethodFault>(new PaymentMethodFault("The negotiation doesn't contain compatible payment methods."));
            }

            // Busines Rule #2: Insure there is a Payee Address
            if (trustSettlementInfo.PayeeAddress1 == null)
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Payee Address was not provided."));
            }
            // Busines Rule #2: Insure there is a Payee City
            if (trustSettlementInfo.PayeeCity == null)
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Payee City was not provided."));
            }

            // Busines Rule #3: Insure there is a Payee Province
            if (trustSettlementInfo.PayeeProvinceId == null)
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Payee Province was not provided."));
            }

            // Busines Rule #4: Insure there is a Payee Company Name
            if (String.IsNullOrEmpty((String)trustSettlementInfo.PayeeCompanyName))
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Payee Company Name was not provided."));
            }

            // Busines Rule #5: Insure there is a Debtor City
            if (String.IsNullOrEmpty((String)trustSettlementInfo.DebtorAddress1))
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Debtor Address was not provided."));
            }

            // Busines Rule #5: Insure there is a Debtor City
            if (String.IsNullOrEmpty((String)trustSettlementInfo.DebtorCity))
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Debtor City was not provided."));
            }

            // Busines Rule #6: Insure there is a Debtor Province
            if (trustSettlementInfo.DebtorProvinceId == null)
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Debtor State was not provided."));
            }

            // Busines Rule #7: Insure there is a first or last name.
            if (String.IsNullOrEmpty((String)trustSettlementInfo.DebtorFirstName) && String.IsNullOrEmpty((String)trustSettlementInfo.DebtorLastName))
            {
                throw new FaultException <ArgumentFault>(new ArgumentFault("The Debtor Name was not provided."));
            }

            // Only when the Consumer Debt side is awaiting a settlement is the settlement generated.
            if (trustSettlementInfo.DebtStatusId == trustSettlementInfo.PendingStatusId)
            {
                // The state of the Match must be updated to reflect that this record is no longer available for negotiation.
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new Object[] { trustSettlementInfo.MatchId },
                    trustSettlementInfo.MatchRowVersion,
                    trustSettlementInfo.AcceptedStatusId,
                    null);

                // The contra is also updated to reflect the settled state of this negotiation.
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new Object[] { trustSettlementInfo.ContraMatchId },
                    trustSettlementInfo.ContraMatchRowVersion,
                    trustSettlementInfo.AcceptedStatusId,
                    null);

                // This records the terms of the settlement between the Consumer Trust account and the Consumer Debt account.
                dataModel.CreateConsumerDebtSettlement(
                    trustSettlementInfo.AccountBalance,
                    trustSettlementInfo.BlotterId,
                    trustSettlementInfo.ConsumerTrustNegotiationId,
                    trustSettlementInfo.ConsumerTrustSettlementId,
                    trustSettlementInfo.CreatedTime,
                    trustSettlementInfo.CreatedUserId,
                    trustSettlementInfo.DebtorAccountNumber,
                    trustSettlementInfo.DebtorAddress1,
                    trustSettlementInfo.DebtorAddress2,
                    trustSettlementInfo.DebtorBankAccountNumber,
                    trustSettlementInfo.DebtorBankRoutingNumber,
                    trustSettlementInfo.DebtorCity,
                    trustSettlementInfo.DebtorFirstName,
                    trustSettlementInfo.DebtorLastName,
                    trustSettlementInfo.DebtorMiddleName,
                    trustSettlementInfo.DebtorOriginalAccountNumber,
                    trustSettlementInfo.DebtorPostalCode,
                    trustSettlementInfo.DebtorProvinceId,
                    trustSettlementInfo.DebtorSalutation,
                    trustSettlementInfo.DebtorSuffix,
                    null,
                    trustSettlementInfo.ModifiedTime,
                    trustSettlementInfo.ModifiedUserId,
                    trustSettlementInfo.PayeeAddress1,
                    trustSettlementInfo.PayeeAddress2,
                    trustSettlementInfo.PayeeBankAccountNumber,
                    trustSettlementInfo.PayeeBankRoutingNumber,
                    trustSettlementInfo.PayeeCity,
                    trustSettlementInfo.PayeeCompanyName,
                    trustSettlementInfo.PayeeContactName,
                    trustSettlementInfo.PayeeDepartment,
                    trustSettlementInfo.PayeeEmail,
                    trustSettlementInfo.PayeeFax,
                    trustSettlementInfo.PayeeForBenefitOf,
                    trustSettlementInfo.PayeePhone,
                    trustSettlementInfo.PayeePostalCode,
                    trustSettlementInfo.PayeeProvinceId,
                    trustSettlementInfo.PaymentLength,
                    trustSettlementInfo.PaymentStartDate,
                    trustSettlementInfo.SettlementAmount,
                    null,
                    trustSettlementInfo.NewStatusId);

                // Each of the acceptable payment methods is also written as part of this transaction.
                foreach (PaymentMethodInfo paymentMethodInfo in trustSettlementInfo.PaymentMethods)
                {
                    dataModel.CreateConsumerDebtSettlementPaymentMethod(
                        trustSettlementInfo.BlotterId,
                        trustSettlementInfo.ConsumerTrustSettlementId,
                        paymentMethodInfo.ConsumerTrustSettlementPaymentMethodId,
                        paymentMethodInfo.PaymentMethodId);
                }
            }
            else
            {
                // At this point, the other party has not yet accepted the offer so we set the status of the Match and wait.
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new Object[] { trustSettlementInfo.MatchId },
                    trustSettlementInfo.MatchRowVersion,
                    trustSettlementInfo.PendingStatusId,
                    null);

                // The counter party must be advised that they can not alter the state of the settlement once it has been accepted.
                dataModel.UpdateMatch(
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    new Object[] { trustSettlementInfo.ContraMatchId },
                    trustSettlementInfo.ContraMatchRowVersion,
                    trustSettlementInfo.OfferAcceptedStatusId,
                    null);
            }
        }
        /// <summary>
        /// Collect negotiation and settlement data to move
        /// </summary>
        /// <param name="dataModelTransaction"></param>
        /// <param name="moveToInfo"></param>
        /// <param name="matchRow"></param>
        private static void CollectNegotiationData(DataModelTransaction dataModelTransaction, MoveToInfo moveToInfo, MatchRow matchRow)
        {
            foreach (ConsumerTrustNegotiationRow consumerTrustNegotiationRow in matchRow.GetConsumerTrustNegotiationRows())
            {
                consumerTrustNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                try
                {
                    moveToInfo.consumerTrustNegotiationRows.Add(new BaseRecord()
                    {
                        RowId = consumerTrustNegotiationRow.ConsumerTrustNegotiationId, RowVersion = consumerTrustNegotiationRow.RowVersion
                    });


                    //Get counter payment rows to move
                    foreach (ConsumerTrustNegotiationCounterPaymentMethodRow counterPaymentMethodRow in consumerTrustNegotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows())
                    {
                        counterPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        try
                        {
                            moveToInfo.consumerTrustNegotiationCounterPaymentMethodRows.Add(new BaseRecord()
                            {
                                RowId = counterPaymentMethodRow.ConsumerTrustNegotiationCounterPaymentMethodId, RowVersion = counterPaymentMethodRow.RowVersion
                            });
                        }
                        finally
                        {
                            counterPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }

                    //Get offer payment rows to move
                    foreach (ConsumerTrustNegotiationOfferPaymentMethodRow offerPaymentMethodRow in consumerTrustNegotiationRow.GetConsumerTrustNegotiationOfferPaymentMethodRows())
                    {
                        offerPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        try
                        {
                            moveToInfo.consumerTrustNegotiationOfferPaymentMethodRows.Add(new BaseRecord()
                            {
                                RowId = offerPaymentMethodRow.ConsumerTrustNegotiationOfferPaymentMethodId, RowVersion = offerPaymentMethodRow.RowVersion
                            });
                        }
                        finally
                        {
                            offerPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }

                    //Get Settlement rows to move
                    CollectSettlementData(dataModelTransaction, moveToInfo, consumerTrustNegotiationRow);
                }
                finally
                {
                    consumerTrustNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }
            }
        }
Example #22
0
        /// <summary>
        /// clean up the bad matches
        /// </summary>
        /// <param name="state"></param>
        private static void CleanUnpairedMatchesProc(object state)
        {
            List <KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > > singleMatchWorkingOrderIds = (List <KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > >)state;

            //first delete all the matches in their own txn
            foreach (KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > pair in singleMatchWorkingOrderIds)
            {
                MatchRow matchRow = pair.Key;
                try
                {
                    DeleteMatch(matchRow);
                }
                catch (Exception ex)
                {
                    FluidTrade.Core.EventLog.Warning("DeleteMatch exception\r\n{0}: {1}\r\n", ex.Message, ex.ToString());
                }
            }

            //set to something in the future.. not being saved so does not really matter how
            //far but if matches run for a long time this is basiclly how long the process of update
            //will run because the check will no longer be > utcNow
            DateTime utcNowPlusHour = DateTime.UtcNow.AddHours(12);

            foreach (KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > pair in singleMatchWorkingOrderIds)
            {
                Guid workingOrderId = pair.Value.Key;

                if (workingOrderId == Guid.Empty)
                {
                    continue;
                }

                try
                {
                    UpdateOrderModifyTime(utcNowPlusHour, workingOrderId);
                }
                catch (Exception ex)
                {
                    FluidTrade.Core.EventLog.Warning("UpdateOrderModifyTime exception\r\n{0}: {1}\r\n", ex.Message, ex.ToString());
                }
            }

            foreach (KeyValuePair <MatchRow, KeyValuePair <Guid, Guid> > pair in singleMatchWorkingOrderIds)
            {
                Guid contraWorkingOrderId = pair.Value.Value;

                if (contraWorkingOrderId == Guid.Empty)
                {
                    continue;
                }

                try
                {
                    UpdateOrderModifyTime(utcNowPlusHour, contraWorkingOrderId);
                }
                catch (Exception ex)
                {
                    FluidTrade.Core.EventLog.Warning("UpdateOrderModifyTime exception\r\n{0}: {1}\r\n", ex.Message, ex.ToString());
                }
            }
        }
Example #23
0
        /// <summary>
        /// Determine whether there is a settlement (indirectly) associated with a match.
        /// </summary>
        /// <param name="transaction">The current transaction.</param>
        /// <param name="match">The match to check.</param>
        /// <param name="checkContra">If true, the contra match will also be checked.</param>
        /// <returns>True if the account is settled.</returns>
        public static bool IsSettled(DataModelTransaction transaction, MatchRow match, System.Boolean checkContra)
        {
            ConsumerDebtNegotiationRow[]  consumerDebtNegotiationRows;
            ConsumerTrustNegotiationRow[] consumerTrustNegotiationRows;
            MatchRow contraMatch;

            if ((match as System.Data.DataRow).RowState == System.Data.DataRowState.Added)
            {
                return(false);
            }

            match.AcquireReaderLock(transaction);
            if (match.RowState == System.Data.DataRowState.Deleted || match.RowState == System.Data.DataRowState.Detached)
            {
                match.ReleaseReaderLock(transaction.TransactionId);
                return(false);
            }
            consumerDebtNegotiationRows  = match.GetConsumerDebtNegotiationRows();
            consumerTrustNegotiationRows = match.GetConsumerTrustNegotiationRows();
            contraMatch = DataModel.Match.MatchKey.Find(match.ContraMatchId);
            match.ReleaseReaderLock(transaction.TransactionId);

            if (contraMatch == null)
            {
                return(false);
            }

            foreach (ConsumerDebtNegotiationRow row in consumerDebtNegotiationRows)
            {
                row.AcquireReaderLock(transaction);
                if (row.RowState == System.Data.DataRowState.Deleted || row.RowState == System.Data.DataRowState.Detached)
                {
                    row.ReleaseReaderLock(transaction.TransactionId);
                    continue;
                }

                int settlements = row.GetConsumerDebtSettlementRows().Length;
                row.ReleaseReaderLock(transaction.TransactionId);
                if (settlements != 0)
                {
                    return(true);
                }
            }

            foreach (ConsumerTrustNegotiationRow row in consumerTrustNegotiationRows)
            {
                row.AcquireReaderLock(transaction);
                if (row.RowState == System.Data.DataRowState.Deleted || row.RowState == System.Data.DataRowState.Detached)
                {
                    row.ReleaseReaderLock(transaction.TransactionId);
                    continue;
                }

                int settlements = row.GetConsumerTrustSettlementRows().Length;
                row.ReleaseReaderLock(transaction.TransactionId);
                if (settlements != 0)
                {
                    return(true);
                }
            }

            if (checkContra)
            {
                return(IsSettled(transaction, contraMatch, false));
            }
            else
            {
                return(false);
            }
        }
        /// <summary>Inserts a Negotiation record using Metadata Parameters.</summary>
        internal static void Offer(Guid matchId, Decimal quantity)
        {
            Guid      negotiationId = Guid.Empty;
            DataModel dataModel     = new DataModel();

            try
            {
                DataModel.DataLock.EnterReadLock();

                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
                if (matchRow != null)
                {
                    // Rule #1: Insure that there are no pending offers.
                    foreach (NegotiationRow innerNegotiationRow in matchRow.GetNegotiationRows())
                    {
                        if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending))
                        {
                            throw new Exception("There is already an offer pending.");
                        }

                        if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Declined))
                        {
                            throw new Exception("This offer has previously been declined.");
                        }
                    }

                    // Time stamps and user stamps
                    Guid     createdUserId  = TradingSupport.UserId;
                    DateTime createdTime    = DateTime.UtcNow;
                    Guid     modifiedUserId = TradingSupport.UserId;
                    DateTime modifiedTime   = createdTime;

                    // This will find the contra matching record.
                    MatchRow contraMatchRow = DataModel.Match.MatchKeyWorkingOrderIdContraOrderId.Find(
                        new Object[] { matchRow.ContraOrderId, matchRow.WorkingOrderId });
                    if (contraMatchRow == null)
                    {
                        throw new Exception(
                                  string.Format("Corruption: the match record for {0}, {1} can't be found", matchRow.ContraOrderId, matchRow.WorkingOrderId));
                    }

                    // This is the order on the other side of the match.
                    WorkingOrderRow contraWorkingOrderRow = contraMatchRow.WorkingOrderRow;

                    // When both sides have agreed to the Negotiation, the Destination Orders are generated.
                    NegotiationRow contraNegotiationRow = null;
                    foreach (NegotiationRow innerNegotiationRow in contraMatchRow.GetNegotiationRows())
                    {
                        if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending))
                        {
                            contraNegotiationRow = innerNegotiationRow;
                            break;
                        }
                    }

                    // This means that there's an offer on the other side.
                    if (contraNegotiationRow == null)
                    {
                        // There is no opposite side of this transaction yet.  It will be placed in the negotation table and wait there
                        // until it times out, or the other side accepts the offer.
                        negotiationId = Guid.NewGuid();
                        dataModel.CreateNegotiation(
                            contraWorkingOrderRow.BlotterId,
                            null,
                            false,
                            contraMatchRow.MatchId,
                            negotiationId,
                            quantity,
                            StatusMap.FromCode(Status.Pending));
                    }
                    else
                    {
                        // At this point, there is an offer on both sides of the match for a follow-on order.  We'll create orders and
                        // executions for both sides of the trade for the minimum agreed upon quantity.
                        WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow;
                        WorkingOrderRow contraOrderRow  = contraNegotiationRow.MatchRow.WorkingOrderRow;

                        // The quantity of this negotiation will be the minimum of the two offers.
                        decimal matchedQuantity = quantity < contraNegotiationRow.Quantity ? quantity : contraNegotiationRow.Quantity;

                        // Create the order on this side of the trade.
                        Guid destinationOrderId = Guid.NewGuid();
                        dataModel.CreateDestinationOrder(
                            workingOrderRow.BlotterId,
                            null,
                            null,
                            createdTime,
                            createdUserId,
                            destinationId,
                            destinationOrderId,
                            null,
                            null,
                            null,
                            null,
                            workingOrderRow[DataModel.WorkingOrder.LimitPriceColumn],
                            modifiedTime,
                            modifiedUserId,
                            matchedQuantity,
                            workingOrderRow.OrderTypeId,
                            workingOrderRow.SecurityId,
                            modifiedTime,
                            workingOrderRow.SettlementId,
                            workingOrderRow.SideId,
                            StateMap.FromCode(State.Acknowledged),
                            StatusMap.FromCode(Status.New),
                            workingOrderRow[DataModel.WorkingOrder.StopPriceColumn],
                            workingOrderRow.TimeInForceId,
                            modifiedTime,
                            null,
                            workingOrderRow.WorkingOrderId);

                        // The the trade is executed at the current price.
                        PriceRow priceRow = DataModel.Price.PriceKey.Find(workingOrderRow.SecurityId, workingOrderRow.SettlementId);

                        // Create the Execution for this side of the trade.
                        Guid executionId = Guid.NewGuid();
                        dataModel.CreateExecution(
                            null,
                            workingOrderRow.BlotterId,
                            null,
                            null,
                            null,
                            createdTime,
                            createdUserId,
                            destinationOrderId,
                            StateMap.FromCode(State.Acknowledged),
                            executionId,
                            priceRow.LastPrice,
                            matchedQuantity,
                            null,
                            null,
                            null,
                            modifiedTime,
                            modifiedUserId,
                            null,
                            null,
                            null,
                            null,
                            StateMap.FromCode(State.Sent),
                            null,
                            null,
                            null,
                            null);

                        // There is no opposite side of this transaction yet.  It will be placed in the negotation table and wait there
                        // until it times out, or the other side accepts the offer.
                        negotiationId = Guid.NewGuid();
                        dataModel.CreateNegotiation(
                            workingOrderRow.BlotterId,
                            executionId,
                            false,
                            matchId,
                            negotiationId,
                            quantity,
                            StatusMap.FromCode(Status.Accepted));

                        // Create an order for the agreed upon quantity.
                        // Create the order on this side of the trade.
                        Guid contraDestinationOrderId = Guid.NewGuid();
                        dataModel.CreateDestinationOrder(
                            contraWorkingOrderRow.BlotterId,
                            null,
                            null,
                            createdTime,
                            createdUserId,
                            destinationId,
                            contraDestinationOrderId,
                            null,
                            null,
                            null,
                            null,
                            contraWorkingOrderRow[DataModel.WorkingOrder.LimitPriceColumn],
                            modifiedTime,
                            modifiedUserId,
                            matchedQuantity,
                            contraWorkingOrderRow.OrderTypeId,
                            contraWorkingOrderRow.SecurityId,
                            modifiedTime,
                            contraWorkingOrderRow.SettlementId,
                            contraWorkingOrderRow.SideId,
                            StateMap.FromCode(State.Acknowledged),
                            StatusMap.FromCode(Status.New),
                            contraWorkingOrderRow[DataModel.WorkingOrder.StopPriceColumn],
                            contraWorkingOrderRow.TimeInForceId,
                            modifiedTime,
                            null,
                            contraWorkingOrderRow.WorkingOrderId);

                        // Create the Execution for this side of the trade.
                        Guid contraExecutionId = Guid.NewGuid();
                        dataModel.CreateExecution(
                            null,
                            contraWorkingOrderRow.BlotterId,
                            null,
                            null,
                            null,
                            createdTime,
                            createdUserId,
                            contraDestinationOrderId,
                            StateMap.FromCode(State.Acknowledged),
                            contraExecutionId,
                            priceRow.LastPrice,
                            matchedQuantity,
                            null,
                            null,
                            null,
                            modifiedTime,
                            modifiedUserId,
                            null,
                            null,
                            null,
                            null,
                            StateMap.FromCode(State.Sent),
                            null,
                            null,
                            null,
                            null);

                        // Update the contra offer.
                        dataModel.UpdateNegotiation(
                            contraWorkingOrderRow.BlotterId,
                            contraExecutionId,
                            false,
                            null,
                            null,
                            new Object[] { contraNegotiationRow.NegotiationId },
                            null,
                            contraNegotiationRow.RowVersion,
                            StatusMap.FromCode(Status.Accepted));
                    }
                }
            }
            finally
            {
                // Release the tables.
                DataModel.DataLock.ExitReadLock();
            }
        }
        internal static void Decline(Guid matchId)
        {
            Guid negotiationId = Guid.Empty;
            long rowVersion    = long.MinValue;

            DataModel dataModel = new DataModel();

            try
            {
                DataModel.DataLock.EnterReadLock();

                // This context is used to keep track of the locks aquired for the ancillary data.
                TransactionScope     transactionScope     = new TransactionScope();
                DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
                if (matchRow != null)
                {
                    WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow;

                    // See if there is already a pending offer.
                    bool isFound = false;
                    foreach (NegotiationRow innerNegotiationRow in matchRow.GetNegotiationRows())
                    {
                        if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Declined))
                        {
                            throw new Exception("This offer has previously been declined.");
                        }

                        if (innerNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending))
                        {
                            // Call the internal method to complete the operation.
                            rowVersion    = innerNegotiationRow.RowVersion;
                            negotiationId = innerNegotiationRow.NegotiationId;
                            dataModel.UpdateNegotiation(
                                null,
                                null,
                                false,
                                null,
                                null,
                                new Object[] { negotiationId },
                                null,
                                rowVersion,
                                StatusMap.FromCode(Status.Declined));
                            isFound = true;
                        }
                    }

                    // Call the internal method to complete the operation.
                    if (!isFound)
                    {
                        negotiationId = Guid.NewGuid();
                        dataModel.CreateNegotiation(workingOrderRow.BlotterId,
                                                    null,
                                                    false,
                                                    matchId,
                                                    negotiationId,
                                                    0.0m,
                                                    StatusMap.FromCode(Status.Declined));
                    }

                    // If there's a counter offer, then notify the couter part that the offer has been declined. This will find the contra matching record.
                    MatchRow contraMatchRow = DataModel.Match.MatchKeyWorkingOrderIdContraOrderId.Find(
                        new object[] { matchRow.ContraOrderId, matchRow.WorkingOrderId });
                    if (contraMatchRow == null)
                    {
                        throw new Exception(string.Format("Corruption: the match record for {0}, {1} can't be found", matchRow.ContraOrderId, matchRow.WorkingOrderId));
                    }

                    // When both sides have agreed to the Negotiation, the Destination Orders are generated.
                    foreach (NegotiationRow contraNegotiationRow in contraMatchRow.GetNegotiationRows())
                    {
                        if (contraNegotiationRow.StatusId == StatusMap.FromCode(Status.Pending))
                        {
                            dataModel.UpdateNegotiation(
                                null,
                                null,
                                false,
                                null,
                                null,
                                new Object[] { contraNegotiationRow.NegotiationId },
                                null,
                                contraNegotiationRow.RowVersion,
                                StatusMap.FromCode(Status.Declined));
                        }
                    }
                }
            }
            finally
            {
                // Release the tables.
                DataModel.DataLock.ExitReadLock();
            }
        }
Example #26
0
        /// <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>
        /// Evaluates whether a given working order is eligible for a cross with another order.
        /// </summary>
        /// <param name="key">The key of the object to be handled.</param>
        /// <param name="parameters">A generic list of paraneters to the handler.</param>
        public static void MergeDocument(Object[] key, params Object[] parameters)
        {
            // Extract the strongly typed variables from the generic parameters.
            Guid consumerDebtSettlementId = (Guid)key[0];

            // This structure will collect the information required for the merge operation.
            MergeInfo mergeInfo = new MergeInfo();

            mergeInfo.ConsumerDebtSettlementId = consumerDebtSettlementId;

            // An instance of the data model is required for CRUD operations.
            DataModel dataModel = new DataModel();

            // If two counterparties agree on a transaction then a settlement report is generated from the Word Template associated with the Consumer Debt
            // Entity.
            using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew, TimeSpan.FromHours(1)))
            {
                // This provides a context for any transactions.
                DataModelTransaction dataModelTransaction = DataModelTransaction.Current;

                // It is important to minimize the locking for these transactions since they will drag the system performance down and create deadlock
                // sitiations if too many are held for too long.
                BlotterRow blotterRow = null;
                ConsumerDebtSettlementRow  consumerDebtSettlementRow  = null;
                ConsumerDebtNegotiationRow consumerDebtNegotiationRow = null;
                MatchRow        matchRow        = null;
                CreditCardRow   creditCardRow   = null;
                WorkingOrderRow workingOrderRow = null;

                try
                {
                    // The ConsumerDebtSettlement row is where the search for the Settlement Information begins.
                    consumerDebtSettlementRow = DataModel.ConsumerDebtSettlement.ConsumerDebtSettlementKey.Find(consumerDebtSettlementId);
                    consumerDebtSettlementRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // There is no need to generate a report on a settlement that isn't new.  This will momentarily lock the status table so we
                    // can see if the settlement is new.
                    try
                    {
                        consumerDebtSettlementRow.StatusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        if (consumerDebtSettlementRow.StatusRow.StatusCode != Status.New)
                        {
                            return;
                        }
                    }
                    finally
                    {
                        consumerDebtSettlementRow.StatusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The RowVersion is needed to update the record with the new PDF report.
                    mergeInfo.RowVersion = consumerDebtSettlementRow.RowVersion;

                    // The negotiation row contains the link to the base matching row.
                    consumerDebtNegotiationRow = consumerDebtSettlementRow.ConsumerDebtNegotiationRow;
                    consumerDebtNegotiationRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // The base matching row is where we'll find the working order.
                    matchRow = consumerDebtNegotiationRow.MatchRow;
                    matchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // The working order row is where the blotter can be found.
                    workingOrderRow = matchRow.WorkingOrderRow;
                    workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // And the blotter will lead us to the Entity hierarchy which is where we'll find the rules.
                    blotterRow = workingOrderRow.BlotterRow;
                    blotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // The 'Pending' status is applied to the Settlement after the letter has been generated.  The status needs to be picked up while we're
                    // still locking and reading tables.
                    StatusRow statusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.Pending);
                    try
                    {
                        statusRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                        mergeInfo.StatusId = statusRow.StatusId;
                    }
                    finally
                    {
                        statusRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    //Find the consumerDebt to find the credit Card to get the origianl creditor
                    ConsumerTrustNegotiationRow trustNegotiation = null;
                    MatchRow contraWorMatchRow = DataModel.Match.MatchKey.Find(matchRow.ContraMatchId);
                    contraWorMatchRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    try
                    {
                        trustNegotiation = contraWorMatchRow.GetConsumerTrustNegotiationRows()[0];
                    }
                    finally
                    {
                        if (contraWorMatchRow != null)
                        {
                            contraWorMatchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }

                    //Consumer Debt Row
                    trustNegotiation.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    try
                    {
                        creditCardRow = trustNegotiation.CreditCardRow;
                    }
                    finally
                    {
                        if (trustNegotiation != null)
                        {
                            trustNegotiation.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }


                    creditCardRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                    // There is only going to be one Debt Class record associated with this blotter, but the iteration is an easier construct to work with than
                    // the equivalent array logic for a single element.
                    foreach (DebtClassRow debtClassRow in blotterRow.GetDebtClassRows())
                    {
                        // This variable will keep track of our current location as we crawl up the hierarchy.  It is important to release the records as soon
                        // as possible to reduce the likelyhood of a deadlock.
                        DebtClassRow currentDebtClassRow = debtClassRow;
                        DebtClassRow nextDebtClassRow    = null;

                        // This flag will be set when a Debt Class in the hierarchy contains a Debt Rule.
                        Boolean isFound = false;

                        // This will crawl up the hierarchy until a Debt Class is found with a rule.  This rule will provide the opening values for the bid on
                        // this negotiation.
                        do
                        {
                            try
                            {
                                // This will lock the current item in the hierarchy so it can be examined for a rule or, failing that, a parent element.
                                currentDebtClassRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                // If the current Debt Class has no rule then the Entity Hierarchy is used to find the parent element.
                                if (currentDebtClassRow.IsSettlementTemplateNull())
                                {
                                    // The entity is the root of all objects in the hierarchy.  From this object the path to the parent Debt Class can be
                                    // navigated.
                                    EntityRow entityRow = DataModel.Entity.EntityKey.Find(currentDebtClassRow.DebtClassId);

                                    try
                                    {
                                        // Each entity needs to be locked before the relation can be used.
                                        entityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                        // This will find each relation in the hierarchy which uses the current node as a child.
                                        foreach (EntityTreeRow entityTreeRow in entityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ChildId())
                                        {
                                            try
                                            {
                                                // Lock the relation down before navigating to the parent.
                                                entityTreeRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                                // This is the parent entity of the current entity in the crawl up the hierarchy.
                                                EntityRow parentEntityRow = entityTreeRow.EntityRowByFK_Entity_EntityTree_ParentId;

                                                try
                                                {
                                                    // The parent entity must be locked befor it can be checked for blotters and then, in turn, debt
                                                    // classes.
                                                    parentEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                                    // In practice, there will be zero or one blotter rows.  The iteration makes it easier to check both
                                                    // conditions.
                                                    foreach (BlotterRow parentBlotterRow in parentEntityRow.GetBlotterRows())
                                                    {
                                                        try
                                                        {
                                                            // The blotter must be locked before iterating through the Debt Classes that may be associated
                                                            // with the blotter.
                                                            parentBlotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

                                                            // Each blotter can have zero or one Debt Classes associated with it.  This is a long an
                                                            // tortuous way to finally get to the parent Debt Class.
                                                            foreach (DebtClassRow parentDebtClassRow in parentBlotterRow.GetDebtClassRows())
                                                            {
                                                                try
                                                                {
                                                                    // Now that we've finally found the parent Debt Class, it will become the parent on the
                                                                    // next pass through the hierarchy.  Note that the locks are released each time we pass
                                                                    // through a level of the hierarchy.
                                                                    parentDebtClassRow.AcquireReaderLock(
                                                                        dataModelTransaction.TransactionId,
                                                                        DataModel.LockTimeout);
                                                                    nextDebtClassRow = parentDebtClassRow;
                                                                }
                                                                finally
                                                                {
                                                                    // The locks are released after the parent Debt Class is found.
                                                                    parentDebtClassRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                                                }
                                                            }
                                                        }
                                                        finally
                                                        {
                                                            // The locks are released after the each level of the hierarchy is checked.
                                                            parentBlotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                                        }
                                                    }
                                                }
                                                finally
                                                {
                                                    // The parent Entity record is released after each level of the hiearchy is examined for a parent.
                                                    parentEntityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                                }
                                            }
                                            finally
                                            {
                                                // The relationship record is released after each level of the hierarchy is examined for a parent.
                                                entityTreeRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                            }
                                        }
                                    }
                                    finally
                                    {
                                        // Finaly, the current entity is released.  This allows us to finally move on to the next level of the hierarchy
                                        // without having to hold the locks for the entire transaction.
                                        entityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                    }
                                }
                                else
                                {
                                    // The template has been found and converted back to a Microsoft Word template.
                                    mergeInfo.SourceDocument = Convert.FromBase64String(currentDebtClassRow.SettlementTemplate);

                                    // This will cause the loop to exit.
                                    isFound = true;
                                }
                            }
                            finally
                            {
                                // The current Debt Class can be released.  At this point, every record that was locked to read the hiearchy has been
                                // released and the loop can either exit (when a rule is found) or move on to the parent Debt Class.
                                currentDebtClassRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                            }

                            // Now that all the locks are released, the parent Debt Class becomes the current one for the next level up in the hierarchy.
                            // This algorithm will keep on climbing through the levels until a rule is found or the hierarchy is exhausted.
                            currentDebtClassRow = nextDebtClassRow;
                        } while (isFound == false && currentDebtClassRow != null);
                    }

                    // AccountBalance
                    mergeInfo.Dictionary.Add(
                        "AccountBalance",
                        String.Format("{0:$#,##0.00}",
                                      consumerDebtSettlementRow.AccountBalance));

                    // CreatedDate
                    mergeInfo.Dictionary.Add("CreatedDate", consumerDebtSettlementRow.CreatedTime);

                    // Original Creditor
                    mergeInfo.Dictionary.Add(
                        "DebtHolder",
                        creditCardRow.IsDebtHolderNull() ? null : creditCardRow.DebtHolder);

                    // DebtorAccountNumber
                    mergeInfo.Dictionary.Add(
                        "DebtorAccountNumber",
                        consumerDebtSettlementRow.IsDebtorAccountNumberNull() ? null : consumerDebtSettlementRow.DebtorAccountNumber);

                    // DebtorBankAccountNumber
                    mergeInfo.Dictionary.Add(
                        "DebtorBankAccountNumber",
                        consumerDebtSettlementRow.IsDebtorBankAccountNumberNull() ? null : consumerDebtSettlementRow.DebtorBankAccountNumber);

                    // DebtorBankRoutingNumber
                    mergeInfo.Dictionary.Add(
                        "DebtorBankRoutingNumber",
                        consumerDebtSettlementRow.IsDebtorBankRoutingNumberNull() ? null : consumerDebtSettlementRow.DebtorBankRoutingNumber);

                    // DebtorAddress1
                    mergeInfo.Dictionary.Add(
                        "DebtorAddress1",
                        consumerDebtSettlementRow.IsDebtorAddress1Null() ? null : consumerDebtSettlementRow.DebtorAddress1);

                    // DebtorAddress2
                    mergeInfo.Dictionary.Add(
                        "DebtorAddress2",
                        consumerDebtSettlementRow.IsDebtorAddress2Null() ? null : consumerDebtSettlementRow.DebtorAddress2);

                    // DebtorCity
                    mergeInfo.Dictionary.Add(
                        "DebtorCity",
                        consumerDebtSettlementRow.IsDebtorCityNull() ? null : consumerDebtSettlementRow.DebtorCity);

                    // DebtorFirstName
                    mergeInfo.Dictionary.Add(
                        "DebtorFirstName",
                        consumerDebtSettlementRow.IsDebtorFirstNameNull() ? null : consumerDebtSettlementRow.DebtorFirstName);

                    // DebtorLastName
                    mergeInfo.Dictionary.Add(
                        "DebtorLastName",
                        consumerDebtSettlementRow.IsDebtorLastNameNull() ? null : consumerDebtSettlementRow.DebtorLastName);

                    // DebtorMiddleName
                    mergeInfo.Dictionary.Add(
                        "DebtorMiddleName",
                        consumerDebtSettlementRow.IsDebtorMiddleNameNull() ? null : consumerDebtSettlementRow.DebtorMiddleName);

                    // DebtorOriginalAccountNumber
                    mergeInfo.Dictionary.Add(
                        "DebtorOriginalAccountNumber",
                        consumerDebtSettlementRow.DebtorOriginalAccountNumber);

                    // DebtorPostalCode
                    mergeInfo.Dictionary.Add(
                        "DebtorPostalCode",
                        consumerDebtSettlementRow.IsDebtorPostalCodeNull() ? null : consumerDebtSettlementRow.DebtorPostalCode);

                    // DebtorProvince
                    String debtorProvince = null;
                    if (!consumerDebtSettlementRow.IsDebtorProvinceIdNull())
                    {
                        ProvinceRow provinceRow = consumerDebtSettlementRow.ProvinceRowByFK_Province_ConsumerDebtSettlement_DebtorProvinceId;
                        try
                        {
                            provinceRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            debtorProvince = provinceRow.Abbreviation;
                        }
                        finally
                        {
                            provinceRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }
                    mergeInfo.Dictionary.Add("DebtorProvinceAbbreviation", debtorProvince);

                    // DebtorSalutation
                    mergeInfo.Dictionary.Add(
                        "DebtorSalutation",
                        consumerDebtSettlementRow.IsDebtorSalutationNull() ? null : consumerDebtSettlementRow.DebtorSalutation);

                    // DebtorSuffix
                    mergeInfo.Dictionary.Add(
                        "DebtorSuffix",
                        consumerDebtSettlementRow.IsDebtorSuffixNull() ? null : consumerDebtSettlementRow.DebtorSuffix);


                    // PayeeAddress1
                    mergeInfo.Dictionary.Add(
                        "PayeeAddress1",
                        consumerDebtSettlementRow.IsPayeeAddress1Null() ? null : consumerDebtSettlementRow.PayeeAddress1);

                    // PayeeAddress2
                    mergeInfo.Dictionary.Add(
                        "PayeeAddress2",
                        consumerDebtSettlementRow.IsPayeeAddress2Null() ? null : consumerDebtSettlementRow.PayeeAddress2);

                    // PayeeCity
                    mergeInfo.Dictionary.Add(
                        "PayeeCity",
                        consumerDebtSettlementRow.IsPayeeCityNull() ? null : consumerDebtSettlementRow.PayeeCity);

                    // PayeeCompanyName
                    mergeInfo.Dictionary.Add(
                        "PayeeCompanyName",
                        consumerDebtSettlementRow.IsPayeeCompanyNameNull() ? null : consumerDebtSettlementRow.PayeeCompanyName);

                    // PayeeContactName
                    mergeInfo.Dictionary.Add(
                        "PayeeContactName",
                        consumerDebtSettlementRow.IsPayeeContactNameNull() ? null : consumerDebtSettlementRow.PayeeContactName);

                    // PayeeDepartment
                    mergeInfo.Dictionary.Add(
                        "PayeeDepartment",
                        consumerDebtSettlementRow.IsPayeeDepartmentNull() ? null : consumerDebtSettlementRow.PayeeDepartment);

                    // PayeeEmail
                    mergeInfo.Dictionary.Add(
                        "PayeeEmail",
                        consumerDebtSettlementRow.IsPayeeEmailNull() ? null : consumerDebtSettlementRow.PayeeEmail);

                    // PayeeFax
                    mergeInfo.Dictionary.Add(
                        "PayeeFax",
                        consumerDebtSettlementRow.IsPayeeFaxNull() ? null : consumerDebtSettlementRow.PayeeFax);

                    // PayeeForBenefitOf
                    mergeInfo.Dictionary.Add(
                        "PayeeForBenefitOf",
                        consumerDebtSettlementRow.IsPayeeForBenefitOfNull() ? null : consumerDebtSettlementRow.PayeeForBenefitOf);

                    // PayeePhone
                    mergeInfo.Dictionary.Add(
                        "PayeePhone",
                        consumerDebtSettlementRow.IsPayeePhoneNull() ? null : consumerDebtSettlementRow.PayeePhone);

                    // PayeePostalCode
                    mergeInfo.Dictionary.Add(
                        "PayeePostalCode",
                        consumerDebtSettlementRow.IsPayeePostalCodeNull() ? null : consumerDebtSettlementRow.PayeePostalCode);

                    // PayeeProvince
                    String payeeProvince = null;
                    if (!consumerDebtSettlementRow.IsPayeeProvinceIdNull())
                    {
                        ProvinceRow provinceRow = consumerDebtSettlementRow.ProvinceRowByFK_Province_ConsumerDebtSettlement_PayeeProvinceId;
                        try
                        {
                            provinceRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            payeeProvince = provinceRow.Abbreviation;
                        }
                        finally
                        {
                            provinceRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }
                    mergeInfo.Dictionary.Add("PayeeProvinceAbbreviation", payeeProvince);

                    // PaymentLength
                    mergeInfo.Dictionary.Add("PaymentLength", consumerDebtSettlementRow.PaymentLength);

                    // PaymentStartDate
                    mergeInfo.Dictionary.Add("PaymentStartDate", consumerDebtSettlementRow.PaymentStartDate.ToLocalTime().ToLongDateString());

                    // PayeeBankAccountNumber
                    mergeInfo.Dictionary.Add(
                        "PayeeBankAccountNumber",
                        consumerDebtSettlementRow.IsPayeeBankAccountNumberNull() ? null : consumerDebtSettlementRow.PayeeBankAccountNumber);

                    // PayeeBankRoutingNumber
                    mergeInfo.Dictionary.Add(
                        "PayeeBankRoutingNumber",
                        consumerDebtSettlementRow.IsPayeeBankRoutingNumberNull() ? null : consumerDebtSettlementRow.PayeeBankRoutingNumber);

                    // SettlementAmount
                    mergeInfo.Dictionary.Add("SettlementAmount", consumerDebtSettlementRow.SettlementAmount);

                    // SettlementPercent
                    mergeInfo.Dictionary.Add("SettlementPercent", consumerDebtSettlementRow.SettlementAmount / consumerDebtSettlementRow.AccountBalance);

                    // TermPaymentAmount
                    mergeInfo.Dictionary.Add("TermPaymentAmount", consumerDebtSettlementRow.SettlementAmount / consumerDebtSettlementRow.PaymentLength);

                    // The payment methods is modeled as a vector which makes it difficult to add as a single merge field.  To work around this, each of the
                    // possible payment methods are described in the data dictionary using the form 'Is{PaymentMethodName}'.  The Word Merge process should look for
                    // the presence of these fields to generate a block of text for the instructions for each of the payment methods.  This iteration will
                    // collect all the possible payment method types in an array and assume that they don't exist (i.e. set them to a Boolean value of 'false')
                    // until they're found in the settlement instructions.
                    foreach (PaymentMethodTypeRow paymentMethodTypeRow in DataModel.PaymentMethodType)
                    {
                        try
                        {
                            paymentMethodTypeRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            mergeInfo.Dictionary.Add(String.Format("Is{0}", paymentMethodTypeRow.Name.Replace(" ", String.Empty)), false);
                        }
                        finally
                        {
                            paymentMethodTypeRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }

                    // This iteration will cycle through all the payment methods in the settlement and set them to be true.  The result is a dictionary of all
                    // possible payment methods with the ones included in this settlement set to be the Boolean value of 'true'.
                    foreach (ConsumerDebtSettlementPaymentMethodRow consumerDebtSettlementPaymentMethodRow in
                             consumerDebtSettlementRow.GetConsumerDebtSettlementPaymentMethodRows())
                    {
                        try
                        {
                            // Each of the payment methods in the settlement are modeled as a list that is associated with the settlement.  This will lock each
                            // of the items in the list in turn and examine the parent 'PaymentMethodType' record to construct a mail-merge tag.
                            consumerDebtSettlementPaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            PaymentMethodTypeRow paymentMethodTypeRow = DataModel.PaymentMethodType.PaymentMethodTypeKey.Find(
                                consumerDebtSettlementPaymentMethodRow.PaymentMethodTypeId);

                            try
                            {
                                // Once the parent MethodType is found a tag is added to the dictionary.  The presence of the 'Is<PaymentMethodType>' item in
                                // the dictionary means that the given payment method is acceptable for this settlement.
                                paymentMethodTypeRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                                mergeInfo.Dictionary[String.Format("Is{0}", paymentMethodTypeRow.Name.Replace(" ", String.Empty))] = true;
                            }
                            finally
                            {
                                // The parent payment method type row is not needed any longer.
                                paymentMethodTypeRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                            }
                        }
                        finally
                        {
                            // Release the payment method row.
                            consumerDebtSettlementPaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                        }
                    }
                }
                finally
                {
                    // The CreditCardRow is no longer needed.
                    if (creditCardRow != null && creditCardRow.IsReaderLockHeld(dataModelTransaction.TransactionId))
                    {
                        creditCardRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The ConsumerDebtSettlementRow is no longer needed.
                    if (consumerDebtSettlementRow != null)
                    {
                        consumerDebtSettlementRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The ConsumerDebtNegotiation Row is no longer needed.
                    if (consumerDebtNegotiationRow != null)
                    {
                        consumerDebtNegotiationRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The MatchRow is no longer needed.
                    if (matchRow != null)
                    {
                        matchRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The WorkingOrderRow is no longer needed.
                    if (workingOrderRow != null)
                    {
                        workingOrderRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }

                    // The BlotterRow is no longer needed.
                    if (blotterRow != null)
                    {
                        blotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }
                }

                MemoryStream memoryStream = null;

                try
                {
                    // At this point, all the data has been collected and the record locks released.  It is time to merge the document.
                    memoryStream = SettlementDocumentFactory.iMailMerge.CreateDocument(mergeInfo.SourceDocument, mergeInfo.Dictionary);
                }
                catch (Exception exception)
                {
                    EventLog.Error("There was a problem creating the settlement letter. \n Details: {0}, {1}", exception.Message, exception.StackTrace);
                }

                if (memoryStream != null)
                {
                    // Update the settlement with the newly generated PFD file.
                    dataModel.UpdateConsumerDebtSettlement(
                        null,
                        null,
                        null,
                        null,
                        new Object[] { consumerDebtSettlementId },
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        mergeInfo.RowVersion,
                        null,
                        Convert.ToBase64String(memoryStream.ToArray()),
                        mergeInfo.StatusId);
                }

                // If we reached here the transaction was successful.
                transactionScope.Complete();
            }
        }
Example #28
0
        internal static void Accept(Guid matchId, Int64 rowVersion)
        {
            DataModel dataModel = new DataModel();

            try
            {
                DataModel.DataLock.EnterReadLock();

                MatchRow matchRow = DataModel.Match.MatchKey.Find(matchId);
                if (matchRow != null)
                {
                    // Time stamps and user stamps
                    Guid     createdUserId  = TradingSupport.UserId;
                    DateTime createdTime    = DateTime.UtcNow;
                    Guid     modifiedUserId = createdUserId;
                    DateTime modifiedTime   = createdTime;

                    // Call the internal method to complete the operation.
                    dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { matchRow.MatchId }, rowVersion, StatusMap.FromCode(Status.Accepted), null);

                    // This is the working order associated with the match.
                    WorkingOrderRow workingOrderRow = matchRow.WorkingOrderRow;

                    // This will find the contra order.
                    MatchRow contraMatchRow = DataModel.Match.MatchKeyWorkingOrderIdContraOrderId.Find(
                        matchRow.ContraOrderId,
                        matchRow.WorkingOrderId);
                    if (contraMatchRow == null)
                    {
                        throw new Exception(string.Format("Corruption: the match record for {0}, {1} can't be found", matchRow.ContraOrderId, matchRow.WorkingOrderId));
                    }

                    // When both sides have agreed to the match, the Destination Orders are generated.
                    if (contraMatchRow.StatusId != StatusMap.FromCode(Status.Accepted))
                    {
                        return;
                    }

                    // At this point, both sides have agreed to a trade.  This is the working order of the contra side of the trade.
                    WorkingOrderRow contraOrderRow = contraMatchRow.WorkingOrderRow;

                    // The quantity of this transaction is the lesser of the two sides of the trade.
                    decimal quantity = workingOrderRow.SubmittedQuantity < contraOrderRow.SubmittedQuantity ?
                                       workingOrderRow.SubmittedQuantity :
                                       contraOrderRow.SubmittedQuantity;

                    PriceRow priceRow = DataModel.Price.PriceKey.Find(workingOrderRow.SecurityId, workingOrderRow.SettlementId);
                    if (priceRow == null)
                    {
                        throw new Exception("The price of this trade can't be determined.");
                    }

                    Guid destinationOrderId = Guid.NewGuid();
                    dataModel.CreateDestinationOrder(
                        workingOrderRow.BlotterId,
                        null,
                        null,
                        createdTime,
                        createdUserId,
                        Match.destinationId,
                        destinationOrderId,
                        null,
                        null,
                        false,
                        false,
                        workingOrderRow[DataModel.WorkingOrder.LimitPriceColumn],
                        modifiedTime,
                        modifiedUserId,
                        quantity,
                        workingOrderRow.OrderTypeId,
                        workingOrderRow.SecurityId,
                        createdTime,
                        workingOrderRow.SettlementId,
                        workingOrderRow.SideId,
                        StateMap.FromCode(State.Acknowledged),
                        StatusMap.FromCode(Status.New),
                        workingOrderRow[DataModel.WorkingOrder.StopPriceColumn],
                        workingOrderRow.TimeInForceId,
                        createdTime,
                        createdUserId,
                        workingOrderRow.WorkingOrderId);

                    Guid executionId = Guid.NewGuid();
                    dataModel.CreateExecution(
                        0.0m,
                        workingOrderRow.BlotterId,
                        null,
                        null,
                        0.0m,
                        createdTime,
                        createdUserId,
                        destinationOrderId,
                        StateMap.FromCode(State.Acknowledged),
                        executionId,
                        priceRow.LastPrice,
                        quantity,
                        null,
                        null,
                        false,
                        modifiedTime,
                        modifiedUserId,
                        null,
                        null,
                        null,
                        null,
                        StateMap.FromCode(State.Sent),
                        null,
                        null,
                        null,
                        null);

                    dataModel.UpdateMatch(null, null, null, null, null, null, null, new Object[] { matchId }, matchRow.RowVersion, StatusMap.FromCode(Status.Accepted), null);

                    Guid contraDestinationOrderId = Guid.NewGuid();
                    dataModel.CreateDestinationOrder(
                        contraOrderRow.BlotterId,
                        0.0m,
                        null,
                        createdTime,
                        createdUserId,
                        Match.destinationId,
                        contraDestinationOrderId,
                        null,
                        null,
                        false,
                        false,
                        contraOrderRow[DataModel.WorkingOrder.LimitPriceColumn],
                        modifiedTime,
                        modifiedUserId,
                        quantity,
                        contraOrderRow.OrderTypeId,
                        contraOrderRow.SecurityId,
                        createdTime,
                        contraOrderRow.SettlementId,
                        contraOrderRow.SideId,
                        StateMap.FromCode(State.Acknowledged),
                        StatusMap.FromCode(Status.New),
                        contraOrderRow[DataModel.WorkingOrder.StopPriceColumn],
                        contraOrderRow.TimeInForceId,
                        createdTime,
                        createdUserId,
                        contraOrderRow.WorkingOrderId);

                    Guid contraExecutionId = Guid.NewGuid();
                    dataModel.CreateExecution(
                        0.0m,
                        contraOrderRow.BlotterId,
                        null,
                        null,
                        0.0m,
                        createdTime,
                        createdUserId,
                        contraDestinationOrderId,
                        StateMap.FromCode(State.Acknowledged),
                        contraExecutionId,
                        priceRow.LastPrice,
                        quantity,
                        null,
                        null,
                        false,
                        modifiedTime,
                        modifiedUserId,
                        null,
                        null,
                        null,
                        null,
                        StateMap.FromCode(State.Sent),
                        0.0m,
                        0.0m,
                        0.0m,
                        0.0m);
                }
            }
            finally
            {
                // Release the tables.
                DataModel.DataLock.ExitReadLock();
            }
        }
Example #29
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);
            }
        }
Example #30
0
        /// <summary>
        /// Determine whether we can automatically accept this negotiation and do so if possible.
        /// </summary>
        /// <param name="info">The notification information.</param>
        private void TryAutoSettle(NotificationInfo info)
        {
            Guid? negotiationId = null;

            lock (DataModel.SyncRoot)
            {

                MatchRow matchRow = DataModel.Match.MatchKey.Find(info.MatchId);
                DebtClassRow debtClassRow;
                Guardian.Windows.DebtRule debtRuleRow;

                if (matchRow == null)
                {

                    EventLog.Information("Match ('{0}') has been deleted before it could be auto-settled from the trust side", info.MatchId);
                    return;

                }

                debtClassRow = DataModel.DebtClass.DebtClassKey.Find(matchRow.WorkingOrderRow.BlotterId);

                if (debtClassRow == null)
                {

                    EventLog.Warning(
                        "The debt class that the match ('{0}') was in has been deleted before it could be auto-settled from the trust side",
                        info.MatchId);
                    return;

                }

                debtRuleRow =
                    Guardian.Windows.DebtClass.GetDebtRule(debtClassRow.DebtClassId, debtClassRow.BlotterRow.EntityRow.TypeId);

                if (debtRuleRow == null)
                {

                    EventLog.Error("Debt class ('{0}') or its parents does not have a debt rule", debtClassRow.DebtClassId);
                    return;

                }

                if (debtRuleRow.IsAutoSettled)
                {

                    ConsumerTrustNegotiationRow[] negotiationRows = matchRow.GetConsumerTrustNegotiationRows();
                    ConsumerTrustNegotiationRow negotiationRow;

                    // If, for whatever reason, there isn't exactly one negotiation row, log the error and bail.
                    if (negotiationRows.Length < 1)
                    {

                        EventLog.Error("Consumer trust match ('{0}') has no negotiation rows", info.MatchId, negotiationRows.Length);
                        return;

                    }

                    negotiationRow = negotiationRows[0];

                    foreach (ConsumerTrustNegotiationRow row in negotiationRows)
                        if (row.RowVersion > negotiationRow.RowVersion)
                            negotiationRow = row;

                    if (IsCashValueAcceptable(
                            negotiationRow.AccountBalance,
                            negotiationRow.CounterSettlementValue,
                            DataModel.SettlementUnit.SettlementUnitKey.Find(negotiationRow.CounterSettlementUnitId).SettlementUnitCode,
                            negotiationRow.OfferSettlementValue,
                            DataModel.SettlementUnit.SettlementUnitKey.Find(debtRuleRow.SettlementUnitId).SettlementUnitCode) &&
                        IsPaymentLengthAcceptable(
                            negotiationRow.CounterPaymentLength,
                            debtRuleRow.PaymentLength) &&
                        IsPaymentStartDateAcceptable(
                            negotiationRow.CounterPaymentStartDateLength,
                            negotiationRow.CounterPaymentStartDateUnitId,
                            negotiationRow.OfferPaymentStartDateLength,
                            negotiationRow.OfferPaymentStartDateUnitId) &&
                        ArePaymentTypesAcceptable(
                            negotiationRow.GetConsumerTrustNegotiationCounterPaymentMethodRows(),
                            negotiationRow.GetConsumerTrustNegotiationOfferPaymentMethodRows()))
                    {

                        negotiationId = negotiationRow.ConsumerTrustNegotiationId;

                    }

                }

            }

            if (negotiationId != null)
                this.AcceptSettlement(negotiationId.Value);
        }