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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +0 -0
  3. data/README.md +0 -0
  4. data/Rakefile +0 -0
  5. data/app/controllers/dscf/banking/accounts_controller.rb +152 -0
  6. data/app/controllers/dscf/banking/application_controller.rb +0 -0
  7. data/app/controllers/dscf/banking/applications_controller.rb +113 -0
  8. data/app/controllers/dscf/banking/interest_configurations_controller.rb +0 -0
  9. data/app/controllers/dscf/banking/interest_rate_tiers_controller.rb +0 -0
  10. data/app/controllers/dscf/banking/interest_rate_types_controller.rb +0 -0
  11. data/app/controllers/dscf/banking/product_approvals_controller.rb +0 -0
  12. data/app/controllers/dscf/banking/product_categories_controller.rb +0 -0
  13. data/app/controllers/dscf/banking/transaction_types_controller.rb +27 -0
  14. data/app/controllers/dscf/banking/transactions_controller.rb +275 -0
  15. data/app/controllers/dscf/banking/virtual_account_products_controller.rb +0 -0
  16. data/app/jobs/dscf/banking/application_job.rb +0 -0
  17. data/app/mailers/dscf/banking/application_mailer.rb +0 -0
  18. data/app/models/concerns/dscf/banking/auditable.rb +0 -0
  19. data/app/models/dscf/banking/account.rb +110 -0
  20. data/app/models/dscf/banking/application.rb +70 -0
  21. data/app/models/dscf/banking/application_record.rb +0 -0
  22. data/app/models/dscf/banking/interest_configuration.rb +0 -0
  23. data/app/models/dscf/banking/interest_rate_tier.rb +0 -0
  24. data/app/models/dscf/banking/interest_rate_type.rb +0 -0
  25. data/app/models/dscf/banking/product_approval.rb +0 -0
  26. data/app/models/dscf/banking/product_audit_log.rb +0 -0
  27. data/app/models/dscf/banking/product_category.rb +0 -0
  28. data/app/models/dscf/banking/transaction.rb +68 -0
  29. data/app/models/dscf/banking/transaction_type.rb +20 -0
  30. data/app/models/dscf/banking/virtual_account_product.rb +0 -0
  31. data/app/serializers/dscf/banking/account_serializer.rb +11 -0
  32. data/app/serializers/dscf/banking/application_serializer.rb +16 -0
  33. data/app/serializers/dscf/banking/interest_configuration_serializer.rb +0 -0
  34. data/app/serializers/dscf/banking/interest_rate_tier_serializer.rb +0 -0
  35. data/app/serializers/dscf/banking/interest_rate_type_serializer.rb +0 -0
  36. data/app/serializers/dscf/banking/product_approval_serializer.rb +0 -0
  37. data/app/serializers/dscf/banking/product_category_serializer.rb +0 -0
  38. data/app/serializers/dscf/banking/transaction_serializer.rb +19 -0
  39. data/app/serializers/dscf/banking/transaction_type_serializer.rb +9 -0
  40. data/app/serializers/dscf/banking/virtual_account_product_serializer.rb +0 -0
  41. data/app/services/dscf/banking/account_creation_service.rb +53 -0
  42. data/app/services/dscf/banking/base_transaction_service.rb +99 -0
  43. data/app/services/dscf/banking/deposit_service.rb +97 -0
  44. data/app/services/dscf/banking/transfer_service.rb +78 -0
  45. data/app/services/dscf/banking/withdrawal_service.rb +100 -0
  46. data/config/routes.rb +27 -0
  47. data/db/migrate/20250830211002_create_dscf_banking_product_categories.rb +0 -0
  48. data/db/migrate/20250830211027_create_dscf_banking_interest_rate_types.rb +0 -0
  49. data/db/migrate/20250831063605_add_code_and_remove_fields_from_interest_rate_types.rb +0 -0
  50. data/db/migrate/20250831064917_create_dscf_banking_virtual_account_products.rb +0 -0
  51. data/db/migrate/20250831072627_create_dscf_banking_interest_configurations.rb +0 -0
  52. data/db/migrate/20250831080745_create_dscf_banking_interest_rate_tiers.rb +0 -0
  53. data/db/migrate/20250831082356_create_dscf_banking_product_approvals.rb +0 -0
  54. data/db/migrate/20250831083907_create_dscf_banking_product_audit_logs.rb +0 -0
  55. data/db/migrate/20250831084706_allow_null_virtual_account_product_id_in_product_audit_logs.rb +0 -0
  56. data/db/migrate/20250912193134_create_dscf_banking_applications.rb +20 -0
  57. data/db/migrate/20250912203527_create_dscf_banking_accounts.rb +21 -0
  58. data/db/migrate/20250919084147_add_account_type_to_accounts.rb +6 -0
  59. data/db/migrate/20250919084927_make_account_associations_optional.rb +6 -0
  60. data/db/migrate/20250919182831_create_dscf_banking_transaction_types.rb +14 -0
  61. data/db/migrate/20250919184220_create_dscf_banking_transactions.rb +21 -0
  62. data/db/seeds.rb +125 -0
  63. data/lib/dscf/banking/engine.rb +0 -0
  64. data/lib/dscf/banking/version.rb +1 -1
  65. data/lib/dscf/banking.rb +0 -0
  66. data/lib/tasks/dscf/banking_tasks.rake +0 -0
  67. data/spec/factories/dscf/banking/accounts.rb +79 -0
  68. data/spec/factories/dscf/banking/applications.rb +65 -0
  69. data/spec/factories/dscf/banking/interest_configurations.rb +0 -0
  70. data/spec/factories/dscf/banking/interest_rate_tiers.rb +0 -0
  71. data/spec/factories/dscf/banking/interest_rate_types.rb +0 -0
  72. data/spec/factories/dscf/banking/product_approvals.rb +0 -0
  73. data/spec/factories/dscf/banking/product_audit_logs.rb +0 -0
  74. data/spec/factories/dscf/banking/product_categories.rb +0 -0
  75. data/spec/factories/dscf/banking/transaction_types.rb +56 -0
  76. data/spec/factories/dscf/banking/transactions.rb +52 -0
  77. data/spec/factories/dscf/banking/virtual_account_products.rb +0 -0
  78. 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
@@ -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,6 @@
1
+ class AddAccountTypeToAccounts < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :dscf_banking_accounts, :system_account, :boolean, default: false, null: false
4
+ add_index :dscf_banking_accounts, :system_account
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class MakeAccountAssociationsOptional < ActiveRecord::Migration[8.0]
2
+ def change
3
+ change_column_null :dscf_banking_accounts, :virtual_account_product_id, true
4
+ change_column_null :dscf_banking_accounts, :application_id, true
5
+ end
6
+ 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!"
File without changes
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Banking
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.2"
4
4
  end
5
5
  end
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