Payment Rating provides the current payment status as a single character:
| Code | Description |
|---|---|
| (blank) | No payment rating applicable |
0 | 0-19 days past due date |
1 | 30-59 days past due |
2 | 60-89 days past due |
3 | 90-119 days past due |
4 | 120-149 days past due |
5 | 150-179 days past due |
6 | 180+ days past due |
G | Collection |
L | Charge-off |
Payment Rating is left blank for non-terminal account statuses. It is populated only for terminal statuses:
05(Account Transferred)13(Paid or Closed)65(Paid in Full - Foreclosure Started)88(Claim Filed for Insured Portion)89(Deed Received in Lieu of Foreclosure)94(Foreclosure Completed)95(Voluntary Surrender)
FUNCTION calculate_payment_rating(account_status, loan_status, snapshot):
TERMINAL_STATUSES = {05, 13, 65, 88, 89, 94, 95}
# Only populate for terminal statuses
IF account_status NOT IN TERMINAL_STATUSES:
RETURN Blank
# For active/frozen/accelerated loans, use current overdue days
IF loan_status IN ('Active', 'Frozen', 'Accelerated'):
RETURN overdue_days_to_rating(snapshot.overdue_number_days)
# For paid-off loans, use the overdue days from before payoff
IF loan_status = 'PaidOff':
most_recent_active_snapshot = find_most_recent_active_snapshot()
IF most_recent_active_snapshot:
RETURN overdue_days_to_rating(most_recent_active_snapshot.overdue_number_days)
RETURN '0' # Default to current if no prior snapshot
# For charged-off loans, always return charge-off rating
IF loan_status = 'ChargedOff':
RETURN 'L' # Charge-off
RAISE Error("Unknown loan status for payment rating")
FUNCTION overdue_days_to_rating(days):
IF days < 30: RETURN '0' # Current
IF days < 60: RETURN '1' # 30-59 days
IF days < 90: RETURN '2' # 60-89 days
IF days < 120: RETURN '3' # 90-119 days
IF days < 150: RETURN '4' # 120-149 days
IF days < 180: RETURN '5' # 150-179 days
RETURN '6' # 180+ daysThe Payment History Profile is a 24-character string representing the payment status for each of the last 24 months, from most recent to oldest.
| Code | Description |
|---|---|
0 | Current |
1 | 30-59 days past due |
2 | 60-89 days past due |
3 | 90-119 days past due |
4 | 120-149 days past due |
5 | 150-179 days past due |
6 | 180+ days past due |
B | No prior history available |
D | No payment reported |
E | Current with zero balance |
G | Collection |
H | Foreclosure completed |
J | Voluntary surrender |
K | Repossession |
L | Charge-off |
FUNCTION calculate_payment_history_profile(loan, report_date):
history = []
# Start from the month before the reporting month
last_reported_month = end_of_previous_month(report_date.replace(day=1) - 1)
reported_months = get_24_months_ending_with(last_reported_month)
FOR EACH reported_month IN reported_months:
# Check if we're before reporting started
IF reporting_start_date > reported_month:
history.append('B') # No prior history
CONTINUE
# Check for migration history
IF migration_cutoff_date AND reported_month <= migration_cutoff_date:
IF migration_payment_history_profile exists:
month_delta = months_between(reported_month, migration_cutoff_date)
IF month_delta < 24:
history.append(migration_payment_history_profile[month_delta])
CONTINUE
# Find snapshot for the month
snapshot = find_snapshot_for_month(reported_month)
# Check for active bankruptcy case that affects this month
# CRITICAL: Loan must be associated with the bankruptcy case
bk_case = find_bankruptcy_case(
loan_associated = True, # Loan must be linked to this case
status IN ('Processing', 'Completed'),
date_filter: (
reported_month >= courtCaseFiledDate AND
reported_month < coalesce(courtCaseClosedDate, courtCaseDebtorDispositionDate,
reported_month + 1 calendar day)
)
)
IF snapshot IS NULL:
history.append('D') # No payment reported
ELIF snapshot.loan_status = 'Frozen' OR bk_case IS NOT NULL:
history.append('D') # No payment reported (frozen or bankruptcy protection)
ELIF snapshot.loan_status = 'ChargedOff':
history.append('L') # Charge-off
ELIF is_open_ended AND balance = 0 AND status = 'Active':
history.append('E') # Current zero balance
ELSE:
history.append(dpd_to_code(snapshot.overdue_number_days))
RETURN join(history)