/// <summary> /// Update the debt class information from a debt class row. /// </summary> /// <param name="debtClassRow">The row to update from.</param> protected void Update(DebtClassRow debtClassRow) { if (!this.Modified && this.DebtClassId == debtClassRow.DebtClassId) { this.DebtRuleId = debtClassRow.IsDebtRuleIdNull() ? null : (Guid?)debtClassRow.DebtRuleId; this.Address1 = debtClassRow.IsAddress1Null() ? null : debtClassRow.Address1; this.Address2 = debtClassRow.IsAddress2Null() ? null : debtClassRow.Address2; this.BankAccountNumber = debtClassRow.IsBankAccountNumberNull() ? null : debtClassRow.BankAccountNumber; this.BankRoutingNumber = debtClassRow.IsBankRoutingNumberNull() ? null : debtClassRow.BankRoutingNumber; this.City = debtClassRow.IsCityNull() ? null : debtClassRow.City; this.CompanyName = debtClassRow.IsCompanyNameNull() ? null : debtClassRow.CompanyName; this.ContactName = debtClassRow.IsContactNameNull() ? null : debtClassRow.ContactName; this.Department = debtClassRow.IsDepartmentNull() ? null : debtClassRow.Department; this.Email = debtClassRow.IsEmailNull() ? null : debtClassRow.Email; this.Fax = debtClassRow.IsFaxNull() ? null : debtClassRow.Fax; this.ForBenefitOf = debtClassRow.IsForBenefitOfNull() ? null : debtClassRow.ForBenefitOf; this.Phone = debtClassRow.IsPhoneNull() ? null : debtClassRow.Phone; this.Province = debtClassRow.IsProvinceIdNull() ? null : (Guid?)debtClassRow.ProvinceId; this.PostalCode = debtClassRow.IsPostalCodeNull() ? null : debtClassRow.PostalCode; this.SettlementTemplate = debtClassRow.IsSettlementTemplateNull() ? null : debtClassRow.SettlementTemplate; this.Modified = false; } this.rowVersion = debtClassRow.RowVersion; }
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); } } } }