dscf-credit 0.2.2 → 0.2.4
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0883e69edbfba633fb3b886139de199303da27bfaa0ed9402c39d7ed036fb778'
|
4
|
+
data.tar.gz: e1ea1f2d623086de0e807c1e986cb340b41d10501056960a1f4c7f8b03b84192
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f624bce3e341b942f97bc54201f94f995db7dc8a507083c8061d6fdfc58e982f0f2c2f13b573c881b37ffc5e1170184db026c9ae247473a05aef86620620117f
|
7
|
+
data.tar.gz: ba02250152266b20ecca88cf929b2379b3931fd7d1f0dd9561d632e1928a6c15c7b83deaac2ffa8930601f8bd6de9969b7578a140a08d43aeb272070a95f5138
|
@@ -2,6 +2,26 @@ module Dscf::Credit
|
|
2
2
|
class LoanApplicationsController < ApplicationController
|
3
3
|
include Dscf::Core::Common
|
4
4
|
include Dscf::Core::ReviewableController
|
5
|
+
reviewable_context :default,
|
6
|
+
statuses: %w[pending approved rejected modify],
|
7
|
+
initial_status: "pending",
|
8
|
+
transitions: {
|
9
|
+
"pending" => %w[approved rejected modify],
|
10
|
+
"modify" => [ "pending" ]
|
11
|
+
},
|
12
|
+
actions: {
|
13
|
+
approve: {
|
14
|
+
status: "approved",
|
15
|
+
after: ->(review) {
|
16
|
+
loan_application = review.reviewable
|
17
|
+
score = loan_application.score
|
18
|
+
LoanApplicationsController.new.create_loan_profile_for_approved_application(loan_application, score)
|
19
|
+
}
|
20
|
+
},
|
21
|
+
reject: { status: "rejected", require_feedback: true },
|
22
|
+
request_modification: { status: "modify", require_feedback: true },
|
23
|
+
resubmit: { status: "pending", update_model: true }
|
24
|
+
}
|
5
25
|
|
6
26
|
def create
|
7
27
|
super do
|
@@ -125,6 +145,24 @@ module Dscf::Credit
|
|
125
145
|
end
|
126
146
|
end
|
127
147
|
|
148
|
+
def create_loan_profile_for_approved_application(loan_application, score)
|
149
|
+
profile_service = LoanProfileCreationService.new(loan_application, score)
|
150
|
+
profile_result = profile_service.create_loan_profile
|
151
|
+
|
152
|
+
unless profile_result[:success]
|
153
|
+
error_message = "Failed to create loan profile for approved application #{loan_application.id}: #{profile_result[:error]}"
|
154
|
+
Rails.logger.error error_message
|
155
|
+
# Raise error to rollback the entire transaction including score and review status
|
156
|
+
raise StandardError, error_message
|
157
|
+
else
|
158
|
+
Rails.logger.info "Loan profile created successfully for approved application #{loan_application.id}"
|
159
|
+
end
|
160
|
+
|
161
|
+
profile_result
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
|
128
166
|
private
|
129
167
|
|
130
168
|
def update_review_status(loan_application, status)
|
@@ -171,20 +209,25 @@ module Dscf::Credit
|
|
171
209
|
end
|
172
210
|
|
173
211
|
# Create loan profile for approved applications
|
174
|
-
def
|
212
|
+
def create_loan_profile_from_review(review)
|
213
|
+
loan_application = review.reviewable # Assumes Review belongs_to :reviewable (polymorphic or direct association to LoanApplication)
|
214
|
+
score = loan_application.score # Assumes score is already set on the loan application
|
215
|
+
|
216
|
+
unless score
|
217
|
+
Rails.logger.warn "No score available for loan application #{loan_application.id} during approve callback"
|
218
|
+
return
|
219
|
+
end
|
220
|
+
|
175
221
|
profile_service = LoanProfileCreationService.new(loan_application, score)
|
176
222
|
profile_result = profile_service.create_loan_profile
|
177
223
|
|
178
224
|
unless profile_result[:success]
|
179
225
|
error_message = "Failed to create loan profile for approved application #{loan_application.id}: #{profile_result[:error]}"
|
180
226
|
Rails.logger.error error_message
|
181
|
-
#
|
182
|
-
raise StandardError, error_message
|
227
|
+
raise StandardError, error_message # This will rollback the transaction in perform_review_action
|
183
228
|
else
|
184
|
-
Rails.logger.info "Loan profile created successfully for approved application #{loan_application.id}"
|
229
|
+
Rails.logger.info "Loan profile created successfully for approved application #{loan_application.id} via review callback"
|
185
230
|
end
|
186
|
-
|
187
|
-
profile_result
|
188
231
|
end
|
189
232
|
|
190
233
|
def model_params
|
data/db/seeds.rb
CHANGED
@@ -568,99 +568,6 @@ puts "Seeding loan profile scoring specs..."
|
|
568
568
|
# Note: This will be moved after loan profiles are created
|
569
569
|
|
570
570
|
# 10.5. Loan Applications (depends on banks, users, and bank branches)
|
571
|
-
puts "Seeding loan applications..."
|
572
|
-
loan_application1 = Dscf::Credit::LoanApplication.find_or_create_by(
|
573
|
-
bank: bunna_bank,
|
574
|
-
user_id: user2.id,
|
575
|
-
review_branch: bunna_head_office
|
576
|
-
) do |application|
|
577
|
-
application.backer = user1
|
578
|
-
application.bank_statement_source = "internal"
|
579
|
-
application.user_info = {
|
580
|
-
name: "Jane Smith",
|
581
|
-
phone: "+251922334455",
|
582
|
-
email: "jane.smith@example.com",
|
583
|
-
address: "123 Main St, Addis Ababa",
|
584
|
-
id_number: "ID123456789",
|
585
|
-
date_of_birth: "1985-05-15"
|
586
|
-
}
|
587
|
-
application.facilitator_info = {
|
588
|
-
business_name: "ABC Trading Company",
|
589
|
-
license_number: "LIC001234",
|
590
|
-
business_type: "retail",
|
591
|
-
years_in_business: 5,
|
592
|
-
monthly_turnover: 150000.00
|
593
|
-
}
|
594
|
-
application.bank_info = {
|
595
|
-
account_number: "123456789012",
|
596
|
-
account_holder: "Jane Smith",
|
597
|
-
bank_name: "Bunna Bank",
|
598
|
-
branch_name: "Head Office"
|
599
|
-
}
|
600
|
-
application.field_assessment = {
|
601
|
-
credit_score: 720,
|
602
|
-
risk_level: "medium",
|
603
|
-
recommendation: "approved",
|
604
|
-
assessed_by: "Field Officer A",
|
605
|
-
assessment_date: Time.current.iso8601
|
606
|
-
}
|
607
|
-
end
|
608
|
-
|
609
|
-
# Create approved review for loan_application1
|
610
|
-
Dscf::Core::Review.find_or_create_by(
|
611
|
-
reviewable: loan_application1,
|
612
|
-
reviewed_by: admin_user
|
613
|
-
) do |review|
|
614
|
-
review.status = 'approved'
|
615
|
-
review.reviewed_at = Time.current
|
616
|
-
end
|
617
|
-
|
618
|
-
loan_application2 = Dscf::Credit::LoanApplication.find_or_create_by(
|
619
|
-
bank: bunna_bank,
|
620
|
-
user_id: user3.id,
|
621
|
-
review_branch: bunna_merkato_branch
|
622
|
-
) do |application|
|
623
|
-
application.backer = user1
|
624
|
-
application.bank_statement_source = "external"
|
625
|
-
application.user_info = {
|
626
|
-
name: "Mike Johnson",
|
627
|
-
phone: "+251933445566",
|
628
|
-
email: "mike.johnson@example.com",
|
629
|
-
address: "456 Oak Ave, Addis Ababa",
|
630
|
-
id_number: "ID987654321",
|
631
|
-
date_of_birth: "1980-12-10"
|
632
|
-
}
|
633
|
-
application.facilitator_info = {
|
634
|
-
business_name: "XYZ Wholesale",
|
635
|
-
license_number: "LIC005678",
|
636
|
-
business_type: "wholesale",
|
637
|
-
years_in_business: 8,
|
638
|
-
monthly_turnover: 500000.00
|
639
|
-
}
|
640
|
-
application.bank_info = {
|
641
|
-
account_number: "987654321098",
|
642
|
-
account_holder: "Mike Johnson",
|
643
|
-
bank_name: "Commercial Bank",
|
644
|
-
branch_name: "Main Branch"
|
645
|
-
}
|
646
|
-
application.field_assessment = {
|
647
|
-
credit_score: 650,
|
648
|
-
risk_level: "high",
|
649
|
-
recommendation: "conditional_approval",
|
650
|
-
assessed_by: "Field Officer B",
|
651
|
-
assessment_date: Time.current.iso8601
|
652
|
-
}
|
653
|
-
application.score = 65.0
|
654
|
-
end
|
655
|
-
|
656
|
-
# Create pending review for loan_application2
|
657
|
-
Dscf::Core::Review.find_or_create_by(
|
658
|
-
reviewable: loan_application2,
|
659
|
-
reviewed_by: bank_admin
|
660
|
-
) do |review|
|
661
|
-
review.status = 'pending'
|
662
|
-
review.reviewed_at = Time.current
|
663
|
-
end
|
664
571
|
|
665
572
|
# 10.6. Facilitator Applications (depends on users and banks)
|
666
573
|
puts "Seeding facilitator applications..."
|
@@ -750,119 +657,6 @@ Dscf::Core::Review.find_or_create_by(
|
|
750
657
|
end
|
751
658
|
|
752
659
|
# 11. Loan Profiles (depends on loan applications)
|
753
|
-
puts "Seeding loan profiles..."
|
754
|
-
loan_profile1 = Dscf::Credit::LoanProfile.find_or_create_by(
|
755
|
-
loan_application: loan_application1
|
756
|
-
) do |profile|
|
757
|
-
profile.code = "BB000001"
|
758
|
-
profile.score = 78.5
|
759
|
-
profile.total_limit = 100000.00
|
760
|
-
end
|
761
|
-
|
762
|
-
# Create approved review for loan_profile1
|
763
|
-
Dscf::Core::Review.find_or_create_by(
|
764
|
-
reviewable: loan_profile1,
|
765
|
-
reviewed_by: admin_user
|
766
|
-
) do |review|
|
767
|
-
review.status = 'approved'
|
768
|
-
review.reviewed_at = Time.current
|
769
|
-
end
|
770
|
-
|
771
|
-
# 12. Loan Profile Scoring Specs (depends on loan profiles)
|
772
|
-
puts "Seeding loan profile scoring specs..."
|
773
|
-
Dscf::Credit::LoanProfileScoringSpec.create!(
|
774
|
-
loan_profile: loan_profile1,
|
775
|
-
scoring_input_data: {
|
776
|
-
'monthly_income' => 45000,
|
777
|
-
'credit_history_score' => 720,
|
778
|
-
'employment_type' => 'permanent',
|
779
|
-
'years_at_job' => 3,
|
780
|
-
'existing_debt' => 15000,
|
781
|
-
'average_daily_purchase' => 15000 # Wholesaler's average daily purchase volume
|
782
|
-
},
|
783
|
-
score: 78.5,
|
784
|
-
total_limit: 100000.00,
|
785
|
-
active: true,
|
786
|
-
created_by: admin_user
|
787
|
-
)
|
788
|
-
|
789
|
-
# 11. Eligible Credit Lines (depends on loan profiles and credit lines)
|
790
|
-
puts "Seeding eligible credit lines..."
|
791
|
-
Dscf::Credit::EligibleCreditLine.create!(
|
792
|
-
loan_profile: loan_profile1,
|
793
|
-
credit_line: credit_line1,
|
794
|
-
credit_limit: 75000.00,
|
795
|
-
available_limit: 67500.00,
|
796
|
-
risk: 0.35
|
797
|
-
)
|
798
|
-
|
799
|
-
Dscf::Credit::EligibleCreditLine.create!(
|
800
|
-
loan_profile: loan_profile1,
|
801
|
-
credit_line: credit_line2,
|
802
|
-
credit_limit: 50000.00,
|
803
|
-
available_limit: 42500.00,
|
804
|
-
risk: 0.45
|
805
|
-
)
|
806
|
-
|
807
|
-
# 12. Loans (depends on loan profiles and credit lines)
|
808
|
-
puts "Seeding loans..."
|
809
|
-
loan1 = Dscf::Credit::Loan.create!(
|
810
|
-
loan_profile: loan_profile1,
|
811
|
-
credit_line: credit_line1,
|
812
|
-
status: 'active',
|
813
|
-
principal_amount: 50000.00,
|
814
|
-
remaining_amount: 50000.00,
|
815
|
-
due_date: 3.months.from_now.to_date,
|
816
|
-
disbursed_at: 1.day.ago,
|
817
|
-
active: true
|
818
|
-
)
|
819
|
-
|
820
|
-
# 12.5. Loan Accruals (depends on loans)
|
821
|
-
puts "Seeding loan accruals..."
|
822
|
-
Dscf::Credit::LoanAccrual.create!(
|
823
|
-
loan: loan1,
|
824
|
-
accrual_type: 'interest',
|
825
|
-
amount: 250.00,
|
826
|
-
applied_on: 1.month.ago.to_date,
|
827
|
-
status: 'pending'
|
828
|
-
)
|
829
|
-
|
830
|
-
Dscf::Credit::LoanAccrual.create!(
|
831
|
-
loan: loan1,
|
832
|
-
accrual_type: 'facilitation_fee',
|
833
|
-
amount: 1000.00,
|
834
|
-
applied_on: 1.day.ago.to_date,
|
835
|
-
status: 'paid'
|
836
|
-
)
|
837
|
-
|
838
|
-
# 13. Loan Transactions (depends on loans)
|
839
|
-
puts "Seeding loan transactions..."
|
840
|
-
Dscf::Credit::LoanTransaction.create!(
|
841
|
-
loan: loan1,
|
842
|
-
transaction_type: 'disbursement',
|
843
|
-
amount: 50000.00,
|
844
|
-
transaction_reference: "TXN-DISB-#{Time.current.to_i}",
|
845
|
-
status: 'completed'
|
846
|
-
)
|
847
|
-
|
848
|
-
Dscf::Credit::LoanTransaction.create!(
|
849
|
-
loan: loan1,
|
850
|
-
transaction_type: 'interest_accrual',
|
851
|
-
amount: 2500.00,
|
852
|
-
transaction_reference: "TXN-INT-#{Time.current.to_i}",
|
853
|
-
status: 'completed'
|
854
|
-
)
|
855
|
-
|
856
|
-
# 14. Daily Routine Transactions (depends on loans)
|
857
|
-
puts "Seeding daily routine transactions..."
|
858
|
-
Dscf::Credit::DailyRoutineTransaction.create!(
|
859
|
-
loan: loan1,
|
860
|
-
routine_type: 'interest_calculation',
|
861
|
-
amount: 83.33,
|
862
|
-
status: 'completed',
|
863
|
-
initiated_at: Date.current.beginning_of_day,
|
864
|
-
approved_at: Date.current.beginning_of_day + 1.hour
|
865
|
-
)
|
866
660
|
|
867
661
|
puts "DSCF Credit Engine seed data completed successfully!"
|
868
662
|
puts "Created sample data for all models with proper relationships."
|
data/lib/dscf/credit/version.rb
CHANGED