Skip to content

Calculations

Obligation and Balance Calculations

Scheduled Monthly Payment Amount

Field 13: Scheduled Monthly Payment Amount

This field represents the regular payment amount due.

Calculation:

IF snapshot.loan_status IN ('ChargedOff', 'PaidOff'):
  scheduled_payment = 0
ELIF lender_supplied_account_status = '97':  # ChargedOff
  scheduled_payment = 0
ELSE:
  # Get current period obligation
  obligation = find_obligation_in_period(month_start, month_end)
  IF obligation:
    scheduled_payment = obligation.obligation_amount
  ELSE:
    scheduled_payment = 0

RETURN round_to_whole_dollars(scheduled_payment)

Amount Past Due

Field 22: Amount Past Due

This field reports the total amount that is past due on the account.

Calculation:

FUNCTION calculate_amount_past_due(loan, snapshot, lender_supplied_status):
  # Priority 1: Paid-in-full statuses always report zero
  IF lender_supplied_status IN ('61', '62', '63'):  # Paid in full statuses
    RETURN 0
  
  # Priority 2: Voluntary Surrender when account is current
  IF lender_supplied_status = '95' AND account_is_current:
    RETURN 0
  
  # Priority 3: Based on loan status
  IF snapshot.loan_status IN ('Active', 'Frozen'):
    amount_past_due = snapshot.overdue_over_30_days_balance_total_amount
  
  ELIF snapshot.loan_status IN ('Accelerated', 'ChargedOff'):
    amount_past_due = snapshot.outstanding_balance_total_amount
  
  ELIF snapshot.loan_status IN ('Pending', 'Originated', 'Declined', 'PaidOff', 'Canceled'):
    amount_past_due = 0
  
  ELSE:
    RAISE ERROR "Unknown loan status"
  
  RETURN round_to_whole_dollars(max(amount_past_due, 0))

Logic Explanation:

Loan StatusAmount Past Due SourceRationale
Active, Frozenoverdue_over_30_days_balance_total_amountOnly amounts 30+ days past due are reported
Accelerated, ChargedOffoutstanding_balance_total_amountEntire balance is considered past due
PaidOff, Canceled, Pending, Originated, Declined0No amount past due

Override Conditions:

ConditionResultCRRG Requirement
Status 61, 62, 63 (Paid in Full)Always 0"Requires Current Balance and Amount Past Due = zero"
Status 95 (Voluntary Surrender) + Account Current0Account surrendered before becoming delinquent

Current Balance

Field 21: Current Balance

Data Source: snapshot.outstanding_balance_total_amount

Components:

  • Principal balance
  • Accrued interest
  • Outstanding fees

Special Rules:

  • For status codes 13, 61, 62, 63: Always report $0
  • Negative balances: Report as $0
  • Round according to loan type configuration

Transaction Types and Payment Calculations

Overview

The Actual Payment Amount field (Field 17) requires understanding which transactions count as "payments" for credit reporting purposes.

Transaction Types

Transaction TypeDescription
PaymentConsumer payment (AutoPay, OneTimePayment, Settlement)
ServiceCreditLender-applied credit adjustment

Service Credit Types

Credit TypeReports as Payment?Description
serviceAgent[YES]Agent-applied credit
serviceSupervisor[YES]Supervisor-approved credit
balanceTransfer[YES]Balance transferred from another account
usuryCap[YES]Usury cap adjustment
settlementOfDebt[NO]Settlement credit (considered a loss)
fraud[NO]Fraud adjustment credit (considered a loss)
badDebt[NO]Bad debt write-off credit (considered a loss)
deceased[NO]Deceased borrower adjustment (considered a loss)
bankruptcy[NO]Bankruptcy adjustment (special Account Status handling)
refund[NO]Refund (always excluded)
interestAdjustment[NO]Interest adjustment (always excluded)
rewards[YES]Rewards credit (e.g., cashback applied to balance)
rounding[NO]Rounding adjustment (always excluded)
rewards[YES]Rewards credit (e.g., cashback applied to balance)

Important: Service credits with types settlementOfDebt, settlementOfDebtNoLoss, fraud, badDebt, deceased, and bankruptcy are NOT considered "real" payments for Actual Payment Amount or Date of Last Payment calculations.

Of those, only settlementOfDebt, fraud, badDebt, and deceased are also treated as "loss" transactions for Account Status determination — their presence prevents a charged-off loan from reporting as status 64 (Paid in Full). settlementOfDebtNoLoss is explicitly excluded from the loss check — it is the variant for settlement scenarios where the lender does not want a loss recorded, allowing a 64 outcome.

bankruptcy is also excluded from the loss check because it is the mechanism for zeroing a balance after a bankruptcy discharge and does not by itself force a 97 status. See Account Status Codes for the full algorithm.

The bankruptcy service credit type should only be used when a bankruptcy case has been discharged and the lender needs to zero the loan balance.

Actual Payment Amount Algorithm

FUNCTION calculate_actual_payment_amount(loan, month_start, month_end):
  
  total_payment = 0
  
  # Query payments in the reporting period
  transactions = query_transactions(
    loan_id = loan.id,
    is_virtual = False,
    status IN ('Initiated', 'Pending', 'Succeeded'),
    display_date BETWEEN month_start AND month_end
  )
  
  # Also include transactions that failed AFTER the report cutoff
  # (they were valid at the time of reporting)
  transactions += query_transactions(
    loan_id = loan.id,
    status = 'Failed',
    failed_at > file_creation_max_datetime,
    initiated_or_pending_at BETWEEN file_creation_min_datetime AND file_creation_max_datetime
  )
  
  FOR EACH tx IN transactions:
    
    # Payment transactions
    IF tx.transaction_type = 'Payment':
      IF tx.payment_reason IN ('AutoPay', 'OneTimePayment', 'Settlement'):
        total_payment += tx.effective_amount
    
    # Service credits - ONLY these four types count as "real" payments
    IF tx.transaction_type = 'ServiceCredit':
      IF tx.credit_type IN ('serviceAgent', 'serviceSupervisor', 'balanceTransfer', 'usuryCap'):
        total_payment += tx.effective_amount
  
  RETURN round_to_whole_dollars(total_payment)

