dscf-banking 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/models/dscf/banking/interest_configuration.rb +58 -10
- data/app/services/dscf/banking/interest_simulation_service.rb +10 -5
- data/db/seeds.rb +205 -95
- data/lib/dscf/banking/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e91b4944ed5da04e89193cc1e06db5150ea053f3f4cd4a8098a576f25585c8c9
|
|
4
|
+
data.tar.gz: 0c1ef04c3785327d68b9d87d6a62ad228329a9fde73e68b6893253614b31284a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a9f07e8d19d474514261bb9189ed89b804525f34839b3ea55704861647a37aa69b840a5ad995b4d3e53c5d6d89237384db92f262173a5021f312257d3abd392e
|
|
7
|
+
data.tar.gz: af083b3874ca0b5e8161125409ed7c06974b8ccf3404f615d0e044bfe434e66022e4f691e6450f7f63a5cd5e15b49061151f4fa27c28ba0acb83aceb330c0a70
|
|
@@ -4,16 +4,21 @@ module Dscf::Banking
|
|
|
4
4
|
belongs_to :virtual_account_product, class_name: "Dscf::Banking::VirtualAccountProduct"
|
|
5
5
|
has_many :interest_rate_tiers, class_name: "Dscf::Banking::InterestRateTier", dependent: :destroy
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
before_validation :normalize_rate_attributes
|
|
8
|
+
validate :interest_free_configuration_guidance
|
|
9
|
+
|
|
10
|
+
with_options unless: :interest_free_configuration_request? do
|
|
11
|
+
validates :annual_interest_rate, presence: true, numericality: { greater_than: 0, less_than_or_equal_to: 1 }
|
|
12
|
+
validates :income_tax_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }
|
|
13
|
+
validates :minimum_balance_for_interest, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
14
|
+
validates :calculation_method, presence: true
|
|
15
|
+
|
|
16
|
+
validates :interest_basis, presence: true
|
|
17
|
+
validates :accrual_frequency, presence: true
|
|
18
|
+
validates :rounding_rule, presence: true
|
|
19
|
+
validates :calculation_timing, presence: true
|
|
20
|
+
validates :is_active, inclusion: { in: [ true, false ] }
|
|
21
|
+
end
|
|
17
22
|
validate :promotional_dates_consistency
|
|
18
23
|
|
|
19
24
|
enum :calculation_method, {
|
|
@@ -59,6 +64,49 @@ module Dscf::Banking
|
|
|
59
64
|
|
|
60
65
|
private
|
|
61
66
|
|
|
67
|
+
def interest_free_configuration_guidance
|
|
68
|
+
return unless no_interest_requested?
|
|
69
|
+
return unless required_calculation_fields_missing?
|
|
70
|
+
|
|
71
|
+
errors.add(
|
|
72
|
+
:base,
|
|
73
|
+
"Interest-free products should not have an interest configuration. Skip interest configuration creation for interest-free products."
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def interest_free_configuration_request?
|
|
78
|
+
no_interest_requested? && required_calculation_fields_missing?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def normalize_rate_attributes
|
|
82
|
+
self.annual_interest_rate = normalize_rate_value(annual_interest_rate_before_type_cast)
|
|
83
|
+
self.income_tax_rate = normalize_rate_value(income_tax_rate_before_type_cast)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def normalize_rate_value(value)
|
|
87
|
+
return value if value.blank?
|
|
88
|
+
|
|
89
|
+
sanitized = value.to_s.strip
|
|
90
|
+
return value if sanitized.blank?
|
|
91
|
+
|
|
92
|
+
percentage_input = sanitized.end_with?("%")
|
|
93
|
+
decimal = BigDecimal(sanitized.delete("%").tr(",", "."))
|
|
94
|
+
|
|
95
|
+
percentage_input || decimal > 1 ? decimal / 100 : decimal
|
|
96
|
+
rescue ArgumentError
|
|
97
|
+
value
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def no_interest_requested?
|
|
101
|
+
annual_interest_rate.blank? || BigDecimal(annual_interest_rate.to_s) <= 0
|
|
102
|
+
rescue ArgumentError
|
|
103
|
+
false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def required_calculation_fields_missing?
|
|
107
|
+
calculation_method.blank? || interest_basis.blank? || accrual_frequency.blank? || rounding_rule.blank? || calculation_timing.blank?
|
|
108
|
+
end
|
|
109
|
+
|
|
62
110
|
def promotional_dates_consistency
|
|
63
111
|
return unless promotional_start_date.present? || promotional_end_date.present?
|
|
64
112
|
|
|
@@ -3,9 +3,8 @@ require "date"
|
|
|
3
3
|
|
|
4
4
|
module Dscf::Banking
|
|
5
5
|
class InterestSimulationService
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
DEFAULT_TAX_RATE = BigDecimal("0.15")
|
|
6
|
+
NO_INTEREST_RATE = BigDecimal("0")
|
|
7
|
+
NO_TAX_RATE = BigDecimal("0")
|
|
9
8
|
|
|
10
9
|
def initialize(account:, initial_balance:, start_date:, end_date:, transactions: [])
|
|
11
10
|
@account = account
|
|
@@ -72,17 +71,23 @@ module Dscf::Banking
|
|
|
72
71
|
end
|
|
73
72
|
|
|
74
73
|
def annual_interest_rate
|
|
74
|
+
return NO_INTEREST_RATE unless interest_configuration
|
|
75
|
+
|
|
75
76
|
configured = interest_configuration&.annual_interest_rate
|
|
76
|
-
configured.present? ? decimal(configured) :
|
|
77
|
+
configured.present? ? decimal(configured) : NO_INTEREST_RATE
|
|
77
78
|
end
|
|
78
79
|
|
|
79
80
|
def annual_interest_rate_for(balance)
|
|
81
|
+
return annual_interest_rate unless interest_configuration
|
|
82
|
+
|
|
80
83
|
interest_rate_tier_for(balance)&.yield_self { |tier| decimal(tier.interest_rate) } || annual_interest_rate
|
|
81
84
|
end
|
|
82
85
|
|
|
83
86
|
def tax_rate
|
|
87
|
+
return NO_TAX_RATE unless interest_configuration
|
|
88
|
+
|
|
84
89
|
configured = interest_configuration&.income_tax_rate
|
|
85
|
-
configured.present? ? decimal(configured) :
|
|
90
|
+
configured.present? ? decimal(configured) : NO_TAX_RATE
|
|
86
91
|
end
|
|
87
92
|
|
|
88
93
|
def day_basis
|
data/db/seeds.rb
CHANGED
|
@@ -1,115 +1,225 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
user3.roles
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
1
|
+
# This file should contain all the record creation needed to seed the banking engine
|
|
2
|
+
# with deterministic, idempotent sample data.
|
|
3
|
+
|
|
4
|
+
puts "Seeding DSCF Banking data..."
|
|
5
|
+
|
|
6
|
+
seed_timestamp = Time.current
|
|
7
|
+
|
|
8
|
+
roles_data = [
|
|
9
|
+
{ code: "USER", name: "User" },
|
|
10
|
+
{ code: "ADMIN", name: "Administrator" },
|
|
11
|
+
{ code: "KYC_OFFICER", name: "KYC Officer" },
|
|
12
|
+
{ code: "BRANCH_MANAGER", name: "Branch Manager" },
|
|
13
|
+
{ code: "VIRTUAL_ACCOUNT_OFFICER", name: "Virtual Account Officer" },
|
|
14
|
+
{ code: "VIRTUAL_ACCOUNT_MANAGER", name: "Virtual Account Manager" },
|
|
15
|
+
{ code: "REGULAR_USER", name: "Regular User" }
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
users_data = [
|
|
19
|
+
{ email: "admin@dscf.com", phone: "+251911000001", roles: %w[ADMIN], password: "password123" },
|
|
20
|
+
{ email: "kyc1@dscf.com", phone: "+251911000002", roles: %w[KYC_OFFICER], password: "password123" },
|
|
21
|
+
{ email: "kyc2@dscf.com", phone: "+251911000003", roles: %w[KYC_OFFICER], password: "password123" },
|
|
22
|
+
{ email: "kyc3@dscf.com", phone: "+251911000004", roles: %w[KYC_OFFICER], password: "password123" },
|
|
23
|
+
{ email: "manager1@dscf.com", phone: "+251911000005", roles: %w[BRANCH_MANAGER], password: "password123" },
|
|
24
|
+
{ email: "manager2@dscf.com", phone: "+251911000006", roles: %w[BRANCH_MANAGER], password: "password123" },
|
|
25
|
+
{ email: "va_officer1@dscf.com", phone: "+251911000007", roles: %w[VIRTUAL_ACCOUNT_OFFICER], password: "password123" },
|
|
26
|
+
{ email: "va_officer2@dscf.com", phone: "+251911000008", roles: %w[VIRTUAL_ACCOUNT_OFFICER], password: "password123" },
|
|
27
|
+
{ email: "va_manager1@dscf.com", phone: "+251911000009", roles: %w[VIRTUAL_ACCOUNT_MANAGER], password: "password123" },
|
|
28
|
+
{ email: "va_manager2@dscf.com", phone: "+251911000010", roles: %w[VIRTUAL_ACCOUNT_MANAGER], password: "password123" },
|
|
29
|
+
{ email: "user1@example.com", phone: "+251911000011", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
30
|
+
{ email: "user2@example.com", phone: "+251911000012", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
31
|
+
{ email: "user3@example.com", phone: "+251911000013", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
32
|
+
{ email: "user4@example.com", phone: "+251911000014", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
33
|
+
{ email: "user5@example.com", phone: "+251911000015", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
34
|
+
{ email: "user6@example.com", phone: "+251911000016", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
35
|
+
{ email: "user7@example.com", phone: "+251911000017", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
36
|
+
{ email: "user8@example.com", phone: "+251911000018", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
37
|
+
{ email: "user9@example.com", phone: "+251911000019", roles: %w[USER REGULAR_USER], password: "password123" },
|
|
38
|
+
{ email: "user10@example.com", phone: "+251911000020", roles: %w[USER REGULAR_USER], password: "password123" }
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
41
|
+
transaction_types_data = [
|
|
42
|
+
{ code: "DEPOSIT", name: "Deposit", description: "Deposit transaction - money coming into account" },
|
|
43
|
+
{ code: "WITHDRAWAL", name: "Withdrawal", description: "Withdrawal transaction - money going out of account" },
|
|
44
|
+
{ code: "TRANSFER", name: "Transfer", description: "Transfer transaction - money moving between accounts" },
|
|
45
|
+
{ code: "VOUCHER", name: "Voucher", description: "Voucher issuance and redemption transactions" }
|
|
46
|
+
].freeze
|
|
47
|
+
|
|
48
|
+
system_accounts_data = [
|
|
49
|
+
{ name: "System Deposit Account" },
|
|
50
|
+
{ name: "System Withdrawal Account" },
|
|
51
|
+
{ name: "Voucher Settlement Account" }
|
|
52
|
+
].freeze
|
|
53
|
+
|
|
54
|
+
product_categories_data = [
|
|
55
|
+
{ name: "Checking Account", description: "Day-to-day transaction accounts" },
|
|
56
|
+
{ name: "Savings Account", description: "Standard savings accounts for retail customers" },
|
|
57
|
+
{ name: "Fixed Deposit", description: "Time-bound deposit products with fixed returns" },
|
|
58
|
+
{ name: "Business Account", description: "Accounts for small and medium business operations" }
|
|
59
|
+
].freeze
|
|
60
|
+
|
|
61
|
+
interest_rate_types_data = [
|
|
62
|
+
{ code: "STANDARD", name: "Standard Rate", description: "Default interest rate for standard products" },
|
|
63
|
+
{ code: "PROMOTIONAL", name: "Promotional Rate", description: "Temporary promotional rate for campaigns" },
|
|
64
|
+
{ code: "TIERED", name: "Tiered Rate", description: "Interest rate that varies by product tier" }
|
|
65
|
+
].freeze
|
|
66
|
+
|
|
67
|
+
virtual_account_products_data = [
|
|
68
|
+
{
|
|
69
|
+
product_code: "CHK-001",
|
|
70
|
+
product_name: "Standard Checking",
|
|
71
|
+
category_name: "Checking Account",
|
|
72
|
+
description: "Everyday checking account for regular transactions."
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
product_code: "SVG-001",
|
|
76
|
+
product_name: "Standard Savings",
|
|
77
|
+
category_name: "Savings Account",
|
|
78
|
+
description: "Savings account for customers who want interest on available balances."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
product_code: "FD-001",
|
|
82
|
+
product_name: "12-Month Fixed Deposit",
|
|
83
|
+
category_name: "Fixed Deposit",
|
|
84
|
+
description: "Fixed-term deposit product with a one-year investment period."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
product_code: "BUS-001",
|
|
88
|
+
product_name: "SME Business Account",
|
|
89
|
+
category_name: "Business Account",
|
|
90
|
+
description: "Business operating account designed for small and medium enterprises."
|
|
91
|
+
}
|
|
92
|
+
].freeze
|
|
93
|
+
|
|
94
|
+
interest_rates_by_category = {
|
|
95
|
+
"Savings Account" => 0.035,
|
|
96
|
+
"Fixed Deposit" => 0.06,
|
|
97
|
+
"Business Account" => 0.025
|
|
98
|
+
}.freeze
|
|
50
99
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
100
|
+
puts "Seeding roles..."
|
|
101
|
+
roles = roles_data.each_with_object({}) do |role_data, memo|
|
|
102
|
+
role = Dscf::Core::Role.find_or_initialize_by(code: role_data[:code])
|
|
103
|
+
role.name = role_data[:name]
|
|
104
|
+
role.active = true
|
|
105
|
+
role.save!
|
|
106
|
+
|
|
107
|
+
memo[role_data[:code]] = role
|
|
108
|
+
puts " Seeded role: #{role.code}"
|
|
56
109
|
end
|
|
57
|
-
puts "Created transaction type: #{deposit_type.name}"
|
|
58
110
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
111
|
+
puts "Seeding users..."
|
|
112
|
+
users = users_data.each_with_object({}) do |user_data, memo|
|
|
113
|
+
user = Dscf::Core::User.find_or_initialize_by(email: user_data[:email])
|
|
114
|
+
user.phone = user_data[:phone]
|
|
115
|
+
user.password = user_data[:password] if user.new_record? || user.password_digest.blank?
|
|
116
|
+
user.temp_password = false
|
|
117
|
+
user.verified_at ||= seed_timestamp
|
|
118
|
+
user.save!
|
|
119
|
+
|
|
120
|
+
user_data[:roles].each do |role_code|
|
|
121
|
+
Dscf::Core::UserRole.find_or_create_by!(user: user, role: roles.fetch(role_code))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
memo[user_data[:email]] = user
|
|
125
|
+
puts " Seeded user: #{user.email}"
|
|
62
126
|
end
|
|
63
|
-
puts "Created transaction type: #{withdrawal_type.name}"
|
|
64
127
|
|
|
65
|
-
|
|
66
|
-
tt.name = "Transfer"
|
|
67
|
-
tt.description = "Transfer transaction - money moving between accounts"
|
|
68
|
-
end
|
|
69
|
-
puts "Created transaction type: #{transfer_type.name}"
|
|
128
|
+
admin_user = users.fetch("admin@dscf.com")
|
|
70
129
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
130
|
+
puts "Seeding transaction types..."
|
|
131
|
+
transaction_types_data.each do |transaction_type_data|
|
|
132
|
+
transaction_type = Dscf::Banking::TransactionType.find_or_initialize_by(code: transaction_type_data[:code])
|
|
133
|
+
transaction_type.name = transaction_type_data[:name]
|
|
134
|
+
transaction_type.description = transaction_type_data[:description]
|
|
135
|
+
transaction_type.save!
|
|
136
|
+
|
|
137
|
+
puts " Seeded transaction type: #{transaction_type.code}"
|
|
74
138
|
end
|
|
75
|
-
puts "Created transaction type: #{voucher_type.name}"
|
|
76
139
|
|
|
77
|
-
# Seed system accounts for transaction processing
|
|
78
140
|
puts "Seeding system accounts..."
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
141
|
+
system_accounts_data.each do |account_data|
|
|
142
|
+
account = Dscf::Banking::Account.find_or_initialize_by(
|
|
143
|
+
name: account_data[:name],
|
|
144
|
+
system_account: true
|
|
145
|
+
)
|
|
83
146
|
account.currency = "ETB"
|
|
84
147
|
account.status = :active
|
|
85
148
|
account.current_balance = 0
|
|
86
149
|
account.available_balance = 0
|
|
87
150
|
account.minimum_balance = 0
|
|
151
|
+
account.active = true
|
|
152
|
+
account.save!
|
|
153
|
+
|
|
154
|
+
puts " Seeded system account: #{account.name}"
|
|
88
155
|
end
|
|
89
|
-
puts "Created system deposit account: #{system_deposit_account.name}"
|
|
90
156
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
157
|
+
puts "Seeding product categories..."
|
|
158
|
+
product_categories = product_categories_data.each_with_object({}) do |category_data, memo|
|
|
159
|
+
category = Dscf::Banking::ProductCategory.find_or_initialize_by(name: category_data[:name])
|
|
160
|
+
category.description = category_data[:description]
|
|
161
|
+
category.is_active = true
|
|
162
|
+
category.save!
|
|
163
|
+
|
|
164
|
+
memo[category_data[:name]] = category
|
|
165
|
+
puts " Seeded product category: #{category.name}"
|
|
100
166
|
end
|
|
101
|
-
puts "Created system withdrawal account: #{system_withdrawal_account.name}"
|
|
102
167
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
168
|
+
puts "Seeding interest rate types..."
|
|
169
|
+
interest_rate_types = interest_rate_types_data.each_with_object([]) do |rate_type_data, memo|
|
|
170
|
+
rate_type = Dscf::Banking::InterestRateType.find_or_initialize_by(code: rate_type_data[:code])
|
|
171
|
+
rate_type.name = rate_type_data[:name]
|
|
172
|
+
rate_type.description = rate_type_data[:description]
|
|
173
|
+
rate_type.save!
|
|
174
|
+
|
|
175
|
+
memo << rate_type
|
|
176
|
+
puts " Seeded interest rate type: #{rate_type.code}"
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
puts "Seeding virtual account products..."
|
|
180
|
+
virtual_account_products = virtual_account_products_data.each_with_object([]) do |product_data, memo|
|
|
181
|
+
product = Dscf::Banking::VirtualAccountProduct.find_or_initialize_by(product_code: product_data[:product_code])
|
|
182
|
+
product.product_name = product_data[:product_name]
|
|
183
|
+
product.product_category = product_categories.fetch(product_data[:category_name])
|
|
184
|
+
product.description = product_data[:description]
|
|
185
|
+
product.document_reference = "DOC-#{product_data[:product_code]}"
|
|
186
|
+
product.status = :approved
|
|
187
|
+
product.created_by = admin_user
|
|
188
|
+
product.approved_by = admin_user
|
|
189
|
+
product.approved_at ||= seed_timestamp
|
|
190
|
+
product.is_active = true
|
|
191
|
+
product.save!
|
|
192
|
+
|
|
193
|
+
memo << product
|
|
194
|
+
puts " Seeded virtual account product: #{product.product_code}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
puts "Seeding interest configurations..."
|
|
198
|
+
virtual_account_products.each_with_index do |product, index|
|
|
199
|
+
category_name = product.product_category&.name
|
|
200
|
+
|
|
201
|
+
if category_name == "Checking Account"
|
|
202
|
+
puts " Skipped interest configuration for: #{product.product_code}"
|
|
203
|
+
next
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
interest_configuration = Dscf::Banking::InterestConfiguration.find_or_initialize_by(
|
|
207
|
+
virtual_account_product: product,
|
|
208
|
+
interest_rate_type: interest_rate_types[index % interest_rate_types.length]
|
|
209
|
+
)
|
|
210
|
+
interest_configuration.annual_interest_rate = interest_rates_by_category.fetch(category_name, 0.02)
|
|
211
|
+
interest_configuration.income_tax_rate = 0.05
|
|
212
|
+
interest_configuration.minimum_balance_for_interest = 1000.0
|
|
213
|
+
interest_configuration.calculation_method = :simple
|
|
214
|
+
interest_configuration.compounding_period = :monthly
|
|
215
|
+
interest_configuration.interest_basis = :actual_365
|
|
216
|
+
interest_configuration.accrual_frequency = :monthly
|
|
217
|
+
interest_configuration.rounding_rule = :nearest_cent
|
|
218
|
+
interest_configuration.calculation_timing ||= seed_timestamp
|
|
219
|
+
interest_configuration.is_active = true
|
|
220
|
+
interest_configuration.save!
|
|
221
|
+
|
|
222
|
+
puts " Seeded interest configuration for: #{product.product_code}"
|
|
112
223
|
end
|
|
113
|
-
puts "Created voucher settlement account: #{voucher_settlement_account.name}"
|
|
114
224
|
|
|
115
|
-
puts "
|
|
225
|
+
puts "DSCF Banking seed completed successfully."
|
data/lib/dscf/banking/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dscf-banking
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Asrat Efrem
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-04-22 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rails
|