Class: Dscf::Credit::RepaymentService

Inherits:
Object
  • Object
show all
Defined in:
app/services/dscf/credit/repayment_service.rb

Overview

RepaymentService handles loan repayment processing with automatic payment allocation across facilitation fees, penalties, interest, and principal.

Examples:

Basic usage

loan = Dscf::Credit::Loan.find(loan_id)
service = Dscf::Credit::RepaymentService.new(loan, 1500.00)
result = service.process_repayment

if result[:success]
  puts "Payment processed: #{result[:message]}"
  puts "Remaining balance: #{result[:payment_details][:remaining_balance]}"
else
  puts "Error: #{result[:error]}"
end

See Also:

  • for detailed documentation

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(loan, payment_amount) ⇒ RepaymentService

Initialize the repayment service

Parameters:

  • loan (Dscf::Credit::Loan)

    The loan to process repayment for

  • payment_amount (Numeric)

    The amount being paid (converted to float)



25
26
27
28
# File 'app/services/dscf/credit/repayment_service.rb', line 25

def initialize(loan, payment_amount)
  @loan = loan
  @payment_amount = payment_amount.to_f
end

Instance Attribute Details

#loanObject (readonly)

Returns the value of attribute loan.



19
20
21
# File 'app/services/dscf/credit/repayment_service.rb', line 19

def loan
  @loan
end

#payment_amountObject (readonly)

Returns the value of attribute payment_amount.



19
20
21
# File 'app/services/dscf/credit/repayment_service.rb', line 19

def payment_amount
  @payment_amount
end

Instance Method Details

#process_repaymentHash

Process loan repayment with automatic allocation and status updates

Payment allocation priority (waterfall method):

  1. Facilitation Fee (from loan_accruals where accrual_type=‘facilitation_fee’ and status=‘pending’)

  2. Penalties (from loan_accruals where accrual_type=‘penalty’ and status=‘pending’)

  3. Interest (from loan_accruals where accrual_type=‘interest’ and status=‘pending’)

  4. Principal (from loan.remaining_amount)

Process steps:

  1. Calculate payment allocation across loan components

  2. Update loan record (remaining_amount only)

  3. Mark accruals as paid (with splitting for partial payments)

  4. Update loan status based on remaining balance

  5. Reactivate credit facilities if loan fully paid

Examples:

Success response

{
  success: true,
  loan: #<Dscf::Credit::Loan>,
  payment_details: {
    payment_amount: 1500.00,
    allocation: { ... },
    new_loan_status: "active",
    paid_off: false,
    remaining_balance: 3600.00
  },
  message: "Payment processed successfully"
}

Error response

{
  success: false,
  loan: nil,
  error: "Payment amount exceeds total outstanding balance"
}

Returns:

  • (Hash)

    Result hash with the following structure:

    • :success [Boolean] Whether the operation succeeded

    • :loan [Dscf::Credit::Loan, nil] Updated loan object (nil on failure)

    • :payment_details [Hash] Detailed payment allocation information

    • :message [String] Success message

    • :error [String] Error message (only present on failure)



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/services/dscf/credit/repayment_service.rb', line 72

def process_repayment
  return error_result("Loan not found") unless loan
  return error_result("Invalid payment amount") unless payment_amount > 0
  return error_result("Loan is not active") unless loan.status.in?([ "active", "overdue", "disbursed" ])

  payment_allocation = calculate_payment_allocation

  return error_result("Payment amount exceeds total outstanding balance") if payment_amount > payment_allocation[:total_outstanding]

  ActiveRecord::Base.transaction do
    process_payment_allocation(payment_allocation)

    update_loan_status

    reactivate_facilities_if_paid_off

    loan_transaction = create_repayment_transaction(payment_allocation)

    success_result(payment_allocation, loan_transaction)
  end
rescue StandardError => e
  error_result("Repayment processing failed: #{e.message}")
end