Ejemplo n.º 1
0
        private void InitializeThread(object state)
        {
            // Extract the initialization parameters.
            Guid blotterId = (Guid)state;

            List <DestinationItem> destinationItems = new List <DestinationItem>();

            // Initialize the Destination list box
            try
            {
                Monitor.Enter(DataModel.SyncRoot);

                DataModel.Destination.DestinationRowChanged += new DestinationRowChangeEventHandler(Destination_DestinationRowChanged);

                BlotterRow blotterRow = DataModel.Blotter.BlotterKey.Find(blotterId);
                foreach (BlotterDestinationMapRow blotterDestinationRowMap in blotterRow.GetBlotterDestinationMapRows())
                {
                    DestinationRow destinationRow = blotterDestinationRowMap.DestinationRow;
                    destinationItems.Add(new DestinationItem(destinationRow.DestinationId, destinationRow.Name,
                                                             destinationRow.ShortName));
                }
            }
            finally
            {
                Monitor.Exit(DataModel.SyncRoot);
            }

            Invoke(new DestinationListDelegate(InitializeListBox), destinationItems);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Handles the end of merging data into the client side data model.
        /// </summary>
        /// <param name="sender">The object that originated the event.</param>
        /// <param name="eventArgs">The unused event arguments.</param>
        private void OnEndMerge(object sender, EventArgs eventArgs)
        {
            // If the hierarchy was changed then the list of blotters visible in this report needs to be evaluated and passed into
            // the filter.  Note that changing the hierarchy will also force a refresh of the report in the foreground giving it a
            // higher precendence than a normal data update.  Said differently, if the hierarchy has changed, the report will be
            // refreshed when the new filter is installed and there is no reason to call the refresh thread from here.
            if (this.isHierarchyChanged)
            {
                isHierarchyChanged = false;


                // This will recreate the list of blotters allowed into this report.  Note that the filter must be set in the
                // foreground once the hierarchy is expanded.
                List <Guid> blotterList = new List <Guid>();
                BlotterRow  blotterRow  = DataModel.Blotter.BlotterKey.Find(this.blotterId);
                if (blotterRow != null)
                {
                    ExpandBlotterRow(blotterList, blotterRow);
                }
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, this.setBlotterFilterHandler, blotterList);
            }
            else
            {
                // The content of the report is regenerated in a worker thread when the data related to this report has changed.  When
                // the content is regenerated, it will be sent to the foreground to be presented in the report.
                if (this.isDataChanged)
                {
                    FluidTrade.Core.ThreadPoolHelper.QueueUserWorkItem(RefreshThread, false);
                    this.isDataChanged = false;
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Count all of the working orders and matches in blotters below the parent entity. The caller should lock the DataModel.
        /// </summary>
        /// <param name="parent">The parent entity.</param>
        /// <param name="totalRecords">The total number of records. Should initially be 0.</param>
        /// <param name="matchedRecords">The number of of valid matches. Should initially be 0.</param>
        private void CountAccounts(EntityRow parent, ref int totalRecords, ref int matchedRecords)
        {
            BlotterRow blotter = DataModel.Blotter.BlotterKey.Find(parent.EntityId);

            if (blotter != null)
            {
                MatchRow[]        matches = blotter.GetMatchRows();
                WorkingOrderRow[] orders  = blotter.GetWorkingOrderRows();

                matchedRecords += matches.Length;

                // Count up the credit cards for everything.
                foreach (WorkingOrderRow order in orders)
                {
                    Guid             security = order.SecurityId;
                    ConsumerTrustRow trust    = DataModel.ConsumerTrust.ConsumerTrustKey.Find(security);

                    if (trust != null)
                    {
                        totalRecords += trust.ConsumerRow.GetCreditCardRows().Length;
                    }
                }
            }

            // Do the same for all of the blotters under this one.
            foreach (EntityTreeRow tree in DataModel.EntityTree)
            {
                if (tree.ParentId == parent.EntityId)
                {
                    this.CountAccounts(tree.EntityRowByFK_Entity_EntityTree_ChildId, ref totalRecords, ref matchedRecords);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Filter what rows are included in the list based on Filter.
        /// </summary>
        /// <param name="row">The row to examine.</param>
        /// <returns>The return value of Filter.</returns>
        protected override bool Filter(DataRow row)
        {
            BlotterRow blotterRow = null;

            if (row is BlotterRow)
            {
                blotterRow = row as BlotterRow;
            }
            else if (row is EntityRow)
            {
                EntityRow entityRow = row as EntityRow;
                if (entityRow.GetBlotterRows().Length != 0)
                {
                    blotterRow = entityRow.GetBlotterRows()[0];
                }
            }
            else
            {
                throw new RowNotHandledException("row isn't the right kind of row");
            }

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

            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// returns blotter row that is the parent folder of current location
        /// </summary>
        /// <param name="previousValues">previous values that define the current folder</param>
        /// <param name="defaultId">folder id to use if cannot find a match</param>
        /// <returns>blotterRow that is the parent</returns>
        private BlotterRow GetBlotterFolderParent(List <ReportParameterValue> previousValues, Guid defaultId)
        {
            //find the current blotter row
            BlotterRow blotterRow = null;

            if (previousValues != null &&
                previousValues.Count > 0)
            {
                blotterRow = previousValues[0].UserObject as BlotterRow;
            }

            if (blotterRow == null)
            {
                blotterRow = DataModel.Blotter.Rows.Find(defaultId) as BlotterRow;
            }

            //not blotter row return null
            if (blotterRow == null)
            {
                return(null);
            }

            //find the parent
            foreach (EntityTreeRow entityTreeRow in blotterRow.EntityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ChildId())
            {
                foreach (BlotterRow parentRow in entityTreeRow.EntityRowByFK_Entity_EntityTree_ParentId.GetBlotterRows())
                {
                    return(parentRow);
                }
            }

            //cant find a parent return
            return(null);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// fills in reportFillParamsArgs with the folders under the current folder
        /// </summary>
        /// <param name="defaultId">folder id to use if cannot find a match</param>
        /// <param name="reportFillParamsArgs">args to fill in</param>
        private void GetBlotterFolderChildren(Guid defaultId, ReportFillParameterEventArgs reportFillParamsArgs)
        {
            BlotterRow blotterRow = null;

            //get the current row out of the parentValue
            if (reportFillParamsArgs.ParentValues != null &&
                reportFillParamsArgs.ParentValues.Count != 0)
            {
                blotterRow = reportFillParamsArgs.ParentValues[0].UserObject as BlotterRow;
            }

            //if there is not row in parent use the default
            if (blotterRow == null)
            {
                blotterRow = DataModel.Blotter.Rows.Find(defaultId) as BlotterRow;
            }

            //no parent row return
            if (blotterRow == null)
            {
                return;
            }

            //get all the child blotter rows
            foreach (EntityTreeRow entityTreeRow in blotterRow.EntityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ParentId())
            {
                foreach (BlotterRow childRow in entityTreeRow.EntityRowByFK_Entity_EntityTree_ChildId.GetBlotterRows())
                {
                    reportFillParamsArgs.AddValue(new ReportParameterValue(childRow.BlotterId, childRow));
                }
            }
        }
Ejemplo n.º 7
0
 private void ExpandBlotterRow(List <Guid> blotterList, BlotterRow blotterRow)
 {
     blotterList.Add(blotterRow.EntityRow.EntityId);
     foreach (EntityTreeRow entityTreeRow in blotterRow.EntityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ParentId())
     {
         foreach (BlotterRow childRow in entityTreeRow.EntityRowByFK_Entity_EntityTree_ChildId.GetBlotterRows())
         {
             ExpandBlotterRow(blotterList, childRow);
         }
     }
 }
Ejemplo n.º 8
0
        private void ExpandBlotterId(Object state)
        {
            Guid        blotterId   = (Guid)state;
            List <Guid> blotterList = new List <Guid>();

            lock (DataModel.SyncRoot)
            {
                BlotterRow blotterRow = DataModel.Blotter.BlotterKey.Find(blotterId);
                if (blotterRow != null)
                {
                    ExpandBlotterRow(blotterList, blotterRow);
                }
            }

            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, this.setBlotterFilterHandler, blotterList);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Count all of the working orders and matches in blotters below the parent entity. The caller should lock the DataModel.
        /// </summary>
        /// <param name="parent">The parent entity.</param>
        /// <param name="orders">The total number of working orders. This should initially be 0.</param>
        /// <param name="matches">The total number of matches. This should initially be 0.</param>
        private void CountChildOrders(EntityRow parent, ref int orders, ref int matches)
        {
            BlotterRow blotter = DataModel.Blotter.BlotterKey.Find(parent.EntityId);

            if (blotter != null)
            {
                orders  += blotter.GetWorkingOrderRows().Count();
                matches += blotter.GetMatchRows().Count();
            }

            foreach (EntityTreeRow tree in DataModel.EntityTree)
            {
                if (tree.ParentId == parent.EntityId)
                {
                    this.CountChildOrders(tree.EntityRowByFK_Entity_EntityTree_ChildId, ref orders, ref matches);
                }
            }
        }
        /// <summary>
        /// Count all of the working orders and matches in blotters below the parent entity. The caller should lock the DataModel.
        /// </summary>
        /// <param name="parent">The parent entity.</param>
        /// <param name="matchedDollars">The total face value of the valid matches. Should initially be 0.0.</param>
        /// <param name="totalDollars">The total face value of all the records. Should initially be 0.0.</param>
        /// <param name="totalRecords">The total number of records. Should initially be 0.</param>
        /// <param name="matchedRecords">The number of of valid matches. Should initially be 0.</param>
        private void CountChildMoney(EntityRow parent, ref decimal matchedDollars, ref decimal totalDollars, ref int totalRecords, ref int matchedRecords)
        {
            BlotterRow blotter = DataModel.Blotter.BlotterKey.Find(parent.EntityId);

            if (blotter != null)
            {
                MatchRow[]        matches = blotter.GetMatchRows();
                WorkingOrderRow[] orders  = blotter.GetWorkingOrderRows();

                matchedRecords += matches.Length;
                totalRecords   += orders.Length;

                // Count up the match/match with funds credit card balances.
                foreach (MatchRow match in matches)
                {
                    if (match.StatusRow.StatusCode == Status.ValidMatch || match.StatusRow.StatusCode == Status.ValidMatchFunds)
                    {
                        Guid security = match.WorkingOrderRow.SecurityId;
                        matchedDollars += DataModel.ConsumerDebt.ConsumerDebtKey.Find(security).CreditCardRow.AccountBalance;
                    }
                }

                // Count up the credit card balances of _everything_, matched or not.
                foreach (WorkingOrderRow order in orders)
                {
                    Guid            security = order.SecurityId;
                    ConsumerDebtRow debt     = DataModel.ConsumerDebt.ConsumerDebtKey.Find(security);

                    if (debt != null)
                    {
                        totalDollars += debt.CreditCardRow.AccountBalance;
                    }
                }
            }

            // Do the same for all of the blotters under this one.
            foreach (EntityTreeRow tree in DataModel.EntityTree)
            {
                if (tree.ParentId == parent.EntityId)
                {
                    this.CountChildMoney(tree.EntityRowByFK_Entity_EntityTree_ChildId, ref matchedDollars, ref totalDollars, ref totalRecords, ref matchedRecords);
                }
            }
        }
Ejemplo n.º 11
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);
            }
        }
Ejemplo n.º 12
0
        public ConsumerTrustMatchInfo(DataModelTransaction dataModelTransaction, WorkingOrderRow workingOrderRow)
        {
            // Initialize the object
            this.PaymentMethodTypes = new List <Guid>();

            // These rows are required for navigating through the asset.  Locks are acquired temporarily for them and released as soon as the Consumer Debt
            // information is collected.
            BlotterRow       blotterRow       = null;
            SecurityRow      securityRow      = null;
            ConsumerTrustRow consumerTrustRow = null;

            // The working order row is where everything starts. This is the asset that is to be matched against another.
            workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);

            try
            {
                // The working order identifier is used when creating matches.
                this.WorkingOrderId = workingOrderRow.WorkingOrderId;
                // The underlying security is a Consumer Debt record.
                securityRow = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId;

                // The blotter row needs to be examined for this cross.
                blotterRow = workingOrderRow.BlotterRow;
            }
            finally
            {
                workingOrderRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
            }


            securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            try
            {
                consumerTrustRow = securityRow.GetConsumerTrustRows()[0];
            }
            finally
            {
                securityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
            }


            DebtRuleRow debtRuleRow = null;

            // This row contains the actual asset that is to be matched.
            consumerTrustRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            try
            {
                // The savings balance is used when calculating the status of the match (whether there is enough funds in the account).
                this.SavingsBalance = consumerTrustRow.SavingsBalance;

                if (consumerTrustRow.IsDebtRuleIdNull() == false)
                {
                    // At this point a rule override was found on an asset and there's no need to search the Entity hierarchy.
                    debtRuleRow = consumerTrustRow.DebtRuleRow;
                }
            }
            finally
            {
                consumerTrustRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
            }

            // This will attempt to find the debt rule associated with this credit card.  If there is no rule explicitly associated with the asset,
            // then the entity hierarchy is searched until a debt class is found that contains a rule.  When the rule is found, the values in that rule
            // will become the opening bid.
            DebtClassRow[] blotterRowDebtClassRows = null;
            blotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
            try
            {
                // The blotter is required for adding matches to the data model once they are found.
                this.BlotterId = blotterRow.BlotterId;

                if (debtRuleRow == null)
                {
                    blotterRowDebtClassRows = blotterRow.GetDebtClassRows();
                }
            }
            finally
            {
                blotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
            }

            if (debtRuleRow == null)
            {
                // At this point, the asset hasn't got an explicit rule, so the hierarchy will need to be searched.  There is only going to be one Debt
                // Class element 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 blotterRowDebtClassRows)
                {
                    // This variable will keep track of our current location as we crawl up the hierarchy.
                    DebtClassRow currentDebtClassRow = debtClassRow;
                    DebtClassRow nextDebtClassRow    = null;

                    // 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
                    {
                        // 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);
                        Guid currentDebtClassRowDebtClassId;
                        try
                        {
                            currentDebtClassRowDebtClassId = currentDebtClassRow.DebtClassId;
                            if (currentDebtClassRow.IsDebtRuleIdNull() == false)
                            {
                                // At this point we have finally found a debt rule that can be used to start the negotiations.
                                debtRuleRow = currentDebtClassRow.DebtRuleRow;
                            }
                        }
                        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);
                        }
                        // If the current Debt Class has no rule then the Entity Hierarchy is used to find the parent element.
                        if (debtRuleRow == null)
                        {
                            EntityTreeRow[] entityTreeRows;
                            // 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(currentDebtClassRowDebtClassId);

                            // Each entity needs to be locked before the relation can be used.
                            entityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                            try
                            {
                                entityTreeRows = entityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ChildId();
                            }
                            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);
                            }

                            // This will find each relation in the hierarchy which uses the current node as a child.
                            foreach (EntityTreeRow entityTreeRow in entityTreeRows)
                            {
                                EntityRow parentEntityRow;
                                // Lock the relation down before navigating to the parent.
                                entityTreeRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                                try
                                {
                                    // This is the parent entity of the current entity in the crawl up the hierarchy.
                                    parentEntityRow = entityTreeRow.EntityRowByFK_Entity_EntityTree_ParentId;
                                }
                                finally
                                {
                                    // The relationship record is released after each level of the hierarchy is examined for a parent.
                                    entityTreeRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                }

                                BlotterRow[] blotterRows;
                                // 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);
                                try
                                {
                                    blotterRows = parentEntityRow.GetBlotterRows();
                                }
                                finally
                                {
                                    // The parent Entity record is released after each level of the hiearchy is examined for a parent.
                                    parentEntityRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                }


                                // In practice, there will be zero or one blotter rows.  The iteration makes it easier to check both
                                // conditions.
                                foreach (BlotterRow parentBlotterRow in blotterRows)
                                {
                                    DebtClassRow[] parentBlotterRowDebtClassRows;
                                    // The blotter must be locked before iterating through the Debt Classes that may be associated
                                    // with the blotter.
                                    parentBlotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                                    try
                                    {
                                        parentBlotterRowDebtClassRows = parentBlotterRow.GetDebtClassRows();
                                    }
                                    finally
                                    {
                                        // The locks are released after the each level of the hierarchy is checked.
                                        parentBlotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                                    }

                                    // 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 parentBlotterRowDebtClassRows)
                                    {
                                        // 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.
                                        nextDebtClassRow = parentDebtClassRow;
                                    }
                                }
                            }
                        }

                        // 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(debtRuleRow == null && currentDebtClassRow != null);
                }
            }

            // The data is copied out of the Debt Rule when one is found in the Entity hierarchy.
            if (debtRuleRow != null)
            {
                DebtRulePaymentMethodRow[] debtRuleRowDebtRulePaymentMethodRows;
                // At this point we found a rule that can be used for the opening bid of a settlement.
                debtRuleRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                try
                {
                    // These values are used in the opening bid of a negotiated settlement.
                    this.PaymentLength          = debtRuleRow.PaymentLength;
                    this.PaymentStartDateLength = debtRuleRow.PaymentStartDateLength;
                    this.PaymentStartDateUnitId = debtRuleRow.PaymentStartDateUnitId;
                    this.SettlementValue        = debtRuleRow.SettlementValue;
                    this.SettlementUnitId       = debtRuleRow.SettlementUnitId;

                    debtRuleRowDebtRulePaymentMethodRows = debtRuleRow.GetDebtRulePaymentMethodRows();
                }
                finally
                {
                    // A lock on the Debt Rule is no longer required.
                    debtRuleRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                }


                // This will copy each of the payment methods that are available for this settlement.  Note that the table rows are locked only long
                // enough to acquire the item, then released.
                foreach (DebtRulePaymentMethodRow debtRulePaymentMethodRow in debtRuleRowDebtRulePaymentMethodRows)
                {
                    debtRulePaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout);
                    try
                    {
                        this.PaymentMethodTypes.Add(debtRulePaymentMethodRow.PaymentMethodTypeId);
                    }
                    finally
                    {
                        debtRulePaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId);
                    }
                }
            }
        }
        /// <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();
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// fill in the Report Parameters. Will fill in the path information.
        /// At this point the path information is mostly blotter based. Assuming that
        /// the tree are blotters. This can be changed to be entity based, but some
        /// keys/relations are missing to make the entity lookup efficient
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="defaultId">defualt Id to be used if cannot find match</param>
        /// <param name="dataRow">dataRow that is the current item row</param>
        /// <param name="reportFillParamsArgs">args to be filled in</param>
        public void ReportFillParams(object sender, Guid defaultId, System.Data.DataRow dataRow, ReportFillParameterEventArgs reportFillParamsArgs)
        {
            //trying to keep this generic, but for now folders are == blotters

            switch (reportFillParamsArgs.PathType)
            {
            case PathType.FolderRoot:    //Position cursor to the root folder
            {
                //walk up parents until the parent is null
                BlotterRow blotterRow = null;
                if (reportFillParamsArgs.ParentValues != null &&
                    reportFillParamsArgs.ParentValues.Count > 0)
                {
                    blotterRow = reportFillParamsArgs.ParentValues[0].UserObject as BlotterRow;
                }

                if (blotterRow == null)
                {
                    blotterRow = DataModel.Blotter.Rows.Find(defaultId) as BlotterRow;
                }
                ;

                BlotterRow nextBlotterRow = blotterRow;
                while (nextBlotterRow != null)
                {
                    nextBlotterRow = GetBlotterFolderParent(reportFillParamsArgs.ParentValues, defaultId);

                    if (nextBlotterRow == null || nextBlotterRow == blotterRow)
                    {
                        break;
                    }

                    blotterRow = nextBlotterRow;
                }

                //found the root
                if (blotterRow != null)
                {
                    reportFillParamsArgs.AddValue(new ReportParameterValue(blotterRow.BlotterId, blotterRow));
                }

                break;
            }

            case PathType.FolderParent:
            {
                //position cursor to the parent folder of the current location
                BlotterRow blotterRow = GetBlotterFolderParent(reportFillParamsArgs.ParentValues, defaultId);

                if (blotterRow != null)
                {
                    reportFillParamsArgs.AddValue(new ReportParameterValue(blotterRow.BlotterId, blotterRow));
                }

                break;
            }

            case PathType.SelectedItem:
            {
                //position cursor to selectedItem. will use the
                //PK of that dataRow to define the value of the selected item
                if (dataRow != null &&
                    dataRow.Table.PrimaryKey != null &&
                    dataRow.Table.PrimaryKey.Length == 1)
                {
                    reportFillParamsArgs.AddValue(new ReportParameterValue(dataRow[dataRow.Table.PrimaryKey[0]], null));
                }
                else
                {
                    System.Data.DataRow blotterRow = DataModel.Blotter.Rows.Find(defaultId);
                    reportFillParamsArgs.AddValue(new ReportParameterValue(defaultId, blotterRow));
                }
                break;
            }

            case PathType.SelectedFolder:
            {
                //position cursor to the Folder of the selected item
                System.Data.DataRow blotterRow = DataModel.Blotter.Rows.Find(defaultId);
                reportFillParamsArgs.AddValue(new ReportParameterValue(defaultId, blotterRow));

                break;
            }

            case PathType.CursorFolder:
            {
                //return the Folder that the cursor is at
                if (reportFillParamsArgs.ParentValues != null &&
                    reportFillParamsArgs.ParentValues.Count != 0)
                {
                    reportFillParamsArgs.AddValue(reportFillParamsArgs.ParentValues[0]);
                }

                break;
            }

            case PathType.CursorChildFolders:
            {
                //return the child folders under the cursor position
                GetBlotterFolderChildren(defaultId, reportFillParamsArgs);
                break;
            }
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Create working orders.
        /// </summary>
        /// <param name="sender">The generic thread initialization parameter.</param>
        public static void CreateOrders(object state)
        {
            GenerateTradeInfo generateTradeInfo = state as GenerateTradeInfo;

            // Create a random number generator with about as random a number as possible.
            Random random = new Random(DateTime.Now.TimeOfDay.Milliseconds);

            XDocument xDocument = new XDocument();

            lock (DataModel.SyncRoot)
            {
                // This is the selected blotter for the orders.
                BlotterRow blotterRow = DataModel.Blotter.BlotterKey.Find(generateTradeInfo.BlotterId);
                if (blotterRow == null)
                {
                    throw new Exception(String.Format("Blotter {0} not found", generateTradeInfo.BlotterId));
                }

                // This is the current user creating the orders.
                UserRow userRow = DataModel.User.UserKey.Find(Information.UserId);
                if (userRow == null)
                {
                    throw new Exception("The current user isn't mapped to a database user.");
                }

                CountryRow countryRow = DataModel.Country.CountryKeyExternalId0.Find("US");
                if (countryRow == null)
                {
                    throw new Exception("The country isn't part of the database.");
                }

                //<script name="Automatically Generated Orders">
                XElement elementRoot = new XElement("script", new XAttribute("name", "Automatically Generated Orders"));
                xDocument.Add(elementRoot);

                //  <client name="DataModelClient" type="DataModelClient, Client Data Model" endpoint="TcpDataModelEndpoint" />
                elementRoot.Add(
                    new XElement("client",
                                 new XAttribute("name", "DataModelClient"),
                                 new XAttribute("type", "DataModelClient, Client Data Model"),
                                 new XAttribute("endpoint", "TcpDataModelEndpoint")));

                for (int index = 0; index < generateTradeInfo.OrderCount; index++)
                {
                    //  <transaction>
                    XElement elementTransaction = new XElement("transaction");
                    elementRoot.Add(elementTransaction);

                    // Generate a working order identifier.
                    Guid workingOrderId = Guid.NewGuid();

                    // Generate the status of the new order.
                    StatusRow statusRow = DataModel.Status.StatusKeyStatusCode.Find(Status.New);

                    // Generate a random US Fixed Income Instrument.
                    SecurityRow securityRow           = null;
                    SecurityRow settlementCurrencyRow = null;
                    while (true)
                    {
                        // Select a random equity.
                        DebtRow debtRow = DataModel.Debt[random.Next(DataModel.Debt.Count - 1)];
                        securityRow = debtRow.SecurityRowByFK_Security_Debt_DebtId;

                        // Generate the settlement currency
                        EntityRow usdEntityRow = DataModel.Entity.EntityKeyExternalId0.Find("USD");
                        settlementCurrencyRow = DataModel.Security.SecurityKey.Find(usdEntityRow.EntityId);

                        PriceRow priceRow = DataModel.Price.PriceKey.Find(securityRow.SecurityId, settlementCurrencyRow.SecurityId);
                        if (priceRow != null)
                        {
                            break;
                        }
                    }

                    // Generate the side for the order.
                    Side    side    = random.Next(2) == 0 ? Side.Buy : Side.Sell;
                    SideRow sideRow = DataModel.Side.SideKeySideCode.Find(side);

                    // Generate the time in force for this order.
                    TimeInForceRow timeInForceRow = DataModel.TimeInForce.TimeInForceKeyTimeInForceCode.Find(TimeInForce.GoodTillCancel);

                    // Generate trade and settlement dates.
                    DateTime tradeDate      = DateTime.Now;
                    DateTime settlementDate = DateTime.Now;
                    for (int dayIndex = 0; dayIndex < 3; dayIndex++)
                    {
                        settlementDate += TimeSpan.FromDays(1.0);
                        if (settlementDate.DayOfWeek == DayOfWeek.Saturday)
                        {
                            settlementDate += TimeSpan.FromDays(1.0);
                        }
                        if (settlementDate.DayOfWeek == DayOfWeek.Sunday)
                        {
                            settlementDate += TimeSpan.FromDays(1.0);
                        }
                    }

                    // Generate matching selections.
                    Boolean isBrokerMatch      = random.Next(10) == 0;
                    Boolean isHedgeMatch       = random.Next(5) == 0;
                    Boolean isInstitutionMatch = true;
                    if (random.Next(5) == 0)
                    {
                        isBrokerMatch      = true;
                        isHedgeMatch       = true;
                        isInstitutionMatch = true;
                    }
                    if (random.Next(10) == 0)
                    {
                        isBrokerMatch      = false;
                        isHedgeMatch       = false;
                        isInstitutionMatch = false;
                    }

                    // Generate a submission type for crossing.
                    Crossing    crossing    = Crossing.NeverMatch;
                    CrossingRow crossingRow = DataModel.Crossing.CrossingKeyCrossingCode.Find(crossing);

                    //    <method name="CreateWorkingOrderEx" client="DataModelClient">
                    XElement elementWorkingOrder = new XElement(
                        "method",
                        new XAttribute("name", "CreateWorkingOrderEx"),
                        new XAttribute("client", "DataModelClient"));
                    elementTransaction.Add(elementWorkingOrder);

                    //      <parameter name="blotterKey" value="TONY DE SILVA BLOTTER" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "blotterKey"),
                                     new XAttribute("value", blotterRow.EntityRow.ExternalId0)));

                    //      <parameter name="configurationId" value="CUSIP" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "configurationId"),
                                     new XAttribute("value", "CUSIP")));

                    //      <parameter name="createdTime" value="5/26/2006 11:57:19 AM" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "createdTime"),
                                     new XAttribute("value", DateTime.Now.ToString("G"))));

                    //      <parameter name="crossingKey" value="ALWAYS" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "crossingKey"),
                                     new XAttribute("value", crossingRow.ExternalId0)));

                    //      <parameter name="externalId0" value="{fed508fb-b2a9-44df-8aa9-760f43a5d768}" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "externalId0"),
                                     new XAttribute("value", workingOrderId.ToString("B"))));

                    //      <parameter name="isBrokerMatch" value="True" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "isBrokerMatch"),
                                     new XAttribute("value", isBrokerMatch)));

                    //      <parameter name="isHedgeMatch" value="True" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "isHedgeMatch"),
                                     new XAttribute("value", isHedgeMatch)));

                    //      <parameter name="isInstitutionMatch" value="True" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "isInstitutionMatch"),
                                     new XAttribute("value", isInstitutionMatch)));

                    //      <parameter name="modifiedTime" value="5/26/2006 11:57:19 AM" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "modifiedTime"),
                                     new XAttribute("value", DateTime.Now.ToString("G"))));

                    //      <parameter name="orderTypeKey" value="MKT" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "orderTypeKey"),
                                     new XAttribute("value", "MKT")));

                    //      <parameter name="securityKeyBySecurityId" value="LMT" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "securityKeyBySecurityId"),
                                     new XAttribute("value", securityRow.EntityRow.ExternalId4)));

                    //      <parameter name="securityKeyBySettlementId" value="USD" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "securityKeyBySettlementId"),
                                     new XAttribute("value", settlementCurrencyRow.EntityRow.ExternalId0)));

                    //		<parameter name="settlementDate" value="3/31/2008 10:00:00 AM" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "settlementDate"),
                                     new XAttribute("value", settlementDate.ToString("G"))));

                    //      <parameter name="sideKey" value="BUY" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "sideKey"),
                                     new XAttribute("value", sideRow.ExternalId0)));

                    //      <parameter name="statusKey" value="PARTIALFILL" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "statusKey"),
                                     new XAttribute("value", statusRow.ExternalId0)));

                    //      <parameter name="timeInForceKey" value="DAY" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "timeInForceKey"),
                                     new XAttribute("value", timeInForceRow.ExternalId0)));

                    //		<parameter name="tradeDate" value="3/28/2008 10:00:00 AM" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "tradeDate"),
                                     new XAttribute("value", tradeDate.ToString("G"))));

                    //      <parameter name="userKeyByCreatedUserId" value="TONY DE SILVA" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "userKeyByCreatedUserId"),
                                     new XAttribute("value", userRow.EntityRow.ExternalId0)));

                    //      <parameter name="userKeyByModifiedUserId" value="TONY DE SILVA" />
                    elementWorkingOrder.Add(
                        new XElement("parameter",
                                     new XAttribute("name", "userKeyByModifiedUserId"),
                                     new XAttribute("value", userRow.EntityRow.ExternalId0)));

                    // Most working orders have only a single source order but occationally they are blocked together and
                    // allocated as a single ticket.
                    Int32 sourceOrderCount = random.Next(6) == 0 ? random.Next(4) + 1 : 1;
                    for (int sourceOrderIndex = 0; sourceOrderIndex < sourceOrderCount; sourceOrderIndex++)
                    {
                        // Generate the source order identifier.
                        Guid sourceOrderId = Guid.NewGuid();

                        // Generate the quantity of this order.
                        Decimal orderedQuantity = Convert.ToDecimal(random.Next(1, 100)) * 100.0M;
                        if (orderedQuantity == 0.0M)
                        {
                            throw new Exception("The Quantity is zero!!");
                        }

                        //    <method name="CreateSourceOrderEx" client="DataModelClient">
                        XElement elementSourceOrder = new XElement(
                            "method",
                            new XAttribute("name", "CreateSourceOrderEx"),
                            new XAttribute("client", "DataModelClient"));
                        elementTransaction.Add(elementSourceOrder);

                        //      <parameter name="blotterKey" value="TONY DE SILVA BLOTTER" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "blotterKey"),
                                         new XAttribute("value", blotterRow.EntityRow.ExternalId0)));

                        //      <parameter name="configurationId" value="CUSIP" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "configurationId"),
                                         new XAttribute("value", "CUSIP")));

                        //      <parameter name="createdTime" value="5/26/2006 11:57:19 AM" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "createdTime"),
                                         new XAttribute("value", DateTime.Now)));

                        //      <parameter name="externalId0" value="{3d289495-9c66-4582-b50f-3548c8c260f1}" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "externalId0"),
                                         new XAttribute("value", sourceOrderId.ToString("B"))));

                        //      <parameter name="modifiedTime" value="5/26/2006 11:57:19 AM" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "modifiedTime"),
                                         new XAttribute("value", DateTime.Now.ToString("G"))));

                        //      <parameter name="orderedQuantity" value="4300.0000000" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "orderedQuantity"),
                                         new XAttribute("value", orderedQuantity)));

                        //      <parameter name="orderTypeKey" value="MKT" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "orderTypeKey"),
                                         new XAttribute("value", "MKT")));

                        //      <parameter name="securityKeyBySecurityId" value="LMT" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "securityKeyBySecurityId"),
                                         new XAttribute("value", securityRow.EntityRow.ExternalId4)));

                        //      <parameter name="securityKeyBySettlementId" value="USD" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "securityKeyBySettlementId"),
                                         new XAttribute("value", settlementCurrencyRow.EntityRow.ExternalId0)));

                        //		<parameter name="settlementDate" value="3/31/2008 10:00:00 AM" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "settlementDate"),
                                         new XAttribute("value", settlementDate)));

                        //      <parameter name="sideKey" value="BUY" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "sideKey"),
                                         new XAttribute("value", sideRow.ExternalId0)));

                        //      <parameter name="statusKey" value="PARTIALFILL" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "statusKey"),
                                         new XAttribute("value", statusRow.ExternalId0)));
                        //      <parameter name="timeInForceKey" value="DAY" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "timeInForceKey"),
                                         new XAttribute("value", timeInForceRow.ExternalId0)));

                        //		<parameter name="tradeDate" value="3/28/2008 10:00:00 AM" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "tradeDate"),
                                         new XAttribute("value", tradeDate.ToString("G"))));

                        //      <parameter name="userKeyByCreatedUserId" value="TONY DE SILVA" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "userKeyByCreatedUserId"),
                                         new XAttribute("value", userRow.EntityRow.ExternalId0)));

                        //      <parameter name="userKeyByModifiedUserId" value="TONY DE SILVA" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "userKeyByModifiedUserId"),
                                         new XAttribute("value", userRow.EntityRow.ExternalId0)));

                        //      <parameter name="workingOrderKey" value="{fed508fb-b2a9-44df-8aa9-760f43a5d768}" />
                        elementSourceOrder.Add(
                            new XElement("parameter",
                                         new XAttribute("name", "workingOrderKey"),
                                         new XAttribute("value", workingOrderId.ToString("B"))));
                    }
                }

                // Fill out the file name with a default directory and an extension if they are required before saving the
                // generated orders.
                String fileName = generateTradeInfo.FileName;
                if (!Path.IsPathRooted(fileName))
                {
                    fileName = Path.Combine(Environment.ExpandEnvironmentVariables(FixedIncomeOrders.DefaultDirectory), fileName);
                }
                if (!Path.HasExtension(fileName))
                {
                    fileName = Path.ChangeExtension(fileName, FixedIncomeOrders.DefaultFileExtension);
                }
                xDocument.Save(fileName);
            }
        }