dscf-credit 0.4.46 → 0.4.48
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/controllers/dscf/credit/categories_controller.rb +6 -8
- data/app/controllers/dscf/credit/credit_limit_calculations_controller.rb +3 -3
- data/app/controllers/dscf/credit/credit_lines_controller.rb +7 -7
- data/app/controllers/dscf/credit/credit_products_controller.rb +66 -0
- data/app/controllers/dscf/credit/loan_applications_controller.rb +15 -15
- data/app/controllers/dscf/credit/loan_profiles_controller.rb +5 -5
- data/app/controllers/dscf/credit/scoring_tables_controller.rb +4 -4
- data/app/models/dscf/credit/category.rb +2 -6
- data/app/models/dscf/credit/credit_line.rb +13 -3
- data/app/models/dscf/credit/credit_product.rb +26 -0
- data/app/models/dscf/credit/loan_application.rb +2 -2
- data/app/models/dscf/credit/scoring_table.rb +2 -2
- data/app/serializers/dscf/credit/category_serializer.rb +1 -3
- data/app/serializers/dscf/credit/credit_line_serializer.rb +1 -1
- data/app/serializers/dscf/credit/credit_product_serializer.rb +13 -0
- data/app/serializers/dscf/credit/loan_application_serializer.rb +1 -1
- data/app/serializers/dscf/credit/scoring_table_serializer.rb +1 -1
- data/app/services/dscf/credit/credit_scoring_engine.rb +4 -4
- data/app/services/dscf/credit/facility_limit_calculation_engine.rb +10 -10
- data/app/services/dscf/credit/loan_profile_creation_service.rb +3 -3
- data/config/locales/en.yml +24 -0
- data/config/routes.rb +9 -0
- data/db/migrate/{20260219000003_create_dscf_credit_categories.rb → 20260219000030_create_dscf_credit_categories.rb} +0 -6
- data/db/migrate/20260219000040_create_dscf_credit_credit_products.rb +17 -0
- data/db/migrate/{20260219000005_create_dscf_credit_credit_lines.rb → 20260219000060_create_dscf_credit_credit_lines.rb} +1 -1
- data/db/migrate/{20260219000013_create_dscf_credit_loan_applications.rb → 20260219000140_create_dscf_credit_loan_applications.rb} +1 -1
- data/db/seeds.rb +40 -8
- data/lib/dscf/credit/version.rb +1 -1
- data/spec/factories/dscf/credit/categories.rb +0 -1
- data/spec/factories/dscf/credit/credit_lines.rb +6 -2
- data/spec/factories/dscf/credit/credit_products.rb +31 -0
- data/spec/factories/dscf/credit/loan_applications.rb +1 -1
- metadata +35 -31
- data/db/dev_seeds.rb +0 -1235
- /data/db/migrate/{20260219000001_create_dscf_credit_banks.rb → 20260219000010_create_dscf_credit_banks.rb} +0 -0
- /data/db/migrate/{20260219000002_create_dscf_credit_scoring_tables.rb → 20260219000020_create_dscf_credit_scoring_tables.rb} +0 -0
- /data/db/migrate/{20260219000004_create_dscf_credit_bank_branches.rb → 20260219000050_create_dscf_credit_bank_branches.rb} +0 -0
- /data/db/migrate/{20260219000006_create_dscf_credit_information_sources.rb → 20260219000070_create_dscf_credit_information_sources.rb} +0 -0
- /data/db/migrate/{20260219000007_create_dscf_credit_scoring_parameters.rb → 20260219000080_create_dscf_credit_scoring_parameters.rb} +0 -0
- /data/db/migrate/{20260219000008_create_dscf_credit_credit_line_specs.rb → 20260219000090_create_dscf_credit_credit_line_specs.rb} +0 -0
- /data/db/migrate/{20260219000009_create_dscf_credit_scoring_table_parameters.rb → 20260219000100_create_dscf_credit_scoring_table_parameters.rb} +0 -0
- /data/db/migrate/{20260219000010_create_dscf_credit_scoring_table_normalizers.rb → 20260219000110_create_dscf_credit_scoring_table_normalizers.rb} +0 -0
- /data/db/migrate/{20260219000011_create_dscf_credit_system_config_definitions.rb → 20260219000120_create_dscf_credit_system_config_definitions.rb} +0 -0
- /data/db/migrate/{20260219000012_create_dscf_credit_system_configs.rb → 20260219000130_create_dscf_credit_system_configs.rb} +0 -0
- /data/db/migrate/{20260219000014_create_dscf_credit_loan_profiles.rb → 20260219000150_create_dscf_credit_loan_profiles.rb} +0 -0
- /data/db/migrate/{20260219000015_create_dscf_credit_scoring_results.rb → 20260219000160_create_dscf_credit_scoring_results.rb} +0 -0
- /data/db/migrate/{20260219000016_create_dscf_credit_facilitator_applications.rb → 20260219000170_create_dscf_credit_facilitator_applications.rb} +0 -0
- /data/db/migrate/{20260219000017_create_dscf_credit_facilitators.rb → 20260219000180_create_dscf_credit_facilitators.rb} +0 -0
- /data/db/migrate/{20260219000018_create_dscf_credit_facilitator_performances.rb → 20260219000190_create_dscf_credit_facilitator_performances.rb} +0 -0
- /data/db/migrate/{20260219000019_create_dscf_credit_loans.rb → 20260219000200_create_dscf_credit_loans.rb} +0 -0
- /data/db/migrate/{20260219000020_create_dscf_credit_loan_transactions.rb → 20260219000210_create_dscf_credit_loan_transactions.rb} +0 -0
- /data/db/migrate/{20260219000021_create_dscf_credit_daily_routine_transactions.rb → 20260219000220_create_dscf_credit_daily_routine_transactions.rb} +0 -0
- /data/db/migrate/{20260219000022_create_dscf_credit_accounting_audit_requests.rb → 20260219000230_create_dscf_credit_accounting_audit_requests.rb} +0 -0
- /data/db/migrate/{20260219000023_create_dscf_credit_failed_operations_logs.rb → 20260219000240_create_dscf_credit_failed_operations_logs.rb} +0 -0
- /data/db/migrate/{20260219000024_create_dscf_credit_accounting_entries.rb → 20260219000250_create_dscf_credit_accounting_entries.rb} +0 -0
- /data/db/migrate/{20260219000025_create_dscf_credit_bank_staff.rb → 20260219000260_create_dscf_credit_bank_staff.rb} +0 -0
- /data/db/migrate/{20260219000026_create_dscf_credit_eligible_credit_lines.rb → 20260219000270_create_dscf_credit_eligible_credit_lines.rb} +0 -0
- /data/db/migrate/{20260219000027_create_dscf_credit_loan_accruals.rb → 20260219000280_create_dscf_credit_loan_accruals.rb} +0 -0
- /data/db/migrate/{20260219000028_create_dscf_credit_loan_application_data.rb → 20260219000290_create_dscf_credit_loan_application_data.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 202f7f16da67e4370a2e290955089d9872866d8c574d3e2a8fb61a980c2dcfff
|
|
4
|
+
data.tar.gz: 3ce121d8bc09a5dcc475aed9e4376a1558a83da30032ffe4f5534cf3ddc32ba6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: daaec706ba7d573f78a42d81e9c25c794b3db39c1c68556fdd633c3a013604c5f034f689c2ff34a3f2f0d19c4b385d3da0a14c404f1942f55beed99736917653
|
|
7
|
+
data.tar.gz: 18dfaee9c7c9b25bcf9847f1c98004e1ec2bace0bbe987613913ff7db164c98cb8b6233e3db6736a1d1dcfb7d233b801a25a145828928fd6f2d3d65ab34741c4
|
|
@@ -10,26 +10,24 @@ module Dscf
|
|
|
10
10
|
:bank_id,
|
|
11
11
|
:category_type,
|
|
12
12
|
:name,
|
|
13
|
-
:description
|
|
14
|
-
:document_reference,
|
|
15
|
-
:scoring_table_id
|
|
13
|
+
:description
|
|
16
14
|
)
|
|
17
15
|
end
|
|
18
16
|
|
|
19
17
|
def eager_loaded_associations
|
|
20
|
-
[ :bank, :
|
|
18
|
+
[ :bank, :scoring_parameters ]
|
|
21
19
|
end
|
|
22
20
|
|
|
23
21
|
def allowed_order_columns
|
|
24
|
-
%w[id category_type name description
|
|
22
|
+
%w[id category_type name description created_at updated_at]
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
def default_serializer_includes
|
|
28
26
|
{
|
|
29
27
|
index: [],
|
|
30
|
-
show: [ :bank, :
|
|
31
|
-
create: [ :bank
|
|
32
|
-
update: [ :bank, :
|
|
28
|
+
show: [ :bank, :scoring_parameters ],
|
|
29
|
+
create: [ :bank ],
|
|
30
|
+
update: [ :bank, :scoring_parameters ]
|
|
33
31
|
}
|
|
34
32
|
end
|
|
35
33
|
end
|
|
@@ -2,9 +2,9 @@ module Dscf::Credit
|
|
|
2
2
|
class CreditLimitCalculationsController < ApplicationController
|
|
3
3
|
def create
|
|
4
4
|
loan_profile = Dscf::Credit::LoanProfile.find(params[:loan_profile_id])
|
|
5
|
-
|
|
5
|
+
credit_product = Dscf::Credit::CreditProduct.find(params[:credit_product_id])
|
|
6
6
|
|
|
7
|
-
engine = Dscf::Credit::FacilityLimitCalculationEngine.new(loan_profile.id,
|
|
7
|
+
engine = Dscf::Credit::FacilityLimitCalculationEngine.new(loan_profile.id, credit_product.id)
|
|
8
8
|
result = engine.calculate_facility_limits
|
|
9
9
|
|
|
10
10
|
if result[:success]
|
|
@@ -13,7 +13,7 @@ module Dscf::Credit
|
|
|
13
13
|
"credit_limit_calculation.success.create",
|
|
14
14
|
data: {
|
|
15
15
|
loan_profile: loan_profile,
|
|
16
|
-
|
|
16
|
+
credit_product: credit_product,
|
|
17
17
|
eligible_credit_lines: result[:data],
|
|
18
18
|
calculation_summary: {
|
|
19
19
|
total_credit_lines_processed: result[:data]&.size || 0,
|
|
@@ -34,7 +34,7 @@ module Dscf::Credit
|
|
|
34
34
|
def model_params
|
|
35
35
|
params.require(:credit_line).permit(
|
|
36
36
|
:bank_id,
|
|
37
|
-
:
|
|
37
|
+
:credit_product_id,
|
|
38
38
|
:name,
|
|
39
39
|
:code,
|
|
40
40
|
:description,
|
|
@@ -44,7 +44,7 @@ module Dscf::Credit
|
|
|
44
44
|
|
|
45
45
|
def eager_loaded_associations
|
|
46
46
|
[
|
|
47
|
-
:bank, :
|
|
47
|
+
:bank, :credit_product, :created_by, :loans, :eligible_credit_lines,
|
|
48
48
|
credit_line_specs: :base_scoring_parameter,
|
|
49
49
|
reviews: { reviewed_by: :user_profile },
|
|
50
50
|
audit_logs: :actor
|
|
@@ -52,21 +52,21 @@ module Dscf::Credit
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def allowed_order_columns
|
|
55
|
-
%w[id name code created_at updated_at
|
|
55
|
+
%w[id name code created_at updated_at credit_product_id]
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def default_serializer_includes
|
|
59
59
|
{
|
|
60
|
-
index: [ :bank, :
|
|
60
|
+
index: [ :bank, :credit_product, reviews: { reviewed_by: :user_profile } ],
|
|
61
61
|
show: [
|
|
62
|
-
:bank, :
|
|
62
|
+
:bank, :credit_product, :created_by, :loans, :eligible_credit_lines,
|
|
63
63
|
credit_line_specs: :base_scoring_parameter,
|
|
64
64
|
reviews: { reviewed_by: :user_profile },
|
|
65
65
|
audit_logs: :actor
|
|
66
66
|
],
|
|
67
|
-
create: [ :bank, :
|
|
67
|
+
create: [ :bank, :credit_product, :created_by, :reviews ],
|
|
68
68
|
update: [
|
|
69
|
-
:bank, :
|
|
69
|
+
:bank, :credit_product, :created_by, :credit_line_specs, :loans, :eligible_credit_lines,
|
|
70
70
|
reviews: { reviewed_by: :user_profile }
|
|
71
71
|
]
|
|
72
72
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Credit
|
|
3
|
+
class CreditProductsController < ApplicationController
|
|
4
|
+
include Dscf::Core::Common
|
|
5
|
+
include Dscf::Core::ReviewableController
|
|
6
|
+
include Dscf::Core::AuditableController
|
|
7
|
+
|
|
8
|
+
auditable associated: [ :reviews ],
|
|
9
|
+
on: %i[approve submit reject request_modification resubmit]
|
|
10
|
+
|
|
11
|
+
auditable on: %i[create],
|
|
12
|
+
associated: { reviews: { only: [ :status ] } }
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
super do
|
|
16
|
+
credit_product = @clazz.new(model_params)
|
|
17
|
+
credit_product.reviews.build(status: "draft", context: "default")
|
|
18
|
+
credit_product
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def update
|
|
23
|
+
unless @obj.editable?
|
|
24
|
+
return render_error(
|
|
25
|
+
errors: [ "Cannot update credit product after submission. Use modification request workflow instead." ],
|
|
26
|
+
status: :unprocessable_entity
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def model_params
|
|
35
|
+
params.require(:credit_product).permit(
|
|
36
|
+
:bank_id,
|
|
37
|
+
:scoring_table_id,
|
|
38
|
+
:name,
|
|
39
|
+
:description,
|
|
40
|
+
:document_reference
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def eager_loaded_associations
|
|
45
|
+
[
|
|
46
|
+
:bank, :scoring_table, :credit_lines,
|
|
47
|
+
reviews: { reviewed_by: :user_profile },
|
|
48
|
+
audit_logs: :actor
|
|
49
|
+
]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def allowed_order_columns
|
|
53
|
+
%w[id name description created_at updated_at bank_id]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def default_serializer_includes
|
|
57
|
+
{
|
|
58
|
+
index: [ :bank, reviews: { reviewed_by: :user_profile } ],
|
|
59
|
+
show: [ :bank, :scoring_table, :credit_lines, reviews: { reviewed_by: :user_profile }, audit_logs: :actor ],
|
|
60
|
+
create: [ :bank, :reviews ],
|
|
61
|
+
update: [ :bank, :scoring_table, reviews: { reviewed_by: :user_profile }, audit_logs: :actor ]
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -32,7 +32,7 @@ module Dscf::Credit
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
scoring_result_data = {
|
|
35
|
-
scoring_table_id: loan_application.
|
|
35
|
+
scoring_table_id: loan_application.credit_product&.scoring_table&.id,
|
|
36
36
|
scoring_input_data: input_snapshot,
|
|
37
37
|
breakdown: {} # Breakdown unavailable for manually-approved pending applications
|
|
38
38
|
}
|
|
@@ -100,11 +100,11 @@ module Dscf::Credit
|
|
|
100
100
|
return render_error(errors: [ "Information source '#{source_code}' not found" ], status: :not_found)
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
scoring_table =
|
|
103
|
+
credit_product = @obj.credit_product
|
|
104
|
+
scoring_table = credit_product&.scoring_table
|
|
105
105
|
|
|
106
106
|
unless scoring_table
|
|
107
|
-
return render_error(errors: [ "No scoring table configured for this loan application's
|
|
107
|
+
return render_error(errors: [ "No scoring table configured for this loan application's credit product" ], status: :unprocessable_entity)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# Load parameters for this source with normalizers
|
|
@@ -156,7 +156,7 @@ module Dscf::Credit
|
|
|
156
156
|
|
|
157
157
|
if result[:success]
|
|
158
158
|
scoring_result_data = {
|
|
159
|
-
|
|
159
|
+
scoring_table_id: loan_application.credit_product&.scoring_table&.id,
|
|
160
160
|
breakdown: result[:breakdown],
|
|
161
161
|
scoring_input_data: build_scoring_input_snapshot(loan_application)
|
|
162
162
|
}
|
|
@@ -249,7 +249,7 @@ module Dscf::Credit
|
|
|
249
249
|
|
|
250
250
|
# Build feedback message based on status and score
|
|
251
251
|
def build_review_feedback(status, score, loan_application = nil)
|
|
252
|
-
scoring_table = loan_application&.
|
|
252
|
+
scoring_table = loan_application&.credit_product&.scoring_table || @obj&.credit_product&.scoring_table
|
|
253
253
|
passing = scoring_table&.passing_score || 60.0
|
|
254
254
|
pending_thresh = scoring_table&.pending_threshold || 50.0
|
|
255
255
|
|
|
@@ -275,13 +275,13 @@ module Dscf::Credit
|
|
|
275
275
|
end
|
|
276
276
|
|
|
277
277
|
def build_eligibility_response(loan_application)
|
|
278
|
-
|
|
279
|
-
return [] unless
|
|
278
|
+
credit_product = loan_application.credit_product
|
|
279
|
+
return [] unless credit_product
|
|
280
280
|
|
|
281
281
|
score = loan_application.score.to_f
|
|
282
282
|
loan_profile = loan_application.loan_profile
|
|
283
283
|
|
|
284
|
-
|
|
284
|
+
credit_product.credit_lines.includes(credit_line_specs: :base_scoring_parameter).map do |credit_line|
|
|
285
285
|
spec = credit_line.credit_line_specs.active.order(created_at: :desc).first
|
|
286
286
|
next unless spec
|
|
287
287
|
|
|
@@ -326,7 +326,7 @@ module Dscf::Credit
|
|
|
326
326
|
def model_params
|
|
327
327
|
params.require(:loan_application).permit(
|
|
328
328
|
:bank_id,
|
|
329
|
-
:
|
|
329
|
+
:credit_product_id,
|
|
330
330
|
:backer_type,
|
|
331
331
|
:backer_id,
|
|
332
332
|
:review_branch_id,
|
|
@@ -337,7 +337,7 @@ module Dscf::Credit
|
|
|
337
337
|
|
|
338
338
|
def eager_loaded_associations
|
|
339
339
|
[
|
|
340
|
-
:bank, :user, :backer, :review_branch, :loan_profile, :
|
|
340
|
+
:bank, :user, :backer, :review_branch, :loan_profile, :credit_product,
|
|
341
341
|
loan_application_data: [ :information_source ],
|
|
342
342
|
reviews: { reviewed_by: :user_profile },
|
|
343
343
|
audit_logs: :actor
|
|
@@ -351,22 +351,22 @@ module Dscf::Credit
|
|
|
351
351
|
def default_serializer_includes
|
|
352
352
|
{
|
|
353
353
|
index: [
|
|
354
|
-
:bank, :user, :backer, :review_branch, :loan_profile, :
|
|
354
|
+
:bank, :user, :backer, :review_branch, :loan_profile, :credit_product,
|
|
355
355
|
loan_application_data: [ :information_source ],
|
|
356
356
|
reviews: { reviewed_by: :user_profile }
|
|
357
357
|
],
|
|
358
358
|
show: [
|
|
359
|
-
:bank, :user, :backer, :review_branch, :loan_profile, :
|
|
359
|
+
:bank, :user, :backer, :review_branch, :loan_profile, :credit_product,
|
|
360
360
|
loan_application_data: [ :information_source ],
|
|
361
361
|
reviews: { reviewed_by: :user_profile },
|
|
362
362
|
audit_logs: :actor
|
|
363
363
|
],
|
|
364
364
|
create: [
|
|
365
|
-
:bank, :user, :backer, :review_branch, :loan_profile, :
|
|
365
|
+
:bank, :user, :backer, :review_branch, :loan_profile, :credit_product, :reviews,
|
|
366
366
|
{ loan_application_data: [ :information_source ] }
|
|
367
367
|
],
|
|
368
368
|
update: [
|
|
369
|
-
:bank, :user, :backer, :review_branch, :loan_profile, :
|
|
369
|
+
:bank, :user, :backer, :review_branch, :loan_profile, :credit_product,
|
|
370
370
|
loan_application_data: [ :information_source ],
|
|
371
371
|
reviews: { reviewed_by: :user_profile }
|
|
372
372
|
]
|
|
@@ -27,15 +27,15 @@ module Dscf::Credit
|
|
|
27
27
|
|
|
28
28
|
def calculate_facility_limits
|
|
29
29
|
loan_profile = @clazz.find(params[:id])
|
|
30
|
-
|
|
30
|
+
credit_product_id = facility_params[:credit_product_id]
|
|
31
31
|
|
|
32
32
|
return render_error(
|
|
33
33
|
"loan_profile.errors.calculate_facility_limits",
|
|
34
|
-
errors: [ "
|
|
34
|
+
errors: [ "Credit Product ID is required" ],
|
|
35
35
|
status: :unprocessable_entity
|
|
36
|
-
) unless
|
|
36
|
+
) unless credit_product_id
|
|
37
37
|
|
|
38
|
-
facility_engine = FacilityLimitCalculationEngine.new(loan_profile.id,
|
|
38
|
+
facility_engine = FacilityLimitCalculationEngine.new(loan_profile.id, credit_product_id)
|
|
39
39
|
result = facility_engine.calculate_facility_limits
|
|
40
40
|
|
|
41
41
|
if result[:success]
|
|
@@ -110,7 +110,7 @@ module Dscf::Credit
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
def facility_params
|
|
113
|
-
params.permit(:
|
|
113
|
+
params.permit(:credit_product_id)
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
def eager_loaded_associations
|
|
@@ -69,7 +69,7 @@ module Dscf::Credit
|
|
|
69
69
|
|
|
70
70
|
def eager_loaded_associations
|
|
71
71
|
[
|
|
72
|
-
:bank, :created_by, :parent_template, :scoring_table_parameters, :
|
|
72
|
+
:bank, :created_by, :parent_template, :scoring_table_parameters, :credit_products,
|
|
73
73
|
reviews: { reviewed_by: :user_profile },
|
|
74
74
|
audit_logs: :actor
|
|
75
75
|
]
|
|
@@ -81,15 +81,15 @@ module Dscf::Credit
|
|
|
81
81
|
|
|
82
82
|
def default_serializer_includes
|
|
83
83
|
{
|
|
84
|
-
index: [ :bank, :
|
|
84
|
+
index: [ :bank, :credit_products, reviews: { reviewed_by: :user_profile } ],
|
|
85
85
|
show: [
|
|
86
|
-
:bank, :created_by, :parent_template, :scoring_table_parameters, :
|
|
86
|
+
:bank, :created_by, :parent_template, :scoring_table_parameters, :credit_products,
|
|
87
87
|
reviews: { reviewed_by: :user_profile },
|
|
88
88
|
audit_logs: :actor
|
|
89
89
|
],
|
|
90
90
|
create: [ :bank, :created_by, :reviews ],
|
|
91
91
|
update: [
|
|
92
|
-
:bank, :created_by, :
|
|
92
|
+
:bank, :created_by, :credit_products,
|
|
93
93
|
reviews: { reviewed_by: :user_profile }
|
|
94
94
|
]
|
|
95
95
|
}
|
|
@@ -4,10 +4,6 @@ module Dscf
|
|
|
4
4
|
self.table_name = "dscf_credit_categories"
|
|
5
5
|
|
|
6
6
|
belongs_to :bank, class_name: "Dscf::Credit::Bank", optional: true
|
|
7
|
-
belongs_to :scoring_table, class_name: "Dscf::Credit::ScoringTable",
|
|
8
|
-
foreign_key: "scoring_table_id", optional: true
|
|
9
|
-
has_many :credit_lines, class_name: "Dscf::Credit::CreditLine",
|
|
10
|
-
foreign_key: "category_id", dependent: :nullify
|
|
11
7
|
has_many :scoring_parameters, class_name: "Dscf::Credit::ScoringParameter",
|
|
12
8
|
foreign_key: "category_id", dependent: :nullify
|
|
13
9
|
|
|
@@ -18,11 +14,11 @@ module Dscf
|
|
|
18
14
|
scope :by_bank, ->(bank_id) { where(bank_id: bank_id) }
|
|
19
15
|
|
|
20
16
|
def self.ransackable_attributes(auth_object = nil)
|
|
21
|
-
%w[id category_type name description
|
|
17
|
+
%w[id category_type name description bank_id created_at updated_at]
|
|
22
18
|
end
|
|
23
19
|
|
|
24
20
|
def self.ransackable_associations(auth_object = nil)
|
|
25
|
-
%w[bank
|
|
21
|
+
%w[bank scoring_parameters]
|
|
26
22
|
end
|
|
27
23
|
end
|
|
28
24
|
end
|
|
@@ -6,23 +6,33 @@ module Dscf::Credit
|
|
|
6
6
|
include Dscf::Core::AuditableModel
|
|
7
7
|
|
|
8
8
|
belongs_to :bank, class_name: "Dscf::Credit::Bank", foreign_key: "bank_id"
|
|
9
|
-
belongs_to :
|
|
9
|
+
belongs_to :credit_product, class_name: "Dscf::Credit::CreditProduct", foreign_key: "credit_product_id"
|
|
10
10
|
belongs_to :created_by, polymorphic: true
|
|
11
11
|
|
|
12
12
|
has_many :credit_line_specs, class_name: "Dscf::Credit::CreditLineSpec", foreign_key: "credit_line_id", dependent: :destroy
|
|
13
13
|
has_many :loans, class_name: "Dscf::Credit::Loan", foreign_key: "credit_line_id", dependent: :destroy
|
|
14
14
|
has_many :eligible_credit_lines, class_name: "Dscf::Credit::EligibleCreditLine", foreign_key: "credit_line_id", dependent: :destroy
|
|
15
|
-
has_many :scoring_parameters, through: :category, source: :scoring_parameters
|
|
16
15
|
|
|
17
16
|
validates :name, presence: true
|
|
18
17
|
validates :code, uniqueness: { scope: :bank_id }, allow_blank: true
|
|
18
|
+
validate :credit_product_must_be_approved, if: -> { credit_product_id_changed? || new_record? }
|
|
19
19
|
|
|
20
20
|
def self.ransackable_attributes(auth_object = nil)
|
|
21
21
|
%w[id name code description document_reference created_at updated_at]
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def self.ransackable_associations(auth_object = nil)
|
|
25
|
-
%w[bank
|
|
25
|
+
%w[bank credit_product created_by credit_line_specs loans eligible_credit_lines reviews]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def credit_product_must_be_approved
|
|
31
|
+
return unless credit_product
|
|
32
|
+
|
|
33
|
+
unless credit_product.approved?
|
|
34
|
+
errors.add(:credit_product, "must be approved before creating a credit line")
|
|
35
|
+
end
|
|
26
36
|
end
|
|
27
37
|
end
|
|
28
38
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Credit
|
|
3
|
+
class CreditProduct < ApplicationRecord
|
|
4
|
+
self.table_name = "dscf_credit_credit_products"
|
|
5
|
+
|
|
6
|
+
include Dscf::Core::ReviewableModel
|
|
7
|
+
include Dscf::Core::AuditableModel
|
|
8
|
+
|
|
9
|
+
belongs_to :bank, class_name: "Dscf::Credit::Bank"
|
|
10
|
+
belongs_to :scoring_table, class_name: "Dscf::Credit::ScoringTable", optional: true
|
|
11
|
+
has_many :credit_lines, class_name: "Dscf::Credit::CreditLine",
|
|
12
|
+
foreign_key: :credit_product_id, dependent: :nullify
|
|
13
|
+
|
|
14
|
+
validates :name, presence: true, uniqueness: { scope: :bank_id }
|
|
15
|
+
validates :bank, presence: true
|
|
16
|
+
|
|
17
|
+
def self.ransackable_attributes(auth_object = nil)
|
|
18
|
+
%w[id name description document_reference bank_id scoring_table_id created_at updated_at]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.ransackable_associations(auth_object = nil)
|
|
22
|
+
%w[bank scoring_table credit_lines reviews audit_logs]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -11,7 +11,7 @@ module Dscf::Credit
|
|
|
11
11
|
end
|
|
12
12
|
belongs_to :backer, polymorphic: true
|
|
13
13
|
belongs_to :review_branch, class_name: "Dscf::Credit::BankBranch", foreign_key: "review_branch_id"
|
|
14
|
-
belongs_to :
|
|
14
|
+
belongs_to :credit_product, class_name: "Dscf::Credit::CreditProduct", foreign_key: "credit_product_id", optional: true
|
|
15
15
|
|
|
16
16
|
has_one :loan_profile, class_name: "Dscf::Credit::LoanProfile", foreign_key: "loan_application_id", dependent: :destroy
|
|
17
17
|
has_many :loan_application_data, class_name: "Dscf::Credit::LoanApplicationDatum", foreign_key: "loan_application_id", dependent: :destroy
|
|
@@ -26,7 +26,7 @@ module Dscf::Credit
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def self.ransackable_associations(auth_object = nil)
|
|
29
|
-
%w[bank user backer review_branch
|
|
29
|
+
%w[bank user backer review_branch credit_product loan_profile loan_application_data reviews audit_logs]
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -11,7 +11,7 @@ module Dscf::Credit
|
|
|
11
11
|
has_many :scoring_table_parameters, class_name: "Dscf::Credit::ScoringTableParameter", foreign_key: "scoring_table_id", dependent: :destroy
|
|
12
12
|
has_many :scoring_parameters, through: :scoring_table_parameters
|
|
13
13
|
has_many :scoring_results, class_name: "Dscf::Credit::ScoringResult", foreign_key: "scoring_table_id"
|
|
14
|
-
has_many :
|
|
14
|
+
has_many :credit_products, class_name: "Dscf::Credit::CreditProduct", foreign_key: "scoring_table_id"
|
|
15
15
|
|
|
16
16
|
validates :code, presence: true, uniqueness: true
|
|
17
17
|
validates :name, presence: true, uniqueness: { scope: :bank_id }
|
|
@@ -28,7 +28,7 @@ module Dscf::Credit
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def self.ransackable_associations(auth_object = nil)
|
|
31
|
-
%w[bank created_by parent_template scoring_table_parameters scoring_parameters scoring_results
|
|
31
|
+
%w[bank created_by parent_template scoring_table_parameters scoring_parameters scoring_results credit_products reviews audit_logs]
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
private
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
module Dscf
|
|
2
2
|
module Credit
|
|
3
3
|
class CategorySerializer < ActiveModel::Serializer
|
|
4
|
-
attributes :id, :category_type, :name, :description, :
|
|
4
|
+
attributes :id, :category_type, :name, :description, :created_at, :updated_at
|
|
5
5
|
|
|
6
6
|
belongs_to :bank, serializer: Dscf::Credit::BankSerializer
|
|
7
|
-
belongs_to :scoring_table, serializer: Dscf::Credit::ScoringTableSerializer
|
|
8
|
-
has_many :credit_lines, serializer: Dscf::Credit::CreditLineSerializer
|
|
9
7
|
has_many :scoring_parameters, serializer: Dscf::Credit::ScoringParameterSerializer
|
|
10
8
|
end
|
|
11
9
|
end
|
|
@@ -4,7 +4,7 @@ module Dscf::Credit
|
|
|
4
4
|
:created_at, :updated_at
|
|
5
5
|
|
|
6
6
|
belongs_to :bank, serializer: Dscf::Credit::BankSerializer
|
|
7
|
-
belongs_to :
|
|
7
|
+
belongs_to :credit_product, serializer: Dscf::Credit::CreditProductSerializer
|
|
8
8
|
belongs_to :created_by, serializer: Dscf::Core::UserSerializer
|
|
9
9
|
has_many :credit_line_specs, serializer: Dscf::Credit::CreditLineSpecSerializer
|
|
10
10
|
has_many :loans, serializer: Dscf::Credit::LoanSerializer
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Dscf
|
|
2
|
+
module Credit
|
|
3
|
+
class CreditProductSerializer < ActiveModel::Serializer
|
|
4
|
+
attributes :id, :name, :description, :document_reference, :created_at, :updated_at
|
|
5
|
+
|
|
6
|
+
belongs_to :bank, serializer: Dscf::Credit::BankSerializer
|
|
7
|
+
belongs_to :scoring_table, serializer: Dscf::Credit::ScoringTableSerializer
|
|
8
|
+
has_many :credit_lines, serializer: Dscf::Credit::CreditLineSerializer
|
|
9
|
+
has_many :reviews, serializer: Dscf::Core::ReviewSerializer
|
|
10
|
+
has_many :audit_logs, serializer: Dscf::Core::AuditLogSerializer
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -6,7 +6,7 @@ module Dscf::Credit
|
|
|
6
6
|
belongs_to :user, serializer: Dscf::Core::UserSerializer
|
|
7
7
|
belongs_to :backer, polymorphic: true
|
|
8
8
|
belongs_to :review_branch, serializer: Dscf::Credit::BankBranchSerializer
|
|
9
|
-
belongs_to :
|
|
9
|
+
belongs_to :credit_product, serializer: Dscf::Credit::CreditProductSerializer
|
|
10
10
|
has_many :reviews, serializer: Dscf::Core::ReviewSerializer
|
|
11
11
|
has_many :audit_logs, serializer: Dscf::Core::AuditLogSerializer
|
|
12
12
|
has_many :loan_application_data, serializer: Dscf::Credit::LoanApplicationDatumSerializer
|
|
@@ -7,7 +7,7 @@ module Dscf::Credit
|
|
|
7
7
|
belongs_to :bank, serializer: Dscf::Credit::BankSerializer
|
|
8
8
|
belongs_to :created_by, polymorphic: true
|
|
9
9
|
belongs_to :parent_template, serializer: Dscf::Credit::ScoringTableSerializer
|
|
10
|
-
has_many :
|
|
10
|
+
has_many :credit_products, serializer: Dscf::Credit::CreditProductSerializer
|
|
11
11
|
has_many :scoring_table_parameters
|
|
12
12
|
has_many :reviews, serializer: Dscf::Core::ReviewSerializer
|
|
13
13
|
has_many :audit_logs, serializer: Dscf::Core::AuditLogSerializer
|
|
@@ -2,14 +2,14 @@ module Dscf::Credit
|
|
|
2
2
|
class CreditScoringEngine
|
|
3
3
|
def initialize(loan_application)
|
|
4
4
|
@loan_application = loan_application
|
|
5
|
-
@
|
|
6
|
-
@scoring_table = @
|
|
5
|
+
@credit_product = loan_application.credit_product
|
|
6
|
+
@scoring_table = @credit_product&.scoring_table
|
|
7
7
|
@data_by_source_id = load_data_by_source
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def calculate_score
|
|
11
|
-
return failure("No
|
|
12
|
-
return failure("No scoring table configured for
|
|
11
|
+
return failure("No credit product assigned to loan application") unless @credit_product
|
|
12
|
+
return failure("No scoring table configured for credit product '#{@credit_product.name}'") unless @scoring_table
|
|
13
13
|
|
|
14
14
|
parameters = @scoring_table.scoring_table_parameters
|
|
15
15
|
.includes(:scoring_parameter, :scoring_table_normalizers, :information_source)
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
module Dscf::Credit
|
|
2
2
|
class FacilityLimitCalculationEngine
|
|
3
|
-
attr_reader :loan_profile, :
|
|
3
|
+
attr_reader :loan_profile, :credit_product_id, :errors
|
|
4
4
|
|
|
5
|
-
def initialize(loan_profile_id,
|
|
5
|
+
def initialize(loan_profile_id, credit_product_id)
|
|
6
6
|
@errors = []
|
|
7
7
|
@loan_profile = LoanProfile.find(loan_profile_id)
|
|
8
|
-
@
|
|
8
|
+
@credit_product_id = credit_product_id
|
|
9
9
|
rescue ActiveRecord::RecordNotFound => e
|
|
10
10
|
@errors << "Loan profile not found: \#{e.message}"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def calculate_facility_limits
|
|
14
14
|
return error_result("Loan profile is required") unless loan_profile
|
|
15
|
-
return error_result("
|
|
15
|
+
return error_result("Credit Product ID is required") unless credit_product_id
|
|
16
16
|
|
|
17
17
|
begin
|
|
18
18
|
ActiveRecord::Base.transaction do
|
|
@@ -22,7 +22,7 @@ module Dscf::Credit
|
|
|
22
22
|
|
|
23
23
|
credit_lines = get_credit_lines_for_calculation
|
|
24
24
|
if credit_lines.empty?
|
|
25
|
-
return error_result("No credit lines found for
|
|
25
|
+
return error_result("No credit lines found for credit product #{credit_product_id} and bank #{loan_profile.loan_application.bank_id}")
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
eligible_credit_lines = []
|
|
@@ -67,9 +67,9 @@ module Dscf::Credit
|
|
|
67
67
|
private
|
|
68
68
|
|
|
69
69
|
def get_credit_lines_for_calculation
|
|
70
|
-
CreditLine.joins(:
|
|
70
|
+
CreditLine.joins(:credit_product, :credit_line_specs)
|
|
71
71
|
.where(
|
|
72
|
-
|
|
72
|
+
credit_product_id: credit_product_id,
|
|
73
73
|
bank_id: loan_profile.loan_application.bank_id,
|
|
74
74
|
dscf_credit_credit_line_specs: { active: true }
|
|
75
75
|
)
|
|
@@ -161,9 +161,9 @@ module Dscf::Credit
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def get_scoring_table
|
|
164
|
-
|
|
165
|
-
return nil unless
|
|
166
|
-
ScoringTable.find_by(id:
|
|
164
|
+
credit_product = CreditProduct.find_by(id: credit_product_id)
|
|
165
|
+
return nil unless credit_product&.scoring_table_id
|
|
166
|
+
ScoringTable.find_by(id: credit_product.scoring_table_id)
|
|
167
167
|
end
|
|
168
168
|
|
|
169
169
|
def update_loan_profile_total_limit
|
|
@@ -82,10 +82,10 @@ module Dscf::Credit
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def calculate_facility_limits(loan_profile)
|
|
85
|
-
|
|
86
|
-
return unless
|
|
85
|
+
credit_product = @loan_application.credit_product
|
|
86
|
+
return unless credit_product
|
|
87
87
|
|
|
88
|
-
engine = FacilityLimitCalculationEngine.new(loan_profile.id,
|
|
88
|
+
engine = FacilityLimitCalculationEngine.new(loan_profile.id, credit_product.id)
|
|
89
89
|
result = engine.calculate_facility_limits
|
|
90
90
|
|
|
91
91
|
unless result[:success]
|
data/config/locales/en.yml
CHANGED
|
@@ -179,6 +179,30 @@ en:
|
|
|
179
179
|
update: "Failed to update credit line specification"
|
|
180
180
|
destroy: "Failed to delete credit line specification"
|
|
181
181
|
|
|
182
|
+
credit_product:
|
|
183
|
+
success:
|
|
184
|
+
index: "Credit products retrieved successfully"
|
|
185
|
+
show: "Credit product details retrieved successfully"
|
|
186
|
+
create: "Credit product created successfully"
|
|
187
|
+
update: "Credit product updated successfully"
|
|
188
|
+
submit: "Credit product submitted for review successfully"
|
|
189
|
+
approve: "Credit product approved successfully"
|
|
190
|
+
reject: "Credit product rejected successfully"
|
|
191
|
+
destroy: "Credit product deleted successfully"
|
|
192
|
+
request_modification: "Modification requested for credit product successfully"
|
|
193
|
+
resubmit: "Credit product resubmitted successfully"
|
|
194
|
+
errors:
|
|
195
|
+
index: "Failed to retrieve credit products"
|
|
196
|
+
show: "Failed to retrieve credit product details"
|
|
197
|
+
create: "Failed to create credit product"
|
|
198
|
+
update: "Failed to update credit product"
|
|
199
|
+
submit: "Failed to submit credit product for review"
|
|
200
|
+
approve: "Failed to approve credit product"
|
|
201
|
+
reject: "Failed to reject credit product"
|
|
202
|
+
destroy: "Failed to delete credit product"
|
|
203
|
+
request_modification: "Failed to request modification for credit product"
|
|
204
|
+
resubmit: "Failed to resubmit credit product"
|
|
205
|
+
|
|
182
206
|
credit_line:
|
|
183
207
|
success:
|
|
184
208
|
index: "Credit lines retrieved successfully"
|