dscf-credit 0.4.0 → 0.4.1
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/credit_lines_controller.rb +5 -3
- data/app/controllers/dscf/credit/scoring_parameters_controller.rb +2 -1
- data/lib/dscf/credit/version.rb +1 -1
- metadata +2 -5
- data/app/services/dscf/credit/facilitator_additional_info_service.rb +0 -50
- data/app/services/dscf/credit/facilitator_approval_service.rb +0 -88
- data/app/services/dscf/credit/scoring_service.rb +0 -297
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0be229f7298a4e4f905fec15eae5ede2fcd755f6f56510f73f12b32e6d5b3453
|
|
4
|
+
data.tar.gz: 7de36c9ecca064d851e13b7ceb8ed7aea01cc7c6d8794fef6e203d5af63400a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb8742b82a81552545e811623eb176fca2a12f06fbf301aa90d060a64293ef2f77c5ad5f3e7db59a77b08e0659e81f0ee84956e0ba0d7b012cbc1cf1873de5cf
|
|
7
|
+
data.tar.gz: e8350b9ce353bf7c88992e00ca287fe7791be962449b10feefb4afbcc8b4af89157b5677957f2ec2cbccc64398fb4b58d40cf54a0896561ab58a33316ab87d54
|
|
@@ -4,9 +4,11 @@ module Dscf::Credit
|
|
|
4
4
|
include Dscf::Core::ReviewableController
|
|
5
5
|
include Dscf::Core::AuditableController
|
|
6
6
|
|
|
7
|
-
auditable associated: :reviews,
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
auditable associated: [ :reviews ],
|
|
8
|
+
on: %i[approve submit reject request_modification resubmit]
|
|
9
|
+
|
|
10
|
+
auditable on: %i[create],
|
|
11
|
+
associated: { reviews: { only: [ :status ] } }
|
|
10
12
|
|
|
11
13
|
def create
|
|
12
14
|
super do
|
|
@@ -7,13 +7,14 @@ module Dscf::Credit
|
|
|
7
7
|
before_action :set_object, only: %i[ show update activate deactivate]
|
|
8
8
|
|
|
9
9
|
auditable associated: [ :reviews ],
|
|
10
|
-
on: %i[approve reject request_modification resubmit]
|
|
10
|
+
on: %i[approve submit reject request_modification resubmit]
|
|
11
11
|
|
|
12
12
|
auditable only: [ :active ],
|
|
13
13
|
on: %i[activate deactivate]
|
|
14
14
|
|
|
15
15
|
auditable on: %i[create],
|
|
16
16
|
associated: { reviews: { only: [ :status ] } }
|
|
17
|
+
|
|
17
18
|
def create
|
|
18
19
|
super do
|
|
19
20
|
scoring_parameter = @clazz.new(model_params)
|
data/lib/dscf/credit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dscf-credit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adoniyas
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-
|
|
10
|
+
date: 2025-12-24 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: dscf-core
|
|
@@ -393,8 +393,6 @@ files:
|
|
|
393
393
|
- app/services/dscf/credit/credit_limit_calculation_service.rb
|
|
394
394
|
- app/services/dscf/credit/credit_scoring_engine.rb
|
|
395
395
|
- app/services/dscf/credit/disbursement_service.rb
|
|
396
|
-
- app/services/dscf/credit/facilitator_additional_info_service.rb
|
|
397
|
-
- app/services/dscf/credit/facilitator_approval_service.rb
|
|
398
396
|
- app/services/dscf/credit/facilitator_creation_service.rb
|
|
399
397
|
- app/services/dscf/credit/facility_limit_calculation_engine.rb
|
|
400
398
|
- app/services/dscf/credit/loan_accrual_generator_service.rb
|
|
@@ -402,7 +400,6 @@ files:
|
|
|
402
400
|
- app/services/dscf/credit/loan_transaction_creator_service.rb
|
|
403
401
|
- app/services/dscf/credit/repayment_service.rb
|
|
404
402
|
- app/services/dscf/credit/risk_application_service.rb
|
|
405
|
-
- app/services/dscf/credit/scoring_service.rb
|
|
406
403
|
- app/views/dscf/credit/bank_staff_welcome_mailer/welcome_email.html.erb
|
|
407
404
|
- app/views/dscf/credit/bank_staff_welcome_mailer/welcome_email.text.erb
|
|
408
405
|
- app/views/dscf/credit/facilitator_mailer/additional_info_received.html.erb
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
module Dscf::Credit
|
|
2
|
-
class FacilitatorAdditionalInfoService
|
|
3
|
-
def submit_info(facilitator_id, additional_info)
|
|
4
|
-
facilitator = Dscf::Credit::Facilitator.find(facilitator_id)
|
|
5
|
-
|
|
6
|
-
performance = facilitator.facilitator_performances.current.first
|
|
7
|
-
|
|
8
|
-
if performance&.input_data&.present? && performance.input_data["additional_info_submitted"]
|
|
9
|
-
raise StandardError, "Additional information has already been submitted for this facilitator"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
if performance
|
|
13
|
-
updated_data = performance.input_data || {}
|
|
14
|
-
updated_data.merge!(additional_info)
|
|
15
|
-
updated_data["additional_info_submitted"] = true
|
|
16
|
-
updated_data["submission_date"] = Time.current.iso8601
|
|
17
|
-
|
|
18
|
-
performance.update!(
|
|
19
|
-
input_data: updated_data,
|
|
20
|
-
updated_at: Time.current
|
|
21
|
-
)
|
|
22
|
-
else
|
|
23
|
-
input_data = additional_info.dup
|
|
24
|
-
input_data["additional_info_submitted"] = true
|
|
25
|
-
input_data["submission_date"] = Time.current.iso8601
|
|
26
|
-
|
|
27
|
-
performance = facilitator.facilitator_performances.create!(
|
|
28
|
-
total_outstanding_loans: 0,
|
|
29
|
-
total_outstanding_amount: 0.0,
|
|
30
|
-
approval_required: false,
|
|
31
|
-
input_data: input_data,
|
|
32
|
-
created_by_type: "System",
|
|
33
|
-
created_by_id: nil
|
|
34
|
-
)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
begin
|
|
38
|
-
FacilitatorMailer.additional_info_received(facilitator).deliver_now
|
|
39
|
-
rescue => e
|
|
40
|
-
Rails.logger.error "Failed to send additional info confirmation email: #{e.message}"
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
facilitator: facilitator,
|
|
45
|
-
performance: performance,
|
|
46
|
-
message: "Additional information submitted successfully"
|
|
47
|
-
}
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
module Dscf::Credit
|
|
2
|
-
class FacilitatorApprovalService
|
|
3
|
-
attr_reader :facilitator, :approver
|
|
4
|
-
|
|
5
|
-
def initialize(facilitator, approver)
|
|
6
|
-
@facilitator = facilitator
|
|
7
|
-
@approver = approver
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def approve
|
|
11
|
-
ActiveRecord::Base.transaction do
|
|
12
|
-
facilitator.update!(
|
|
13
|
-
kyc_status: "approved",
|
|
14
|
-
kyc_reviewed_by: approver
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
token = generate_additional_info_token
|
|
18
|
-
|
|
19
|
-
begin
|
|
20
|
-
FacilitatorMailer.approval_notification(facilitator, token).deliver_now
|
|
21
|
-
rescue => e
|
|
22
|
-
Rails.logger.error "Failed to send approval email: #{e.message}"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
update_facilitator_performance
|
|
26
|
-
|
|
27
|
-
facilitator
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def reject(review_feedback = nil)
|
|
32
|
-
ActiveRecord::Base.transaction do
|
|
33
|
-
facilitator.update!(
|
|
34
|
-
kyc_status: "rejected",
|
|
35
|
-
kyc_reviewed_by: approver,
|
|
36
|
-
review_feedback: review_feedback
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
begin
|
|
40
|
-
FacilitatorMailer.rejection_notification(facilitator, review_feedback).deliver_now
|
|
41
|
-
rescue => e
|
|
42
|
-
Rails.logger.error "Failed to send rejection email: #{e.message}"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
facilitator
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def set_limit(total_limit)
|
|
50
|
-
facilitator.update!(total_limit: total_limit)
|
|
51
|
-
|
|
52
|
-
begin
|
|
53
|
-
FacilitatorMailer.limit_update_notification(facilitator).deliver_now
|
|
54
|
-
rescue => e
|
|
55
|
-
Rails.logger.error "Failed to send limit update email: #{e.message}"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
facilitator
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
private
|
|
62
|
-
|
|
63
|
-
def generate_additional_info_token
|
|
64
|
-
payload = {
|
|
65
|
-
facilitator_id: facilitator.id,
|
|
66
|
-
purpose: "additional_info",
|
|
67
|
-
exp: 30.days.from_now.to_i
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
Rails.application.message_verifier("additional_info").generate(payload)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def update_facilitator_performance
|
|
74
|
-
performance = facilitator.facilitator_performances.current.first
|
|
75
|
-
|
|
76
|
-
if performance
|
|
77
|
-
performance.update!(approval_required: false)
|
|
78
|
-
else
|
|
79
|
-
facilitator.facilitator_performances.create!(
|
|
80
|
-
total_outstanding_loans: 0,
|
|
81
|
-
total_outstanding_amount: 0.0,
|
|
82
|
-
approval_required: false,
|
|
83
|
-
created_by: approver
|
|
84
|
-
)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
module Dscf::Credit
|
|
2
|
-
class ScoringService
|
|
3
|
-
attr_reader :loan_profile
|
|
4
|
-
|
|
5
|
-
def initialize(loan_profile)
|
|
6
|
-
@loan_profile = loan_profile
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
# Calculate credit score for a loan profile using the eligibility category scoring table
|
|
10
|
-
# @param external_scoring_data [Hash] Optional external scoring input data
|
|
11
|
-
# @return [Hash] Result containing score, total_limit, and success status
|
|
12
|
-
def calculate_credit_score(external_scoring_data = nil)
|
|
13
|
-
eligibility_category = find_eligibility_category
|
|
14
|
-
return error_result("Eligibility category not found") unless eligibility_category
|
|
15
|
-
|
|
16
|
-
scoring_tables = eligibility_category.scoring_tables.active.includes(:scoring_parameter)
|
|
17
|
-
return error_result("No active scoring parameters found for eligibility category") if scoring_tables.empty?
|
|
18
|
-
|
|
19
|
-
scoring_data = get_scoring_data(external_scoring_data)
|
|
20
|
-
score = calculate_weighted_score(scoring_tables, scoring_data)
|
|
21
|
-
facility_limit = calculate_facility_limit(score, scoring_data)
|
|
22
|
-
|
|
23
|
-
success_result(score, facility_limit)
|
|
24
|
-
rescue StandardError => e
|
|
25
|
-
error_result("Score calculation failed: #{e.message}")
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def get_scoring_data(external_scoring_data)
|
|
31
|
-
if external_scoring_data.present?
|
|
32
|
-
external_scoring_data
|
|
33
|
-
else
|
|
34
|
-
extract_scoring_data_from_profile
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def extract_scoring_data_from_profile
|
|
39
|
-
latest_spec = loan_profile.loan_profile_scoring_specs.order(created_at: :desc).first
|
|
40
|
-
|
|
41
|
-
if latest_spec&.scoring_input_data.present? && !latest_spec.scoring_input_data.empty?
|
|
42
|
-
default_data = prepare_scoring_data
|
|
43
|
-
default_data.merge(latest_spec.scoring_input_data.symbolize_keys)
|
|
44
|
-
else
|
|
45
|
-
prepare_scoring_data
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def find_eligibility_category
|
|
50
|
-
Dscf::Credit::Category.find_by(type: "eligibility", name: "default") ||
|
|
51
|
-
Dscf::Credit::Category.find_by(type: "eligibility")
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def prepare_scoring_data
|
|
55
|
-
{
|
|
56
|
-
average_daily_purchase: extract_average_daily_purchase,
|
|
57
|
-
years_at_location: extract_years_at_location,
|
|
58
|
-
marital_status: extract_marital_status,
|
|
59
|
-
dependents_count: extract_dependents_count,
|
|
60
|
-
education_level: extract_education_level,
|
|
61
|
-
bill_payment_timing: extract_bill_payment_timing,
|
|
62
|
-
other_accounts: extract_other_accounts,
|
|
63
|
-
money_preference: extract_money_preference,
|
|
64
|
-
business_license: extract_business_license,
|
|
65
|
-
bank_statements: extract_bank_statements,
|
|
66
|
-
transaction_frequency: extract_transaction_frequency,
|
|
67
|
-
purchase_volume: extract_purchase_volume,
|
|
68
|
-
cancellation_rate: extract_cancellation_rate,
|
|
69
|
-
reliability_score: extract_reliability_score
|
|
70
|
-
}
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Calculate weighted score based on scoring parameters
|
|
74
|
-
def calculate_weighted_score(scoring_tables, scoring_data)
|
|
75
|
-
total_score = 0.0
|
|
76
|
-
total_weight = 0.0
|
|
77
|
-
|
|
78
|
-
scoring_tables.each do |table|
|
|
79
|
-
parameter = table.scoring_parameter
|
|
80
|
-
raw_value = find_parameter_value(parameter, scoring_data)
|
|
81
|
-
|
|
82
|
-
next if raw_value.nil?
|
|
83
|
-
|
|
84
|
-
normalized_score = normalize_parameter_value(parameter, raw_value)
|
|
85
|
-
weighted_score = normalized_score * table.weight
|
|
86
|
-
|
|
87
|
-
total_score += weighted_score
|
|
88
|
-
total_weight += table.weight
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
return 0.0 if total_weight.zero?
|
|
92
|
-
|
|
93
|
-
(total_score / total_weight) * 100
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Find parameter value from scoring data using flexible key matching
|
|
97
|
-
def find_parameter_value(parameter, scoring_data)
|
|
98
|
-
param_name = parameter.name
|
|
99
|
-
|
|
100
|
-
# Try exact match first
|
|
101
|
-
if scoring_data.key?(param_name.to_sym)
|
|
102
|
-
return scoring_data[param_name.to_sym]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
if scoring_data.key?(param_name)
|
|
106
|
-
return scoring_data[param_name]
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Try snake_case version
|
|
110
|
-
snake_case_name = param_name.downcase.gsub(/\s+/, "_")
|
|
111
|
-
if scoring_data.key?(snake_case_name.to_sym)
|
|
112
|
-
return scoring_data[snake_case_name.to_sym]
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
if scoring_data.key?(snake_case_name)
|
|
116
|
-
return scoring_data[snake_case_name]
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Try common mappings
|
|
120
|
-
case param_name.downcase
|
|
121
|
-
when "monthly income"
|
|
122
|
-
scoring_data[:monthly_income] || scoring_data["monthly_income"]
|
|
123
|
-
when "credit history score"
|
|
124
|
-
scoring_data[:credit_history_score] || scoring_data["credit_history_score"]
|
|
125
|
-
when "employment type"
|
|
126
|
-
scoring_data[:employment_type] || scoring_data["employment_type"]
|
|
127
|
-
else
|
|
128
|
-
nil
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Calculate facility limit based on score and business metrics
|
|
133
|
-
def calculate_facility_limit(score, scoring_data)
|
|
134
|
-
return 0 if score < 50 # Below 50% score = no facility
|
|
135
|
-
|
|
136
|
-
average_daily_purchase = scoring_data[:average_daily_purchase] || 0
|
|
137
|
-
|
|
138
|
-
credit_line_multiplier = get_default_credit_line_multiplier
|
|
139
|
-
|
|
140
|
-
base_limit = average_daily_purchase * credit_line_multiplier * (score / 100.0)
|
|
141
|
-
|
|
142
|
-
apply_limit_constraints(base_limit)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Get default credit line multiplier from the bank's approved credit line specs
|
|
146
|
-
def get_default_credit_line_multiplier
|
|
147
|
-
return 30.0 unless loan_profile.bank
|
|
148
|
-
|
|
149
|
-
credit_line_spec = loan_profile.bank.credit_lines.approved
|
|
150
|
-
.joins(:credit_line_specs)
|
|
151
|
-
.merge(Dscf::Credit::CreditLineSpec.active)
|
|
152
|
-
.select("dscf_credit_credit_line_specs.credit_line_multiplier")
|
|
153
|
-
.first&.credit_line_specs&.active&.first
|
|
154
|
-
|
|
155
|
-
credit_line_spec&.credit_line_multiplier || 30.0
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def apply_limit_constraints(base_limit)
|
|
159
|
-
min_limit = get_bank_config("min_credit_limit", 0)
|
|
160
|
-
max_limit = get_bank_config("max_credit_limit", 1000000)
|
|
161
|
-
|
|
162
|
-
return 0 if base_limit < min_limit
|
|
163
|
-
return max_limit if base_limit > max_limit
|
|
164
|
-
|
|
165
|
-
base_limit
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Get bank configuration value from system configs
|
|
169
|
-
def get_bank_config(config_key, default_value)
|
|
170
|
-
return default_value unless loan_profile.bank
|
|
171
|
-
|
|
172
|
-
config_definition = loan_profile.bank.system_config_definitions
|
|
173
|
-
.find_by(config_key: config_key)
|
|
174
|
-
return default_value unless config_definition
|
|
175
|
-
|
|
176
|
-
system_config = Dscf::Credit::SystemConfig.approved
|
|
177
|
-
.find_by(config_definition: config_definition)
|
|
178
|
-
|
|
179
|
-
if system_config&.config_value
|
|
180
|
-
numeric_value = system_config.config_value.to_f
|
|
181
|
-
numeric_value > 0 ? numeric_value : default_value
|
|
182
|
-
else
|
|
183
|
-
default_value
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# Normalize parameter value to 0-1 scale
|
|
188
|
-
def normalize_parameter_value(parameter, raw_value)
|
|
189
|
-
case parameter.data_type
|
|
190
|
-
when "boolean"
|
|
191
|
-
raw_value ? 1.0 : 0.0
|
|
192
|
-
when "integer", "decimal"
|
|
193
|
-
normalize_numeric_value(parameter, raw_value.to_f)
|
|
194
|
-
when "string"
|
|
195
|
-
normalize_string_value(parameter, raw_value)
|
|
196
|
-
else
|
|
197
|
-
0.5 # Default neutral score
|
|
198
|
-
end
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
def normalize_numeric_value(parameter, value)
|
|
202
|
-
min_val = parameter.min_value || 0
|
|
203
|
-
max_val = parameter.max_value || 100
|
|
204
|
-
|
|
205
|
-
return 0.0 if value < min_val
|
|
206
|
-
return 1.0 if value > max_val
|
|
207
|
-
|
|
208
|
-
(value - min_val) / (max_val - min_val)
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def normalize_string_value(parameter, value)
|
|
212
|
-
normalizer = parameter.parameter_normalizers.find { |n| n.raw_value == value }
|
|
213
|
-
return normalizer.normalized_value if normalizer
|
|
214
|
-
|
|
215
|
-
case value.downcase
|
|
216
|
-
when "excellent", "high", "good" then 1.0
|
|
217
|
-
when "fair", "medium", "average" then 0.7
|
|
218
|
-
when "poor", "low", "bad" then 0.3
|
|
219
|
-
else 0.5
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def extract_average_daily_purchase
|
|
224
|
-
5000.0 # Default average daily purchase
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def extract_years_at_location
|
|
228
|
-
2 # Default years at current location
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def extract_marital_status
|
|
232
|
-
"single" # Default marital status
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def extract_dependents_count
|
|
236
|
-
0 # Default number of dependents
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
def extract_education_level
|
|
240
|
-
"bachelor" # Default education level
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def extract_bill_payment_timing
|
|
244
|
-
"on_time" # Default payment timing
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def extract_other_accounts
|
|
248
|
-
false # Default: no other active accounts
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
def extract_money_preference
|
|
252
|
-
"save" # Default money preference
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
def extract_business_license
|
|
256
|
-
false # Default: no business license
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def extract_bank_statements
|
|
260
|
-
true # Default: bank statements available
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def extract_transaction_frequency
|
|
264
|
-
15 # Default monthly transaction frequency
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
def extract_purchase_volume
|
|
268
|
-
50000.0 # Default monthly purchase volume
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def extract_cancellation_rate
|
|
272
|
-
0.05 # Default 5% cancellation rate
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def extract_reliability_score
|
|
276
|
-
75.0 # Default reliability score (0-100)
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
def success_result(score, facility_limit)
|
|
280
|
-
{
|
|
281
|
-
success: true,
|
|
282
|
-
score: score.round(2),
|
|
283
|
-
facility_limit: facility_limit.round(2),
|
|
284
|
-
message: "Credit score calculated successfully"
|
|
285
|
-
}
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
def error_result(message)
|
|
289
|
-
{
|
|
290
|
-
success: false,
|
|
291
|
-
score: 0,
|
|
292
|
-
facility_limit: 0,
|
|
293
|
-
error: message
|
|
294
|
-
}
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
end
|