dscf-banking 0.1.0 → 0.1.2
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/MIT-LICENSE +0 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/app/controllers/dscf/banking/accounts_controller.rb +152 -0
- data/app/controllers/dscf/banking/application_controller.rb +0 -0
- data/app/controllers/dscf/banking/applications_controller.rb +113 -0
- data/app/controllers/dscf/banking/interest_configurations_controller.rb +0 -0
- data/app/controllers/dscf/banking/interest_rate_tiers_controller.rb +0 -0
- data/app/controllers/dscf/banking/interest_rate_types_controller.rb +0 -0
- data/app/controllers/dscf/banking/product_approvals_controller.rb +0 -0
- data/app/controllers/dscf/banking/product_categories_controller.rb +0 -0
- data/app/controllers/dscf/banking/transaction_types_controller.rb +27 -0
- data/app/controllers/dscf/banking/transactions_controller.rb +275 -0
- data/app/controllers/dscf/banking/virtual_account_products_controller.rb +0 -0
- data/app/jobs/dscf/banking/application_job.rb +0 -0
- data/app/mailers/dscf/banking/application_mailer.rb +0 -0
- data/app/models/concerns/dscf/banking/auditable.rb +0 -0
- data/app/models/dscf/banking/account.rb +110 -0
- data/app/models/dscf/banking/application.rb +70 -0
- data/app/models/dscf/banking/application_record.rb +0 -0
- data/app/models/dscf/banking/interest_configuration.rb +0 -0
- data/app/models/dscf/banking/interest_rate_tier.rb +0 -0
- data/app/models/dscf/banking/interest_rate_type.rb +0 -0
- data/app/models/dscf/banking/product_approval.rb +0 -0
- data/app/models/dscf/banking/product_audit_log.rb +0 -0
- data/app/models/dscf/banking/product_category.rb +0 -0
- data/app/models/dscf/banking/transaction.rb +68 -0
- data/app/models/dscf/banking/transaction_type.rb +20 -0
- data/app/models/dscf/banking/virtual_account_product.rb +0 -0
- data/app/serializers/dscf/banking/account_serializer.rb +11 -0
- data/app/serializers/dscf/banking/application_serializer.rb +16 -0
- data/app/serializers/dscf/banking/interest_configuration_serializer.rb +0 -0
- data/app/serializers/dscf/banking/interest_rate_tier_serializer.rb +0 -0
- data/app/serializers/dscf/banking/interest_rate_type_serializer.rb +0 -0
- data/app/serializers/dscf/banking/product_approval_serializer.rb +0 -0
- data/app/serializers/dscf/banking/product_category_serializer.rb +0 -0
- data/app/serializers/dscf/banking/transaction_serializer.rb +19 -0
- data/app/serializers/dscf/banking/transaction_type_serializer.rb +9 -0
- data/app/serializers/dscf/banking/virtual_account_product_serializer.rb +0 -0
- data/app/services/dscf/banking/account_creation_service.rb +53 -0
- data/app/services/dscf/banking/base_transaction_service.rb +99 -0
- data/app/services/dscf/banking/deposit_service.rb +97 -0
- data/app/services/dscf/banking/transfer_service.rb +78 -0
- data/app/services/dscf/banking/withdrawal_service.rb +100 -0
- data/config/routes.rb +27 -0
- data/db/migrate/20250830211002_create_dscf_banking_product_categories.rb +0 -0
- data/db/migrate/20250830211027_create_dscf_banking_interest_rate_types.rb +0 -0
- data/db/migrate/20250831063605_add_code_and_remove_fields_from_interest_rate_types.rb +0 -0
- data/db/migrate/20250831064917_create_dscf_banking_virtual_account_products.rb +0 -0
- data/db/migrate/20250831072627_create_dscf_banking_interest_configurations.rb +0 -0
- data/db/migrate/20250831080745_create_dscf_banking_interest_rate_tiers.rb +0 -0
- data/db/migrate/20250831082356_create_dscf_banking_product_approvals.rb +0 -0
- data/db/migrate/20250831083907_create_dscf_banking_product_audit_logs.rb +0 -0
- data/db/migrate/20250831084706_allow_null_virtual_account_product_id_in_product_audit_logs.rb +0 -0
- data/db/migrate/20250912193134_create_dscf_banking_applications.rb +20 -0
- data/db/migrate/20250912203527_create_dscf_banking_accounts.rb +21 -0
- data/db/migrate/20250919084147_add_account_type_to_accounts.rb +6 -0
- data/db/migrate/20250919084927_make_account_associations_optional.rb +6 -0
- data/db/migrate/20250919182831_create_dscf_banking_transaction_types.rb +14 -0
- data/db/migrate/20250919184220_create_dscf_banking_transactions.rb +21 -0
- data/db/seeds.rb +125 -0
- data/lib/dscf/banking/engine.rb +0 -0
- data/lib/dscf/banking/version.rb +1 -1
- data/lib/dscf/banking.rb +0 -0
- data/lib/tasks/dscf/banking_tasks.rake +0 -0
- data/spec/factories/dscf/banking/accounts.rb +79 -0
- data/spec/factories/dscf/banking/applications.rb +65 -0
- data/spec/factories/dscf/banking/interest_configurations.rb +0 -0
- data/spec/factories/dscf/banking/interest_rate_tiers.rb +0 -0
- data/spec/factories/dscf/banking/interest_rate_types.rb +0 -0
- data/spec/factories/dscf/banking/product_approvals.rb +0 -0
- data/spec/factories/dscf/banking/product_audit_logs.rb +0 -0
- data/spec/factories/dscf/banking/product_categories.rb +0 -0
- data/spec/factories/dscf/banking/transaction_types.rb +56 -0
- data/spec/factories/dscf/banking/transactions.rb +52 -0
- data/spec/factories/dscf/banking/virtual_account_products.rb +0 -0
- metadata +30 -2
@@ -0,0 +1,78 @@
|
|
1
|
+
module Dscf::Banking
|
2
|
+
class TransferService < BaseTransactionService
|
3
|
+
attr_reader :transaction
|
4
|
+
|
5
|
+
def initialize(debit_account:, credit_account:, amount:, description:, transaction_type_code: "TRANSFER")
|
6
|
+
super()
|
7
|
+
@debit_account = debit_account
|
8
|
+
@credit_account = credit_account
|
9
|
+
@amount = amount.to_f
|
10
|
+
@description = description
|
11
|
+
@transaction_type_code = transaction_type_code
|
12
|
+
@transaction = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
return self unless validate_transfer
|
17
|
+
|
18
|
+
ActiveRecord::Base.transaction do
|
19
|
+
create_transfer_transaction
|
20
|
+
return self unless success?
|
21
|
+
|
22
|
+
process_transaction(@transaction)
|
23
|
+
return self unless success?
|
24
|
+
end
|
25
|
+
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_transfer
|
32
|
+
# Validate debit account
|
33
|
+
return false unless validate_account_active(@debit_account, "Debit account")
|
34
|
+
|
35
|
+
# Validate credit account
|
36
|
+
return false unless validate_account_active(@credit_account, "Credit account")
|
37
|
+
|
38
|
+
# Validate amount
|
39
|
+
if @amount <= 0
|
40
|
+
add_error("Transfer amount must be greater than zero")
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
# Validate sufficient funds
|
45
|
+
return false unless validate_sufficient_funds(@debit_account, @amount)
|
46
|
+
|
47
|
+
# Validate different accounts
|
48
|
+
if @debit_account.id == @credit_account.id
|
49
|
+
add_error("Cannot transfer to the same account")
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
# Validate currency match
|
54
|
+
if @debit_account.currency != @credit_account.currency
|
55
|
+
add_error("Currency mismatch between accounts")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_transfer_transaction
|
63
|
+
transaction_type = find_or_create_transaction_type(@transaction_type_code)
|
64
|
+
return unless transaction_type
|
65
|
+
|
66
|
+
@transaction = create_transaction(
|
67
|
+
account: @debit_account, # Primary account for the transaction
|
68
|
+
transaction_type: transaction_type,
|
69
|
+
debit_account: @debit_account,
|
70
|
+
credit_account: @credit_account,
|
71
|
+
amount: @amount,
|
72
|
+
currency: @debit_account.currency,
|
73
|
+
description: @description,
|
74
|
+
status: :pending
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Dscf::Banking
|
2
|
+
class WithdrawalService < BaseTransactionService
|
3
|
+
attr_reader :transaction
|
4
|
+
|
5
|
+
def initialize(account:, amount:, description:, transaction_type_code: "WITHDRAWAL")
|
6
|
+
super()
|
7
|
+
@account = account
|
8
|
+
@amount = amount.to_f
|
9
|
+
@description = description
|
10
|
+
@transaction_type_code = transaction_type_code
|
11
|
+
@transaction = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute
|
15
|
+
return self unless validate_withdrawal
|
16
|
+
|
17
|
+
ActiveRecord::Base.transaction do
|
18
|
+
create_withdrawal_transaction
|
19
|
+
return self unless success?
|
20
|
+
|
21
|
+
process_withdrawal
|
22
|
+
return self unless success?
|
23
|
+
end
|
24
|
+
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def validate_withdrawal
|
31
|
+
# Validate account
|
32
|
+
return false unless validate_account_active(@account, "Source account")
|
33
|
+
|
34
|
+
# Validate amount
|
35
|
+
if @amount <= 0
|
36
|
+
add_error("Withdrawal amount must be greater than zero")
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Validate sufficient funds
|
41
|
+
return false unless validate_sufficient_funds(@account, @amount)
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_withdrawal_transaction
|
47
|
+
transaction_type = find_or_create_transaction_type(@transaction_type_code)
|
48
|
+
return unless transaction_type
|
49
|
+
|
50
|
+
# For withdrawals, we need a system account as the credit account
|
51
|
+
# This represents the external destination
|
52
|
+
system_account = find_or_create_system_account
|
53
|
+
|
54
|
+
@transaction = create_transaction(
|
55
|
+
account: @account, # Primary account for the transaction
|
56
|
+
transaction_type: transaction_type,
|
57
|
+
debit_account: @account, # Customer account being debited
|
58
|
+
credit_account: system_account, # External destination
|
59
|
+
amount: @amount,
|
60
|
+
currency: @account.currency,
|
61
|
+
description: @description,
|
62
|
+
status: :pending
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def process_withdrawal
|
67
|
+
@transaction.update(status: :processing)
|
68
|
+
|
69
|
+
# Update account balance (decrease for withdrawal)
|
70
|
+
new_balance = @account.current_balance - @amount
|
71
|
+
new_available = @account.available_balance - @amount
|
72
|
+
|
73
|
+
if @account.update(current_balance: new_balance, available_balance: new_available)
|
74
|
+
@transaction.update(status: :completed)
|
75
|
+
true
|
76
|
+
else
|
77
|
+
@account.errors.full_messages.each { |msg| add_error(msg) }
|
78
|
+
@transaction.update(status: :failed)
|
79
|
+
false
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def find_or_create_system_account
|
84
|
+
# Find or create a system account for external withdrawals
|
85
|
+
system_account = Dscf::Banking::Account.system_accounts
|
86
|
+
.where(currency: @account.currency)
|
87
|
+
.where("name LIKE ?", "%Withdrawal%")
|
88
|
+
.first
|
89
|
+
|
90
|
+
unless system_account
|
91
|
+
# In a real system, this would be pre-created during setup
|
92
|
+
# For now, we'll assume it exists or create a placeholder
|
93
|
+
add_error("System withdrawal account not found for currency #{@account.currency}")
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
|
97
|
+
system_account
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/config/routes.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
Dscf::Banking::Engine.routes.draw do
|
2
|
+
resources :accounts do
|
3
|
+
member do
|
4
|
+
post :activate
|
5
|
+
post :suspend
|
6
|
+
post :close
|
7
|
+
end
|
8
|
+
end
|
2
9
|
resources :product_categories
|
3
10
|
resources :interest_rate_types
|
4
11
|
resources :virtual_account_products do
|
@@ -9,4 +16,24 @@ Dscf::Banking::Engine.routes.draw do
|
|
9
16
|
resources :interest_configurations
|
10
17
|
resources :interest_rate_tiers
|
11
18
|
resources :product_approvals
|
19
|
+
resources :applications do
|
20
|
+
member do
|
21
|
+
post :approve
|
22
|
+
post :reject
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
resources :transaction_types
|
27
|
+
|
28
|
+
resources :transactions do
|
29
|
+
collection do
|
30
|
+
post :transfer
|
31
|
+
post :deposit
|
32
|
+
post :withdrawal
|
33
|
+
end
|
34
|
+
member do
|
35
|
+
post :cancel
|
36
|
+
get :details
|
37
|
+
end
|
38
|
+
end
|
12
39
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/db/migrate/20250831084706_allow_null_virtual_account_product_id_in_product_audit_logs.rb
CHANGED
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateDscfBankingApplications < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :dscf_banking_applications do |t|
|
4
|
+
t.string :application_number, null: false
|
5
|
+
t.references :user, null: false, foreign_key: { to_table: :dscf_core_users }
|
6
|
+
t.integer :applicant_type, null: false
|
7
|
+
t.integer :status, null: false, default: 0
|
8
|
+
|
9
|
+
t.jsonb :form_data
|
10
|
+
t.datetime :submitted_at
|
11
|
+
t.datetime :completed_at
|
12
|
+
t.text :rejection_reason
|
13
|
+
t.references :assigned_kyc_officer, null: true, foreign_key: { to_table: :dscf_core_users }
|
14
|
+
t.references :assigned_branch_manager, null: true, foreign_key: { to_table: :dscf_core_users }
|
15
|
+
t.references :virtual_account_product, null: false, foreign_key: { to_table: :dscf_banking_virtual_account_products }
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateDscfBankingAccounts < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :dscf_banking_accounts do |t|
|
4
|
+
t.string :account_number, null: false
|
5
|
+
t.references :virtual_account_product, null: false, foreign_key: { to_table: :dscf_banking_virtual_account_products }
|
6
|
+
t.references :application, null: false, foreign_key: { to_table: :dscf_banking_applications }
|
7
|
+
t.string :name, null: false
|
8
|
+
t.integer :status, default: 0
|
9
|
+
t.date :activation_date
|
10
|
+
t.date :closure_date
|
11
|
+
t.jsonb :account_properties, default: {}
|
12
|
+
t.decimal :current_balance, precision: 20, scale: 4, default: 0
|
13
|
+
t.decimal :available_balance, precision: 20, scale: 4, default: 0
|
14
|
+
t.decimal :minimum_balance, precision: 20, scale: 4, default: 0
|
15
|
+
t.string :currency, null: false, default: 'ETB'
|
16
|
+
t.boolean :active, default: true
|
17
|
+
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateDscfBankingTransactionTypes < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :dscf_banking_transaction_types do |t|
|
4
|
+
t.string :code, null: false, limit: 20
|
5
|
+
t.string :name, null: false, limit: 100
|
6
|
+
t.text :description
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :dscf_banking_transaction_types, :code, unique: true
|
12
|
+
add_index :dscf_banking_transaction_types, :name, unique: true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateDscfBankingTransactions < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :dscf_banking_transactions do |t|
|
4
|
+
t.references :account, null: false, foreign_key: { to_table: :dscf_banking_accounts }
|
5
|
+
t.references :transaction_type, null: false, foreign_key: { to_table: :dscf_banking_transaction_types }
|
6
|
+
t.decimal :amount, precision: 20, scale: 4, null: false
|
7
|
+
t.string :currency, null: false, default: "ETB"
|
8
|
+
t.string :reference_number, null: false
|
9
|
+
t.text :description
|
10
|
+
t.integer :status, default: 0, null: false
|
11
|
+
t.references :debit_account, null: false, foreign_key: { to_table: :dscf_banking_accounts }
|
12
|
+
t.references :credit_account, null: false, foreign_key: { to_table: :dscf_banking_accounts }
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :dscf_banking_transactions, :status
|
18
|
+
add_index :dscf_banking_transactions, :reference_number, unique: true
|
19
|
+
add_index :dscf_banking_transactions, [ :account_id, :created_at ]
|
20
|
+
end
|
21
|
+
end
|
data/db/seeds.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# db/seeds.rb
|
2
|
+
|
3
|
+
# DEBUG: Confirm seed file execution and model availability
|
4
|
+
puts "Seed file started"
|
5
|
+
puts "Dscf::Core::User loaded? => #{defined?(Dscf::Core::User)}"
|
6
|
+
puts "Dscf::Core::Role loaded? => #{defined?(Dscf::Core::Role)}"
|
7
|
+
|
8
|
+
# DSCF Banking Engine Seed Data
|
9
|
+
# This file seeds the database with sample data for all models in the correct dependency order
|
10
|
+
|
11
|
+
puts "Starting DSCF Banking Engine seed data..."
|
12
|
+
|
13
|
+
|
14
|
+
# 1. Seed roles (if model exists)
|
15
|
+
puts "Seeding roles..."
|
16
|
+
if defined?(Dscf::Core::Role)
|
17
|
+
user_role = Dscf::Core::Role.find_or_create_by(code: 'user') do |role|
|
18
|
+
role.name = 'User'
|
19
|
+
end
|
20
|
+
officer_role = Dscf::Core::Role.find_or_create_by(code: 'virtual_account_officer') do |role|
|
21
|
+
role.name = 'Virtual Account Officer'
|
22
|
+
end
|
23
|
+
manager_role = Dscf::Core::Role.find_or_create_by(code: 'virtual_account_manager') do |role|
|
24
|
+
role.name = 'Virtual Account Manager'
|
25
|
+
end
|
26
|
+
kyc_officer_role = Dscf::Core::Role.find_or_create_by(code: 'kyc_officer') do |role|
|
27
|
+
role.name = 'KYC Officer'
|
28
|
+
end
|
29
|
+
branch_manager_role = Dscf::Core::Role.find_or_create_by(code: 'branch_manager') do |role|
|
30
|
+
role.name = 'Branch Manager'
|
31
|
+
end
|
32
|
+
puts "✓ Roles created/found"
|
33
|
+
else
|
34
|
+
puts "Warning: Dscf::Core::Role model not found. Skipping role seeding."
|
35
|
+
end
|
36
|
+
# 2. Seed users with roles (if model exists)
|
37
|
+
puts "Seeding users..."
|
38
|
+
if defined?(Dscf::Core::User)
|
39
|
+
user1 = Dscf::Core::User.find_or_create_by(email: "user@banking.com") do |u|
|
40
|
+
u.phone = "+251911123456"
|
41
|
+
u.password = "SecurePassword123!"
|
42
|
+
u.verified_at = Time.current
|
43
|
+
u.temp_password = false
|
44
|
+
end
|
45
|
+
user1.roles << user_role if defined?(user_role)
|
46
|
+
puts "Created user: #{user1.email} (user@banking.com)"
|
47
|
+
|
48
|
+
user2 = Dscf::Core::User.find_or_create_by(email: "virtual_account_officer@banking.com") do |u|
|
49
|
+
u.phone = "+251922123456"
|
50
|
+
u.password = "SecurePassword123!"
|
51
|
+
u.verified_at = Time.current
|
52
|
+
u.temp_password = false
|
53
|
+
end
|
54
|
+
user2.roles << officer_role if defined?(officer_role)
|
55
|
+
puts "Created user: #{user2.email} (virtual_account_officer@banking.com)"
|
56
|
+
|
57
|
+
user3 = Dscf::Core::User.find_or_create_by(email: "virtual_account_manager@banking.com") do |u|
|
58
|
+
u.phone = "+251933123456"
|
59
|
+
u.password = "SecurePassword123!"
|
60
|
+
u.verified_at = Time.current
|
61
|
+
u.temp_password = false
|
62
|
+
end
|
63
|
+
user3.roles << manager_role if defined?(manager_role)
|
64
|
+
puts "Created user: #{user3.email} (virtual_account_manager@banking.com)"
|
65
|
+
|
66
|
+
user4 = Dscf::Core::User.find_or_create_by(email: "user_virtual_account_officer@banking.com") do |u|
|
67
|
+
u.phone = "+251944123456"
|
68
|
+
u.password = "SecurePassword123!"
|
69
|
+
u.verified_at = Time.current
|
70
|
+
u.temp_password = false
|
71
|
+
end
|
72
|
+
user4.roles << user_role if defined?(user_role)
|
73
|
+
user4.roles << officer_role if defined?(officer_role)
|
74
|
+
puts "Created user: #{user4.email} (user_virtual_account_officer@banking.com)"
|
75
|
+
|
76
|
+
user5 = Dscf::Core::User.find_or_create_by(email: "virtual_account_manager2@banking.com") do |u|
|
77
|
+
u.phone = "+251955123456"
|
78
|
+
u.password = "SecurePassword123!"
|
79
|
+
u.verified_at = Time.current
|
80
|
+
u.temp_password = false
|
81
|
+
end
|
82
|
+
user5.roles << manager_role if defined?(manager_role)
|
83
|
+
puts "Created user: #{user5.email} (virtual_account_manager2@banking.com)"
|
84
|
+
|
85
|
+
user6 = Dscf::Core::User.find_or_create_by(email: "kyc_officer@banking.com") do |u|
|
86
|
+
u.phone = "+251966123456"
|
87
|
+
u.password = "SecurePassword123!"
|
88
|
+
u.verified_at = Time.current
|
89
|
+
u.temp_password = false
|
90
|
+
end
|
91
|
+
user6.roles << kyc_officer_role if defined?(kyc_officer_role)
|
92
|
+
puts "Created user: #{user6.email} (kyc_officer@banking.com)"
|
93
|
+
|
94
|
+
user7 = Dscf::Core::User.find_or_create_by(email: "branch_manager@banking.com") do |u|
|
95
|
+
u.phone = "+251977123456"
|
96
|
+
u.password = "SecurePassword123!"
|
97
|
+
u.verified_at = Time.current
|
98
|
+
u.temp_password = false
|
99
|
+
end
|
100
|
+
user7.roles << branch_manager_role if defined?(branch_manager_role)
|
101
|
+
puts "Created user: #{user7.email} (branch_manager@banking.com)"
|
102
|
+
else
|
103
|
+
puts "Warning: Dscf::Core::User model not found. Skipping user seeding."
|
104
|
+
end# 3. Seed transaction types (engine model)
|
105
|
+
puts "Seeding transaction types..."
|
106
|
+
if defined?(Dscf::Banking::TransactionType)
|
107
|
+
transaction_types = [
|
108
|
+
{ name: "Deposit", code: "DEP" },
|
109
|
+
{ name: "Withdrawal", code: "WDL" },
|
110
|
+
{ name: "Transfer", code: "TRF" },
|
111
|
+
{ name: "Interest Credit", code: "INTC" },
|
112
|
+
{ name: "Fee Debit", code: "FEED" }
|
113
|
+
]
|
114
|
+
|
115
|
+
transaction_types.each do |attrs|
|
116
|
+
Dscf::Banking::TransactionType.find_or_create_by(code: attrs[:code]) do |tt|
|
117
|
+
tt.name = attrs[:name]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
puts "✓ Transaction types created/found"
|
121
|
+
else
|
122
|
+
puts "Warning: Dscf::Banking::TransactionType not found. Skipping transaction type seeding."
|
123
|
+
end
|
124
|
+
|
125
|
+
puts "DSCF Banking Engine seed data completed successfully!"
|
data/lib/dscf/banking/engine.rb
CHANGED
File without changes
|
data/lib/dscf/banking/version.rb
CHANGED
data/lib/dscf/banking.rb
CHANGED
File without changes
|
File without changes
|
@@ -0,0 +1,79 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :dscf_banking_account, class: "Dscf::Banking::Account" do
|
3
|
+
association :virtual_account_product, factory: :virtual_account_product
|
4
|
+
association :application, factory: :application
|
5
|
+
|
6
|
+
name { "Test Account" }
|
7
|
+
currency { "ETB" }
|
8
|
+
current_balance { 0 }
|
9
|
+
available_balance { 0 }
|
10
|
+
minimum_balance { 0 }
|
11
|
+
status { :draft }
|
12
|
+
active { true }
|
13
|
+
system_account { false }
|
14
|
+
account_properties { {} }
|
15
|
+
|
16
|
+
trait :active do
|
17
|
+
status { :active }
|
18
|
+
activation_date { Date.current }
|
19
|
+
end
|
20
|
+
|
21
|
+
trait :suspended do
|
22
|
+
status { :suspended }
|
23
|
+
end
|
24
|
+
|
25
|
+
trait :closed do
|
26
|
+
status { :closed }
|
27
|
+
active { false }
|
28
|
+
closure_date { Date.current }
|
29
|
+
end
|
30
|
+
|
31
|
+
trait :with_balance do
|
32
|
+
current_balance { 1000 }
|
33
|
+
available_balance { 1000 }
|
34
|
+
minimum_balance { 100 }
|
35
|
+
end
|
36
|
+
|
37
|
+
trait :system_account do
|
38
|
+
system_account { true }
|
39
|
+
virtual_account_product { nil }
|
40
|
+
application { nil }
|
41
|
+
end
|
42
|
+
|
43
|
+
trait :settlement_account do
|
44
|
+
system_account { true }
|
45
|
+
name { "Core Banking Settlement Account" }
|
46
|
+
virtual_account_product { nil }
|
47
|
+
application { nil }
|
48
|
+
end
|
49
|
+
|
50
|
+
trait :interest_expense_account do
|
51
|
+
system_account { true }
|
52
|
+
name { "Interest Expense Account" }
|
53
|
+
virtual_account_product { nil }
|
54
|
+
application { nil }
|
55
|
+
end
|
56
|
+
|
57
|
+
trait :tax_liability_account do
|
58
|
+
system_account { true }
|
59
|
+
name { "Interest Tax Payable Account" }
|
60
|
+
virtual_account_product { nil }
|
61
|
+
application { nil }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Alias for shared spec compatibility
|
66
|
+
factory :account, class: "Dscf::Banking::Account" do
|
67
|
+
association :virtual_account_product, factory: :virtual_account_product
|
68
|
+
association :application, factory: :application
|
69
|
+
|
70
|
+
name { "Test Account" }
|
71
|
+
currency { "ETB" }
|
72
|
+
current_balance { 0 }
|
73
|
+
available_balance { 0 }
|
74
|
+
minimum_balance { 0 }
|
75
|
+
status { :draft }
|
76
|
+
active { true }
|
77
|
+
account_properties { {} }
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :application, class: "Dscf::Banking::Application" do
|
3
|
+
association :user
|
4
|
+
association :virtual_account_product
|
5
|
+
applicant_type { :individual }
|
6
|
+
status { :draft }
|
7
|
+
sequence(:application_number) { |n| "IND#{Date.current.strftime('%Y%m%d')}#{n.to_s.rjust(4, '0')}" }
|
8
|
+
|
9
|
+
form_data do
|
10
|
+
{
|
11
|
+
first_name: Faker::Name.first_name,
|
12
|
+
last_name: Faker::Name.last_name,
|
13
|
+
date_of_birth: Faker::Date.birthday(min_age: 18, max_age: 80).to_s,
|
14
|
+
nationality: "Ethiopian",
|
15
|
+
phone: Faker::PhoneNumber.phone_number,
|
16
|
+
address: Faker::Address.full_address
|
17
|
+
}
|
18
|
+
end
|
19
|
+
submitted_at { nil }
|
20
|
+
completed_at { nil }
|
21
|
+
rejection_reason { nil }
|
22
|
+
assigned_kyc_officer { nil }
|
23
|
+
assigned_branch_manager { nil }
|
24
|
+
|
25
|
+
trait :business do
|
26
|
+
applicant_type { :business }
|
27
|
+
sequence(:application_number) { |n| "BUS#{Date.current.strftime('%Y%m%d')}#{n.to_s.rjust(4, '0')}" }
|
28
|
+
form_data do
|
29
|
+
{
|
30
|
+
business_name: Faker::Company.name,
|
31
|
+
tin_number: Faker::Number.number(digits: 10).to_s,
|
32
|
+
business_type: "Limited Company",
|
33
|
+
contact_person: Faker::Name.name,
|
34
|
+
phone: Faker::PhoneNumber.phone_number,
|
35
|
+
address: Faker::Address.full_address
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
trait :submitted do
|
41
|
+
status { :submitted }
|
42
|
+
submitted_at { 1.day.ago }
|
43
|
+
end
|
44
|
+
|
45
|
+
trait :under_review do
|
46
|
+
status { :under_review }
|
47
|
+
submitted_at { 2.days.ago }
|
48
|
+
association :assigned_kyc_officer, factory: :user
|
49
|
+
end
|
50
|
+
|
51
|
+
trait :approved do
|
52
|
+
status { :approved }
|
53
|
+
submitted_at { 3.days.ago }
|
54
|
+
association :assigned_kyc_officer, factory: :user
|
55
|
+
association :assigned_branch_manager, factory: :user
|
56
|
+
end
|
57
|
+
|
58
|
+
trait :rejected do
|
59
|
+
status { :rejected }
|
60
|
+
submitted_at { 3.days.ago }
|
61
|
+
rejection_reason { "Incomplete documentation" }
|
62
|
+
association :assigned_kyc_officer, factory: :user
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|