Date of Last Payment

Field 27: Date of Last Payment

Returns the date of the most recent qualifying transaction (same inclusion criteria as Actual Payment Amount):

FUNCTION get_date_of_last_payment(loan, date_of_account_info):
  
  # Find most recent payment transaction
  payment_tx = query_most_recent_transaction(
    loan_id = loan.id,
    transaction_type = 'Payment',
    payment_reason IN ('AutoPay', 'OneTimePayment', 'Settlement'),
    status IN ('Initiated', 'Pending', 'Succeeded'),
    display_date <= date_of_account_info,
    is_virtual = False
  )
  
  # Find most recent qualifying service credit
  service_tx = query_most_recent_transaction(
    loan_id = loan.id,
    transaction_type = 'ServiceCredit',
    credit_type IN ('serviceAgent', 'serviceSupervisor', 'balanceTransfer', 'usuryCap'),
    status IN ('Initiated', 'Pending', 'Succeeded'),
    display_date <= date_of_account_info,
    is_virtual = False
  )
  
  # Return the most recent of the two
  IF payment_tx AND service_tx:
    RETURN max(payment_tx.display_date, service_tx.display_date)
  ELIF payment_tx:
    RETURN payment_tx.display_date
  ELIF service_tx:
    RETURN service_tx.display_date
  ELSE:
    RETURN NULL

> **Note:** The implementation combines these two lookups into a single query for efficiency, but the logic is equivalent.

Note: The implementation combines these two lookups into a single query for efficiency, but the logic is equivalent.

Loan Replay and Retroactive Changes

What is Loan Replay?

Loan replay is the process of recalculating a loan's history when:

  • Interest rates change retroactively
  • Payments are backdated
  • Errors are corrected

Impact on Credit Reporting

When a loan is replayed:

  • Previous Metro 2 files remain unchanged (already submitted)
  • Next Metro 2 file reflects corrected current state
  • Payment History Profile may show different values for past months

Terminal Reporting Events

When Reporting Stops — Key Change

BEFORE (Old Logic):

IF loan_status = 'ChargedOff' AND chargedOffReason = 'bankruptcy':
  → Report loan for the LAST time (stop immediately)

AFTER (New Logic - Matches Spec):

IF loan_status = 'ChargedOff' AND outstanding_balance = 0:
  → Report loan for the LAST time (stop when balance reaches zero)

Key Difference: Previously, bankruptcy charge-offs stopped reporting immediately regardless of balance. Now, all charge-offs (including bankruptcy) continue reporting until the balance reaches $0.

When Reporting Stops

Credit reporting stops (terminal event) when:

ConditionFinal StatusBehavior
Loan paid off13Report once with status 13, then stop
Loan charged off with zero balance AND no service credit transaction types (settlementOfDebt, fraud, badDebt, deceased)64Report once with status 64, then stop
Loan charged off with zero balance BUT has service credit transaction types (settlementOfDebt, fraud, badDebt, deceased)97Report with status 97 (loss occurred)
Bankruptcy charge-off with balance97Continue reporting until balance reaches zero
Bankruptcy charge-off, balance reaches zero (no loss service credits)64Report once with status 64, then stop
Fraudulent charge-offDFSend deletion, then stop
Legal deletionDASend deletion, then stop
Loan data corruptedDASend deletion, then stop

Service Credit Transaction Types Indicating Loss: Service credits of type settlementOfDebt, fraud, badDebt, or deceased indicate the lender took a loss. If any of these were used to bring the balance to zero, the account reports status 97 instead of 64.

Bankruptcy Charge-Off Terminal Logic

Special handling for bankruptcy charge-offs:

IF charged_off_reason = 'bankruptcy':
  # Check for service credit transaction types that indicate a loss
  # (excludes 'bankruptcy' serviceCreditType)
  loss_service_credits = find_service_credits(
    types = ['settlementOfDebt', 'fraud', 'badDebt', 'deceased'],
    status = 'Succeeded'
  )
  
  IF outstanding_balance > 0:
    # Continue reporting with status 97
    reporting_continues = True
    account_status = '97'
  ELIF count(loss_service_credits) > 0:
    # Balance is zero but loss occurred
    reporting_continues = False
    account_status = '97'
  ELSE:
    # Balance is zero, no loss - final report with 64
    reporting_continues = False
    account_status = '64'

Term Charge-Off Terminal Logic

IF charged_off_reason = 'term':
  loss_service_credits = find_service_credits(
    types = ['settlementOfDebt', 'fraud', 'badDebt', 'deceased'],
    status = 'Succeeded'
  )
  
  IF outstanding_balance > 0:
    reporting_continues = True
    account_status = '97'
  ELIF count(loss_service_credits) > 0:
    # Balance is zero but loss occurred
    reporting_continues = False
    account_status = '97'
  ELSE:
    # Balance is zero, no loss - final report with 64
    reporting_continues = False
    account_status = '64'

Stop Reporting Process

When reporting should stop:

  1. CreditReportingStatus.reporting_status is set to Stopped
  2. reporting_end_date is set to the final reporting date
  3. Final file includes the loan with terminal status
  4. Subsequent files exclude the loan