Class: Dscf::Banking::InterestSimulationService

Inherits:
Object
  • Object
show all
Defined in:
app/services/dscf/banking/interest_simulation_service.rb

Constant Summary collapse

NO_INTEREST_RATE =
BigDecimal("0")
NO_TAX_RATE =
BigDecimal("0")

Instance Method Summary collapse

Constructor Details

#initialize(account:, initial_balance:, start_date:, end_date:, transactions: []) ⇒ InterestSimulationService

Returns a new instance of InterestSimulationService.



9
10
11
12
13
14
15
16
# File 'app/services/dscf/banking/interest_simulation_service.rb', line 9

def initialize(account:, initial_balance:, start_date:, end_date:, transactions: [])
  @account = 
  @initial_balance = decimal(initial_balance)
  @start_date = to_date(start_date)
  @end_date = to_date(end_date)
  @transactions_by_date = {}
  @transactions = normalize_transactions(transactions || [])
end

Instance Method Details

#callObject

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'app/services/dscf/banking/interest_simulation_service.rb', line 18

def call
  raise ArgumentError, "start_date must be before or equal to end_date" if @start_date > @end_date

  balance = @initial_balance
  gross_interest = BigDecimal("0")
  accrued_interest = BigDecimal("0")
  daily_breakdown = []

  (@start_date..@end_date).each do |date|
    daily_transactions = @transactions_by_date[date] || []
    daily_transaction_sum = daily_transactions.sum(BigDecimal("0")) { |transaction| transaction[:signed_amount] }
    balance += daily_transaction_sum

    daily_rate = annual_interest_rate_for(balance) / BigDecimal(day_basis.to_s)
    raw_daily_interest = eligible_for_interest?(date, balance) ? balance * daily_rate : BigDecimal("0")
    accrued_interest += raw_daily_interest

    posted_daily_interest = BigDecimal("0")
    if accrual_posting_due?(date)
      posted_daily_interest = accrued_interest
      accrued_interest = BigDecimal("0")
      gross_interest += posted_daily_interest

      # Compound mode credits posted interest into principal for subsequent days.
      balance += posted_daily_interest if compound_calculation? && compounding_due?(date)
    end

    daily_breakdown << {
      date: date.iso8601,
      balance: money(balance),
      transaction_total: money(daily_transaction_sum),
      daily_interest: money(posted_daily_interest)
    }
  end

  tax_amount = gross_interest * tax_rate
  net_interest = gross_interest - tax_amount

  {
    gross_interest: money(gross_interest),
    tax_amount: money(tax_amount),
    net_interest: money(net_interest),
    daily_breakdown: daily_breakdown,
    accounting_records: accounting_records(gross_interest, tax_amount, net_interest)
  }
end