dscf-credit 0.1.4 → 0.1.6
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/concerns/dscf/core/copilot-instructions.md +683 -0
- data/app/controllers/concerns/dscf/core/reviewable_controller.rb +347 -0
- data/app/controllers/dscf/credit/categories_controller.rb +3 -3
- data/app/controllers/dscf/credit/credit_lines_controller.rb +21 -13
- data/app/controllers/dscf/credit/disbursements_controller.rb +15 -16
- data/app/controllers/dscf/credit/eligible_credit_lines_controller.rb +50 -8
- data/app/controllers/dscf/credit/facilitator_applications_controller.rb +35 -0
- data/app/controllers/dscf/credit/facilitators_controller.rb +8 -96
- data/app/controllers/dscf/credit/loan_applications_controller.rb +252 -0
- data/app/controllers/dscf/credit/loan_profiles_controller.rb +61 -68
- data/app/controllers/dscf/credit/loans_controller.rb +7 -7
- data/app/controllers/dscf/credit/scoring_parameters_controller.rb +59 -13
- data/app/controllers/dscf/credit/system_configs_controller.rb +30 -12
- data/app/models/concerns/core/reviewable_model.rb +31 -0
- data/app/models/dscf/credit/bank.rb +3 -3
- data/app/models/dscf/credit/bank_branch.rb +1 -1
- data/app/models/dscf/credit/category.rb +1 -2
- data/app/models/dscf/credit/credit_line.rb +4 -10
- data/app/models/dscf/credit/eligible_credit_line.rb +2 -2
- data/app/models/dscf/credit/facilitator.rb +6 -17
- data/app/models/dscf/credit/facilitator_application.rb +20 -0
- data/app/models/dscf/credit/loan.rb +4 -4
- data/app/models/dscf/credit/loan_application.rb +30 -0
- data/app/models/dscf/credit/loan_profile.rb +10 -30
- data/app/models/dscf/credit/parameter_normalizer.rb +1 -1
- data/app/models/dscf/credit/scoring_parameter.rb +5 -7
- data/app/models/dscf/credit/system_config.rb +4 -9
- data/app/serializers/dscf/credit/category_serializer.rb +0 -1
- data/app/serializers/dscf/credit/credit_line_serializer.rb +2 -2
- data/app/serializers/dscf/credit/facilitator_application_serializer.rb +7 -0
- data/app/serializers/dscf/credit/facilitator_serializer.rb +3 -6
- data/app/serializers/dscf/credit/loan_application_serializer.rb +12 -0
- data/app/serializers/dscf/credit/loan_profile_serializer.rb +3 -6
- data/app/serializers/dscf/credit/loan_serializer.rb +1 -2
- data/app/serializers/dscf/credit/scoring_parameter_serializer.rb +3 -4
- data/app/serializers/dscf/credit/system_config_serializer.rb +2 -2
- data/app/services/dscf/credit/credit_scoring_engine.rb +258 -0
- data/app/services/dscf/credit/disbursement_service.rb +39 -84
- data/app/services/dscf/credit/facility_limit_calculation_engine.rb +159 -0
- data/app/services/dscf/credit/loan_profile_creation_service.rb +91 -0
- data/app/services/dscf/credit/risk_application_service.rb +61 -11
- data/config/locales/en.yml +65 -50
- data/config/routes.rb +30 -18
- data/db/migrate/20250822091131_create_dscf_credit_credit_lines.rb +1 -8
- data/db/migrate/20250822091820_create_dscf_credit_system_configs.rb +0 -7
- data/db/migrate/20250822092050_create_dscf_credit_scoring_parameters.rb +2 -6
- data/db/migrate/20250822092225_create_dscf_credit_parameter_normalizers.rb +1 -1
- data/db/migrate/20250822092236_create_dscf_credit_loan_applications.rb +20 -0
- data/db/migrate/20250822092246_create_dscf_credit_loan_profiles.rb +7 -19
- data/db/migrate/20250822092426_create_dscf_credit_facilitator_applications.rb +10 -0
- data/db/migrate/20250822092436_create_dscf_credit_facilitators.rb +1 -16
- data/db/migrate/20250822092654_create_dscf_credit_loans.rb +3 -1
- data/db/seeds.rb +321 -290
- data/lib/dscf/credit/version.rb +1 -1
- data/spec/factories/dscf/credit/banks.rb +1 -1
- data/spec/factories/dscf/credit/credit_lines.rb +0 -23
- data/spec/factories/dscf/credit/facilitator_applications.rb +37 -0
- data/spec/factories/dscf/credit/facilitators.rb +8 -30
- data/spec/factories/dscf/credit/loan_applications.rb +42 -0
- data/spec/factories/dscf/credit/loan_profiles.rb +20 -34
- data/spec/factories/dscf/credit/loans.rb +5 -1
- data/spec/factories/dscf/credit/parameter_normalizers.rb +4 -4
- data/spec/factories/dscf/credit/scoring_parameters.rb +14 -11
- data/spec/factories/dscf/credit/system_configs.rb +21 -5
- metadata +20 -20
- data/app/controllers/concerns/dscf/credit/reviewable.rb +0 -112
- data/app/controllers/dscf/credit/payment_requests_controller.rb +0 -87
- data/app/controllers/dscf/credit/payments_controller.rb +0 -36
- data/app/controllers/dscf/credit/scoring_tables_controller.rb +0 -63
- data/app/models/dscf/credit/payment.rb +0 -22
- data/app/models/dscf/credit/payment_request.rb +0 -29
- data/app/models/dscf/credit/scoring_table.rb +0 -24
- data/app/serializers/dscf/credit/payment_request_serializer.rb +0 -10
- data/app/serializers/dscf/credit/payment_serializer.rb +0 -8
- data/app/serializers/dscf/credit/scoring_table_serializer.rb +0 -9
- data/db/migrate/20250822092608_create_dscf_credit_payment_requests.rb +0 -26
- data/db/migrate/20250822092843_create_dscf_credit_payments.rb +0 -23
- data/db/migrate/20250901172842_create_dscf_credit_scoring_tables.rb +0 -18
- data/spec/factories/dscf/credit/payment_requests.rb +0 -40
- data/spec/factories/dscf/credit/payments.rb +0 -39
- data/spec/factories/dscf/credit/scoring_tables.rb +0 -25
@@ -1,112 +0,0 @@
|
|
1
|
-
module Dscf
|
2
|
-
module Credit
|
3
|
-
module Reviewable
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
before_action :set_reviewable_resource, only: %i[approve reject request_modification resubmit]
|
8
|
-
end
|
9
|
-
|
10
|
-
# PATCH /resource/:id/approve
|
11
|
-
def approve
|
12
|
-
if reviewable_resource.update(
|
13
|
-
status: :approved,
|
14
|
-
reviewed_by: current_reviewer,
|
15
|
-
review_date: Time.current
|
16
|
-
)
|
17
|
-
render_success(data: reviewable_resource)
|
18
|
-
else
|
19
|
-
render_error(errors: reviewable_resource.errors.full_messages)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# PATCH /resource/:id/request_modification
|
24
|
-
def request_modification
|
25
|
-
feedback = safe_feedback_param! or return
|
26
|
-
|
27
|
-
if reviewable_resource.update(
|
28
|
-
status: :modify,
|
29
|
-
review_feedback: feedback,
|
30
|
-
reviewed_by: current_reviewer,
|
31
|
-
review_date: Time.current
|
32
|
-
)
|
33
|
-
render_success(data: reviewable_resource)
|
34
|
-
else
|
35
|
-
render_error(errors: reviewable_resource.errors.full_messages)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# PATCH /resource/:id/reject
|
40
|
-
def reject
|
41
|
-
feedback = safe_feedback_param! or return
|
42
|
-
|
43
|
-
unless feedback.key?("message")
|
44
|
-
return render_error(errors: "Provide review_feedback with a 'message' key")
|
45
|
-
end
|
46
|
-
|
47
|
-
if reviewable_resource.update(
|
48
|
-
status: :rejected,
|
49
|
-
review_feedback: feedback,
|
50
|
-
reviewed_by: current_reviewer,
|
51
|
-
review_date: Time.current
|
52
|
-
)
|
53
|
-
render_success(data: reviewable_resource)
|
54
|
-
else
|
55
|
-
render_error(errors: reviewable_resource.errors.full_messages)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# PATCH /resource/:id/resubmit
|
60
|
-
def resubmit
|
61
|
-
unless reviewable_resource.status.to_s == "modify"
|
62
|
-
return render_error(errors: "Only items with status 'modify' can be resubmitted", status: :unprocessable_entity)
|
63
|
-
end
|
64
|
-
|
65
|
-
updates = model_params.merge(
|
66
|
-
status: :pending,
|
67
|
-
review_feedback: {},
|
68
|
-
)
|
69
|
-
|
70
|
-
if reviewable_resource.update(updates)
|
71
|
-
render_success(data: reviewable_resource)
|
72
|
-
else
|
73
|
-
render_error(errors: reviewable_resource.errors.full_messages)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def safe_feedback_param!
|
80
|
-
feedback = params[:review_feedback]
|
81
|
-
unless feedback.respond_to?(:to_unsafe_h)
|
82
|
-
render_error(errors: "review_feedback must be a JSON object") and return
|
83
|
-
end
|
84
|
-
feedback.to_unsafe_h
|
85
|
-
end
|
86
|
-
|
87
|
-
def model_class
|
88
|
-
model_name = controller_name.classify
|
89
|
-
|
90
|
-
controller_namespace = self.class.name.deconstantize
|
91
|
-
"#{controller_namespace}::#{model_name}".constantize
|
92
|
-
rescue NameError
|
93
|
-
model_name.constantize
|
94
|
-
end
|
95
|
-
|
96
|
-
def reviewable_resource
|
97
|
-
@reviewable_resource ||= model_class.find(params[:id])
|
98
|
-
end
|
99
|
-
|
100
|
-
# Override if current_user is not the reviewer
|
101
|
-
def current_reviewer
|
102
|
-
current_user
|
103
|
-
end
|
104
|
-
|
105
|
-
def set_reviewable_resource
|
106
|
-
reviewable_resource
|
107
|
-
rescue ActiveRecord::RecordNotFound => e
|
108
|
-
render_error("errors.record_not_found", status: :not_found, errors: [ e.message ])
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class PaymentRequestsController < ApplicationController
|
3
|
-
include Dscf::Core::Common
|
4
|
-
|
5
|
-
def create
|
6
|
-
super do
|
7
|
-
obj = @clazz.new(model_params)
|
8
|
-
obj.request_type = "credit"
|
9
|
-
obj.initiated_at = Time.current
|
10
|
-
obj
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def approve
|
15
|
-
@obj = @clazz.find(params[:id])
|
16
|
-
|
17
|
-
if @obj.update(status: "approved", approved_at: Time.current)
|
18
|
-
@obj = @clazz.includes(eager_loaded_associations).find(@obj.id) if eager_loaded_associations.present?
|
19
|
-
includes = serializer_includes_for_action(:show)
|
20
|
-
options = includes.present? ? { include: includes } : {}
|
21
|
-
render_success(data: @obj, serializer_options: options)
|
22
|
-
else
|
23
|
-
render_error(errors: @obj.errors.full_messages[0], status: :unprocessable_entity)
|
24
|
-
end
|
25
|
-
rescue StandardError => e
|
26
|
-
render_error(error: e.message)
|
27
|
-
end
|
28
|
-
|
29
|
-
def eligible_credit_lines
|
30
|
-
payment_request = @clazz.find(params[:id])
|
31
|
-
|
32
|
-
if payment_request.user.nil?
|
33
|
-
return render_error(error: "Payment request has no associated user", status: :unprocessable_entity)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Find all eligible credit lines for the user through their approved loan profiles
|
37
|
-
# Only include credit lines with available credit
|
38
|
-
eligible_credit_lines = Dscf::Credit::EligibleCreditLine
|
39
|
-
.joins(loan_profile: :user)
|
40
|
-
.where(dscf_credit_loan_profiles: {
|
41
|
-
user_id: payment_request.user_id,
|
42
|
-
status: [ "approved", "kyc_approved" ] # Only approved loan profiles
|
43
|
-
})
|
44
|
-
.where("dscf_credit_eligible_credit_lines.available_limit > 0") # Only with available credit
|
45
|
-
.includes(:loan_profile, :credit_line)
|
46
|
-
.order("dscf_credit_eligible_credit_lines.available_limit DESC") # Order by available limit
|
47
|
-
|
48
|
-
render_success(
|
49
|
-
data: eligible_credit_lines,
|
50
|
-
)
|
51
|
-
rescue ActiveRecord::RecordNotFound
|
52
|
-
render_error(error: "Payment request not found", status: :not_found)
|
53
|
-
rescue StandardError => e
|
54
|
-
render_error(error: e.message)
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
def model_params
|
60
|
-
params.require(:payment_request).permit(
|
61
|
-
:user_id,
|
62
|
-
:order_id,
|
63
|
-
:amount,
|
64
|
-
:receiver_account_reference,
|
65
|
-
:status,
|
66
|
-
:failure_reason
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
def eager_loaded_associations
|
71
|
-
[ :user, :loans, :payments ]
|
72
|
-
end
|
73
|
-
|
74
|
-
def allowed_order_columns
|
75
|
-
%w[id order_id request_type amount status initiated_at approved_at created_at updated_at]
|
76
|
-
end
|
77
|
-
|
78
|
-
def default_serializer_includes
|
79
|
-
{
|
80
|
-
index: [ :user ],
|
81
|
-
show: [ :user, :loans, :payments ],
|
82
|
-
create: [ :user ],
|
83
|
-
update: [ :user, :loans, :payments ]
|
84
|
-
}
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class PaymentsController < ApplicationController
|
3
|
-
include Dscf::Core::Common
|
4
|
-
|
5
|
-
private
|
6
|
-
|
7
|
-
def model_params
|
8
|
-
params.require(:payment).permit(
|
9
|
-
:payment_request_id,
|
10
|
-
:amount,
|
11
|
-
:receiver_account_reference,
|
12
|
-
:transaction_reference,
|
13
|
-
:status,
|
14
|
-
:failure_reason,
|
15
|
-
:processed_at
|
16
|
-
)
|
17
|
-
end
|
18
|
-
|
19
|
-
def eager_loaded_associations
|
20
|
-
[ :payment_request ]
|
21
|
-
end
|
22
|
-
|
23
|
-
def allowed_order_columns
|
24
|
-
%w[id amount status processed_at created_at updated_at]
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_serializer_includes
|
28
|
-
{
|
29
|
-
index: [ :payment_request ],
|
30
|
-
show: [ :payment_request ],
|
31
|
-
create: [ :payment_request ],
|
32
|
-
update: [ :payment_request ]
|
33
|
-
}
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class ScoringTablesController < ApplicationController
|
3
|
-
include Dscf::Core::Common
|
4
|
-
|
5
|
-
def create
|
6
|
-
super do
|
7
|
-
scoring_table = @clazz.new(model_params)
|
8
|
-
scoring_table.created_by = current_user
|
9
|
-
scoring_table
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def activate
|
14
|
-
@obj = @clazz.find(params[:id])
|
15
|
-
if @obj.update(active: true)
|
16
|
-
render_success(data: @obj, serializer_options: { include: [ :category, :scoring_parameter, :created_by ] })
|
17
|
-
else
|
18
|
-
render_error(errors: @obj.errors.full_messages[0], status: :unprocessable_entity)
|
19
|
-
end
|
20
|
-
rescue StandardError => e
|
21
|
-
render_error(error: e.message)
|
22
|
-
end
|
23
|
-
|
24
|
-
def deactivate
|
25
|
-
@obj = @clazz.find(params[:id])
|
26
|
-
if @obj.update(active: false)
|
27
|
-
render_success(data: @obj, serializer_options: { include: [ :category, :scoring_parameter, :created_by ] })
|
28
|
-
else
|
29
|
-
render_error(errors: @obj.errors.full_messages[0], status: :unprocessable_entity)
|
30
|
-
end
|
31
|
-
rescue StandardError => e
|
32
|
-
render_error(error: e.message)
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def model_params
|
38
|
-
params.require(:scoring_table).permit(
|
39
|
-
:category_id,
|
40
|
-
:scoring_parameter_id,
|
41
|
-
:weight,
|
42
|
-
:active
|
43
|
-
)
|
44
|
-
end
|
45
|
-
|
46
|
-
def eager_loaded_associations
|
47
|
-
[ :category, :scoring_parameter, :created_by ]
|
48
|
-
end
|
49
|
-
|
50
|
-
def allowed_order_columns
|
51
|
-
%w[id weight active created_at updated_at]
|
52
|
-
end
|
53
|
-
|
54
|
-
def default_serializer_includes
|
55
|
-
{
|
56
|
-
index: [ :category, :scoring_parameter, :created_by ],
|
57
|
-
show: [ :category, :scoring_parameter, :created_by ],
|
58
|
-
create: [ :category, :scoring_parameter, :created_by ],
|
59
|
-
update: [ :category, :scoring_parameter, :created_by ]
|
60
|
-
}
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class Payment < ApplicationRecord
|
3
|
-
self.table_name = "dscf_credit_payments"
|
4
|
-
|
5
|
-
belongs_to :payment_request, class_name: "Dscf::Credit::PaymentRequest", foreign_key: "payment_request_id"
|
6
|
-
|
7
|
-
validates :amount, :receiver_account_reference, :transaction_reference, :status, presence: true
|
8
|
-
validates :amount, numericality: { greater_than: 0 }
|
9
|
-
validates :status, inclusion: { in: %w[pending processing completed failed cancelled] }
|
10
|
-
validates :transaction_reference, uniqueness: true
|
11
|
-
|
12
|
-
scope :by_status, ->(status) { where(status: status) }
|
13
|
-
|
14
|
-
def self.ransackable_attributes(auth_object = nil)
|
15
|
-
%w[id amount receiver_account_reference transaction_reference status failure_reason processed_at created_at updated_at]
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.ransackable_associations(auth_object = nil)
|
19
|
-
%w[payment_request]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class PaymentRequest < ApplicationRecord
|
3
|
-
self.table_name = "dscf_credit_payment_requests"
|
4
|
-
|
5
|
-
if defined?(Dscf::Core::User)
|
6
|
-
belongs_to :user, class_name: "Dscf::Core::User", foreign_key: "user_id"
|
7
|
-
end
|
8
|
-
has_many :loans, class_name: "Dscf::Credit::Loan", foreign_key: "payment_request_id", dependent: :destroy
|
9
|
-
has_many :payments, class_name: "Dscf::Credit::Payment", foreign_key: "payment_request_id", dependent: :destroy
|
10
|
-
|
11
|
-
validates :order_id, presence: true, uniqueness: true
|
12
|
-
validates :request_type, :amount, :receiver_account_reference, presence: true
|
13
|
-
validates :amount, numericality: { greater_than: 0 }
|
14
|
-
validates :status, inclusion: { in: %w[pending approved rejected processed failed] }
|
15
|
-
|
16
|
-
scope :pending, -> { where(status: "pending") }
|
17
|
-
scope :approved, -> { where(status: "approved") }
|
18
|
-
scope :processed, -> { where(status: "processed") }
|
19
|
-
scope :failed, -> { where(status: "failed") }
|
20
|
-
|
21
|
-
def self.ransackable_attributes(auth_object = nil)
|
22
|
-
%w[id order_id request_type amount receiver_account_reference status failure_reason initiated_at approved_at created_at updated_at]
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.ransackable_associations(auth_object = nil)
|
26
|
-
%w[user loans payments]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class ScoringTable < ApplicationRecord
|
3
|
-
self.table_name = "dscf_credit_scoring_tables"
|
4
|
-
|
5
|
-
belongs_to :category, class_name: "Dscf::Credit::Category", foreign_key: "category_id"
|
6
|
-
belongs_to :scoring_parameter, class_name: "Dscf::Credit::ScoringParameter", foreign_key: "scoring_parameter_id"
|
7
|
-
belongs_to :created_by, polymorphic: true
|
8
|
-
|
9
|
-
validates :weight, presence: true, numericality: { greater_than: 0, less_than_or_equal_to: 1 }
|
10
|
-
validates :category_id, uniqueness: { scope: :scoring_parameter_id }
|
11
|
-
|
12
|
-
scope :active, -> { where(active: true) }
|
13
|
-
scope :by_category, ->(category_id) { where(category_id: category_id) }
|
14
|
-
scope :by_scoring_parameter, ->(scoring_parameter_id) { where(scoring_parameter_id: scoring_parameter_id) }
|
15
|
-
|
16
|
-
def self.ransackable_attributes(auth_object = nil)
|
17
|
-
%w[id weight active created_at updated_at]
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.ransackable_associations(auth_object = nil)
|
21
|
-
%w[category scoring_parameter created_by]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class PaymentRequestSerializer < ActiveModel::Serializer
|
3
|
-
attributes :id, :order_id, :request_type, :amount, :receiver_account_reference,
|
4
|
-
:status, :failure_reason, :initiated_at, :approved_at, :created_at, :updated_at
|
5
|
-
|
6
|
-
belongs_to :user, serializer: Dscf::Core::UserSerializer
|
7
|
-
has_many :loans, serializer: Dscf::Credit::LoanSerializer
|
8
|
-
has_many :payments, serializer: Dscf::Credit::PaymentSerializer
|
9
|
-
end
|
10
|
-
end
|
@@ -1,8 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class PaymentSerializer < ActiveModel::Serializer
|
3
|
-
attributes :id, :amount, :receiver_account_reference, :transaction_reference,
|
4
|
-
:status, :failure_reason, :processed_at, :created_at, :updated_at
|
5
|
-
|
6
|
-
belongs_to :payment_request, serializer: PaymentRequestSerializer
|
7
|
-
end
|
8
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
module Dscf::Credit
|
2
|
-
class ScoringTableSerializer < ActiveModel::Serializer
|
3
|
-
attributes :id, :weight, :active, :created_at, :updated_at
|
4
|
-
|
5
|
-
belongs_to :category, serializer: Dscf::Credit::CategorySerializer
|
6
|
-
belongs_to :scoring_parameter, serializer: Dscf::Credit::ScoringParameterSerializer
|
7
|
-
belongs_to :created_by, serializer: Dscf::Core::UserSerializer
|
8
|
-
end
|
9
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
class CreateDscfCreditPaymentRequests < ActiveRecord::Migration[8.0]
|
2
|
-
def change
|
3
|
-
create_table :dscf_credit_payment_requests do |t|
|
4
|
-
t.references :user, null: false, foreign_key: { to_table: :dscf_core_users }
|
5
|
-
t.string :order_id, null: false
|
6
|
-
t.string :request_type, null: false
|
7
|
-
t.decimal :amount, precision: 15, scale: 2, null: false
|
8
|
-
t.string :receiver_account_reference, null: false
|
9
|
-
t.string :status, default: 'pending'
|
10
|
-
t.text :failure_reason
|
11
|
-
t.datetime :initiated_at
|
12
|
-
t.datetime :approved_at
|
13
|
-
|
14
|
-
t.timestamps
|
15
|
-
end
|
16
|
-
|
17
|
-
add_index :dscf_credit_payment_requests, :order_id, unique: true
|
18
|
-
add_index :dscf_credit_payment_requests, :request_type
|
19
|
-
add_index :dscf_credit_payment_requests, :status
|
20
|
-
add_index :dscf_credit_payment_requests, :receiver_account_reference
|
21
|
-
add_index :dscf_credit_payment_requests, :initiated_at
|
22
|
-
add_index :dscf_credit_payment_requests, :approved_at
|
23
|
-
add_index :dscf_credit_payment_requests, [ :user_id, :status ]
|
24
|
-
add_index :dscf_credit_payment_requests, [ :user_id, :request_type ]
|
25
|
-
end
|
26
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class CreateDscfCreditPayments < ActiveRecord::Migration[8.0]
|
2
|
-
def change
|
3
|
-
create_table :dscf_credit_payments do |t|
|
4
|
-
t.references :payment_request, null: false, foreign_key: { to_table: :dscf_credit_payment_requests }
|
5
|
-
t.decimal :amount, precision: 15, scale: 2, null: false
|
6
|
-
t.string :receiver_account_reference, null: false
|
7
|
-
t.string :transaction_reference, null: false
|
8
|
-
t.string :status, default: 'pending'
|
9
|
-
t.text :failure_reason
|
10
|
-
t.datetime :processed_at
|
11
|
-
|
12
|
-
t.timestamps
|
13
|
-
end
|
14
|
-
|
15
|
-
add_index :dscf_credit_payments, :transaction_reference, unique: true
|
16
|
-
add_index :dscf_credit_payments, :receiver_account_reference
|
17
|
-
add_index :dscf_credit_payments, :status
|
18
|
-
add_index :dscf_credit_payments, :amount
|
19
|
-
add_index :dscf_credit_payments, :processed_at
|
20
|
-
add_index :dscf_credit_payments, [ :payment_request_id, :status ]
|
21
|
-
add_index :dscf_credit_payments, :created_at
|
22
|
-
end
|
23
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class CreateDscfCreditScoringTables < ActiveRecord::Migration[8.0]
|
2
|
-
def change
|
3
|
-
create_table :dscf_credit_scoring_tables do |t|
|
4
|
-
t.references :category, null: false, foreign_key: { to_table: :dscf_credit_categories }
|
5
|
-
t.references :scoring_parameter, null: false, foreign_key: { to_table: :dscf_credit_scoring_parameters }
|
6
|
-
t.decimal :weight, precision: 5, scale: 4, null: false
|
7
|
-
t.boolean :active, default: true
|
8
|
-
t.references :created_by, polymorphic: true, null: false
|
9
|
-
|
10
|
-
t.timestamps
|
11
|
-
end
|
12
|
-
|
13
|
-
add_index :dscf_credit_scoring_tables, :weight
|
14
|
-
add_index :dscf_credit_scoring_tables, :active
|
15
|
-
add_index :dscf_credit_scoring_tables, [ :created_by_type, :created_by_id ]
|
16
|
-
add_index :dscf_credit_scoring_tables, [ :category_id, :scoring_parameter_id ], unique: true, name: 'index_scoring_tables_on_category_and_scoring_parameter'
|
17
|
-
end
|
18
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
FactoryBot.define do
|
2
|
-
factory :payment_request, class: "Dscf::Credit::PaymentRequest" do
|
3
|
-
association :user, factory: :user if defined?(Dscf::Core::User)
|
4
|
-
order_id { Faker::Alphanumeric.alphanumeric(number: 16).upcase }
|
5
|
-
request_type { %w[loan_disbursement loan_repayment interest_payment fee_payment].sample }
|
6
|
-
amount { Faker::Number.decimal(l_digits: 5, r_digits: 2) }
|
7
|
-
receiver_account_reference { Faker::Bank.account_number }
|
8
|
-
status { %w[pending approved rejected processed failed].sample }
|
9
|
-
failure_reason { Faker::Lorem.sentence if status.in?(%w[rejected failed]) }
|
10
|
-
initiated_at { Faker::Time.between(from: 1.month.ago, to: Time.current) }
|
11
|
-
approved_at { initiated_at + rand(1..24).hours if status.in?(%w[approved processed]) }
|
12
|
-
|
13
|
-
trait :pending do
|
14
|
-
status { "pending" }
|
15
|
-
approved_at { nil }
|
16
|
-
failure_reason { nil }
|
17
|
-
end
|
18
|
-
|
19
|
-
trait :approved do
|
20
|
-
status { "approved" }
|
21
|
-
approved_at { initiated_at + rand(1..24).hours }
|
22
|
-
failure_reason { nil }
|
23
|
-
end
|
24
|
-
|
25
|
-
trait :rejected do
|
26
|
-
status { "rejected" }
|
27
|
-
failure_reason { Faker::Lorem.sentence }
|
28
|
-
end
|
29
|
-
|
30
|
-
trait :processed do
|
31
|
-
status { "processed" }
|
32
|
-
approved_at { initiated_at + rand(1..24).hours }
|
33
|
-
end
|
34
|
-
|
35
|
-
trait :failed do
|
36
|
-
status { "failed" }
|
37
|
-
failure_reason { Faker::Lorem.sentence }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
FactoryBot.define do
|
2
|
-
factory :payment, class: "Dscf::Credit::Payment" do
|
3
|
-
association :payment_request, factory: :payment_request
|
4
|
-
amount { Faker::Number.decimal(l_digits: 5, r_digits: 2) }
|
5
|
-
receiver_account_reference { Faker::Alphanumeric.alphanumeric(number: 20) }
|
6
|
-
transaction_reference { Faker::Alphanumeric.alphanumeric(number: 16) }
|
7
|
-
status { %w[pending processing completed failed cancelled].sample }
|
8
|
-
failure_reason { Faker::Lorem.sentence if status.in?(%w[failed cancelled]) }
|
9
|
-
processed_at { Faker::Time.between(from: 1.month.ago, to: Time.current) if status.in?(%w[completed failed]) }
|
10
|
-
|
11
|
-
trait :pending do
|
12
|
-
status { "pending" }
|
13
|
-
processed_at { nil }
|
14
|
-
failure_reason { nil }
|
15
|
-
end
|
16
|
-
|
17
|
-
trait :processing do
|
18
|
-
status { "processing" }
|
19
|
-
processed_at { nil }
|
20
|
-
end
|
21
|
-
|
22
|
-
trait :completed do
|
23
|
-
status { "completed" }
|
24
|
-
processed_at { Faker::Time.between(from: 1.month.ago, to: Time.current) }
|
25
|
-
failure_reason { nil }
|
26
|
-
end
|
27
|
-
|
28
|
-
trait :failed do
|
29
|
-
status { "failed" }
|
30
|
-
processed_at { Faker::Time.between(from: 1.month.ago, to: Time.current) }
|
31
|
-
failure_reason { Faker::Lorem.sentence }
|
32
|
-
end
|
33
|
-
|
34
|
-
trait :cancelled do
|
35
|
-
status { "cancelled" }
|
36
|
-
failure_reason { Faker::Lorem.sentence }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
FactoryBot.define do
|
2
|
-
factory :scoring_table, class: "Dscf::Credit::ScoringTable" do
|
3
|
-
association :category, factory: :category
|
4
|
-
association :scoring_parameter, factory: :scoring_parameter
|
5
|
-
association :created_by, factory: :user if defined?(Dscf::Core::User)
|
6
|
-
weight { Faker::Number.decimal(l_digits: 0, r_digits: 4).clamp(0.0001, 1.0) }
|
7
|
-
active { true }
|
8
|
-
|
9
|
-
trait :inactive do
|
10
|
-
active { false }
|
11
|
-
end
|
12
|
-
|
13
|
-
trait :high_weight do
|
14
|
-
weight { Faker::Number.decimal(l_digits: 0, r_digits: 4).clamp(0.7, 1.0) }
|
15
|
-
end
|
16
|
-
|
17
|
-
trait :medium_weight do
|
18
|
-
weight { Faker::Number.decimal(l_digits: 0, r_digits: 4).clamp(0.3, 0.7) }
|
19
|
-
end
|
20
|
-
|
21
|
-
trait :low_weight do
|
22
|
-
weight { Faker::Number.decimal(l_digits: 0, r_digits: 4).clamp(0.0001, 0.3) }
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|