bscf-core 0.4.97 → 0.4.98
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/bscf/core/loan.rb +28 -0
- data/app/models/bscf/core/loan_repayment.rb +45 -0
- data/app/models/bscf/core/virtual_account.rb +26 -2
- data/db/migrate/20250720123239_create_bscf_core_loans.rb +16 -0
- data/db/migrate/20250720131241_create_bscf_core_loan_repayments.rb +12 -0
- data/db/migrate/20250720184059_nullable_occupation_source_of_funds.rb +6 -0
- data/lib/bscf/core/version.rb +1 -1
- data/spec/factories/bscf/core/loan_repayments.rb +9 -0
- data/spec/factories/bscf/core/loans.rb +12 -0
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e21ece92c538dd2de05e92798fdbcdb484515fb2b4d51579a49a7743cd845908
|
4
|
+
data.tar.gz: 323646d95a5005ddf6ba62a24b5b3d0184ab70d2e570cb969104be978e1f378a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19e9f2eb4f89d4849965264b20c08cff31570de7f4c67bd595900475a550986a44b8d803f93e3b82b44db1740ed4ad1c66e3c4f61c10b4e8d8dcf78a82264c88
|
7
|
+
data.tar.gz: 72ab3727d5ef514d63f5f8219e7635ec0c5446c6cc2993bd67e0f03084602c9bee6fdf67fe195f612aa5ca37621936efa43ee1e511d2971ba59e80fa9a676555
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Bscf::Core
|
2
|
+
class Loan < ApplicationRecord
|
3
|
+
belongs_to :virtual_account, class_name: "Bscf::Core::VirtualAccount"
|
4
|
+
belongs_to :disbursement_transaction, class_name: "Bscf::Core::VirtualAccountTransaction"
|
5
|
+
|
6
|
+
enum :status, { disbursed: 0, late: 1, paid: 2 }
|
7
|
+
|
8
|
+
validates :principal_amount, :interest_amount, :unpaid_balance, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
9
|
+
validates :status, :due_date, presence: true
|
10
|
+
validates :status, inclusion: { in: statuses.keys }
|
11
|
+
|
12
|
+
validate :paid_at_requires_zero_balance_and_paid_status
|
13
|
+
validate :paid_status_requires_zero_balance
|
14
|
+
|
15
|
+
def paid_at_requires_zero_balance_and_paid_status
|
16
|
+
if paid_at.present?
|
17
|
+
errors.add(:paid_at, "can only be set if loan is marked as paid") if status != "paid"
|
18
|
+
errors.add(:paid_at, "can only be set if unpaid balance is zero") if unpaid_balance.to_f > 0
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def paid_status_requires_zero_balance
|
23
|
+
if status == "paid" && unpaid_balance.to_f > 0
|
24
|
+
errors.add(:status, "can only be set to paid if unpaid balance is zero")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Bscf::Core
|
2
|
+
class LoanRepayment < ApplicationRecord
|
3
|
+
belongs_to :loan, class_name: "Bscf::Core::Loan"
|
4
|
+
belongs_to :repayment_transaction, class_name: "Bscf::Core::VirtualAccountTransaction"
|
5
|
+
|
6
|
+
validates :amount, presence: true, numericality: { greater_than: 0 }
|
7
|
+
validates :payment_date, presence: true
|
8
|
+
validate :amount_cannot_exceed_unpaid_balance
|
9
|
+
validate :loan_cannot_be_already_paid
|
10
|
+
|
11
|
+
after_create :apply_repayment_to_loan
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def apply_repayment_to_loan
|
16
|
+
loan.with_lock do
|
17
|
+
loan.unpaid_balance -= amount
|
18
|
+
loan.unpaid_balance = 0 if loan.unpaid_balance.negative?
|
19
|
+
|
20
|
+
if loan.unpaid_balance.zero?
|
21
|
+
loan.status = "paid"
|
22
|
+
loan.paid_at = payment_date
|
23
|
+
end
|
24
|
+
|
25
|
+
loan.save!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def amount_cannot_exceed_unpaid_balance
|
30
|
+
return if loan.blank? || amount.blank?
|
31
|
+
|
32
|
+
if amount > loan.unpaid_balance
|
33
|
+
errors.add(:amount, "cannot be greater than the loan's unpaid balance")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def loan_cannot_be_already_paid
|
38
|
+
return if loan.blank?
|
39
|
+
|
40
|
+
if loan.paid?
|
41
|
+
errors.add(:loan, "is already marked as paid")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -76,9 +76,33 @@ module Bscf
|
|
76
76
|
def generate_account_number
|
77
77
|
return if account_number.present?
|
78
78
|
|
79
|
-
|
79
|
+
last_account = self.class.maximum(:account_number)
|
80
|
+
last_seq = last_account ? last_account[-6..-1].to_i : 0
|
80
81
|
seq = (last_seq + 1).to_s.rjust(6, "0")
|
81
|
-
|
82
|
+
|
83
|
+
branch_part = branch_code.to_s.rjust(3, "0")[0..2]
|
84
|
+
product_part = map_product_scheme_to_digit(product_scheme)
|
85
|
+
voucher_part = map_voucher_type_to_digit(voucher_type)
|
86
|
+
|
87
|
+
self.account_number = "#{branch_part}#{product_part}#{voucher_part}#{seq}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def map_product_scheme_to_digit(scheme)
|
91
|
+
case scheme
|
92
|
+
when "SAVINGS" then "1"
|
93
|
+
when "CURRENT" then "2"
|
94
|
+
when "LOAN" then "3"
|
95
|
+
else "0"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def map_voucher_type_to_digit(type)
|
100
|
+
case type
|
101
|
+
when "REGULAR" then "1"
|
102
|
+
when "SPECIAL" then "2"
|
103
|
+
when "TEMPORARY" then "3"
|
104
|
+
else "0"
|
105
|
+
end
|
82
106
|
end
|
83
107
|
|
84
108
|
def transfer_to!(to_account, amount)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateBscfCoreLoans < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_loans do |t|
|
4
|
+
t.references :virtual_account, null: false, foreign_key: { to_table: :bscf_core_virtual_accounts }
|
5
|
+
t.references :disbursement_transaction, null: false, foreign_key: { to_table: :bscf_core_virtual_account_transactions }
|
6
|
+
t.float :principal_amount, null: false, default: 0.0
|
7
|
+
t.float :interest_amount, null: false, default: 0.0
|
8
|
+
t.float :unpaid_balance, null: false, default: 0.0
|
9
|
+
t.integer :status, null: false, default: 0
|
10
|
+
t.date :due_date, null: false, default: Date.today + 15.days
|
11
|
+
t.date :paid_at, null: true
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateBscfCoreLoanRepayments < ActiveRecord::Migration[8.0]
|
2
|
+
def change
|
3
|
+
create_table :bscf_core_loan_repayments do |t|
|
4
|
+
t.references :loan, null: false, foreign_key: { to_table: :bscf_core_loans }
|
5
|
+
t.references :repayment_transaction, null: false, foreign_key: { to_table: :bscf_core_virtual_account_transactions }
|
6
|
+
t.float :amount, null: false
|
7
|
+
t.date :payment_date, null: false, default: Date.today
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/bscf/core/version.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
FactoryBot.define do
|
2
|
+
factory :loan, class: 'Bscf::Core::Loan' do
|
3
|
+
association :virtual_account
|
4
|
+
association :disbursement_transaction, factory: :virtual_account_transaction
|
5
|
+
|
6
|
+
principal_amount { 200.5 }
|
7
|
+
interest_amount { 10.5 }
|
8
|
+
unpaid_balance { 210.5 }
|
9
|
+
status { 0 }
|
10
|
+
due_date { Date.today + 15.days }
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bscf-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.98
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Asrat
|
@@ -296,6 +296,8 @@ files:
|
|
296
296
|
- app/models/bscf/core/delivery_order_item.rb
|
297
297
|
- app/models/bscf/core/invoice.rb
|
298
298
|
- app/models/bscf/core/invoice_item.rb
|
299
|
+
- app/models/bscf/core/loan.rb
|
300
|
+
- app/models/bscf/core/loan_repayment.rb
|
299
301
|
- app/models/bscf/core/marketplace_listing.rb
|
300
302
|
- app/models/bscf/core/order.rb
|
301
303
|
- app/models/bscf/core/order_item.rb
|
@@ -364,6 +366,9 @@ files:
|
|
364
366
|
- db/migrate/20250624062746_rename_business_id_to_user_id_in_bscf_core_business_documents.rb
|
365
367
|
- db/migrate/20250624122210_add_document_type_to_business_documents.rb
|
366
368
|
- db/migrate/20250714201747_add_optimized_route_to_delivery_order.rb
|
369
|
+
- db/migrate/20250720123239_create_bscf_core_loans.rb
|
370
|
+
- db/migrate/20250720131241_create_bscf_core_loan_repayments.rb
|
371
|
+
- db/migrate/20250720184059_nullable_occupation_source_of_funds.rb
|
367
372
|
- lib/bscf/core.rb
|
368
373
|
- lib/bscf/core/engine.rb
|
369
374
|
- lib/bscf/core/version.rb
|
@@ -379,6 +384,8 @@ files:
|
|
379
384
|
- spec/factories/bscf/core/delivery_orders.rb
|
380
385
|
- spec/factories/bscf/core/invoice_items.rb
|
381
386
|
- spec/factories/bscf/core/invoices.rb
|
387
|
+
- spec/factories/bscf/core/loan_repayments.rb
|
388
|
+
- spec/factories/bscf/core/loans.rb
|
382
389
|
- spec/factories/bscf/core/marketplace_listings.rb
|
383
390
|
- spec/factories/bscf/core/order_items.rb
|
384
391
|
- spec/factories/bscf/core/orders.rb
|