dscf-credit 0.3.7 → 0.3.8

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: 1443779ba67dff25e894c91b282acabdd8e6872728ced4a0dd9066a935da2c12
4
- data.tar.gz: 141228623b227b54ac146125203dde6bb4adcb40a1c3e39e81062b5e64f50aa9
3
+ metadata.gz: 04cc64832d4b85ab0ca609c056fb8b92282b6231cd996144e85721b1ecfd05dd
4
+ data.tar.gz: 6f90fadd4bf75cfdb003b2eca35d17bd95916c75c2be77105a2296e4720b7645
5
5
  SHA512:
6
- metadata.gz: 5991cb4fb11b1adbd0ca101d7ed8a27cf6f3f91f634f56aeb800477d1f275c586916d47bf5c5a0a70f657f331d68fdd1c5a77564aa6047103d71d5468eb31ce8
7
- data.tar.gz: 60d7fec2c04ceb1f5485f4b8cbcf39375219be4ae6e5c79a21ea204203eb6ade319a1709dd90eacc62ec362baf8ed25bb376341aae929c2cadab8de04a4e217b
6
+ metadata.gz: f2ca07ab61fb05247a399992d06b0692b6e0ac020b28b3cee9fd39ea4eea9a52dad7b8ade4303344616649e24c9d51dab515cd0b5ee93ec4d1f6d8abb5c55349
7
+ data.tar.gz: ff113b79a241223bf3834715c0f8abd8bd4f7267a0fabebc8e46438852d0a56724fe6a3f8ae74012139e1590561fceb5fe1e247fa5544769832559e71ce8d464
@@ -0,0 +1,34 @@
1
+ module Dscf::Credit
2
+ class LoanTransactionsController < ApplicationController
3
+ include Dscf::Core::Common
4
+
5
+ private
6
+
7
+ def model_params
8
+ params.require(:loan_transaction).permit(
9
+ :loan_id,
10
+ :transaction_type,
11
+ :amount,
12
+ :transaction_reference,
13
+ :status
14
+ )
15
+ end
16
+
17
+ def eager_loaded_associations
18
+ [ :loan ]
19
+ end
20
+
21
+ def allowed_order_columns
22
+ %w[id transaction_type amount transaction_reference status created_at updated_at]
23
+ end
24
+
25
+ def default_serializer_includes
26
+ {
27
+ index: [ :loan ],
28
+ show: [ :loan ],
29
+ create: [ :loan ],
30
+ update: [ :loan ]
31
+ }
32
+ end
33
+ end
34
+ end
@@ -28,7 +28,7 @@ module Dscf::Credit
28
28
  def default_serializer_includes
29
29
  {
30
30
  index: [ :loan_profile, :credit_line ],
31
- show: [ :loan_profile, :credit_line, :loan_accruals ],
31
+ show: [ :loan_profile, :credit_line, :loan_accruals, :loan_transactions ],
32
32
  create: [ :loan_profile, :credit_line ],
33
33
  update: [ :loan_profile, :credit_line ]
34
34
  }
@@ -6,12 +6,22 @@ module Dscf::Credit
6
6
 
7
7
  validates :transaction_type, :amount, :transaction_reference, :status, presence: true
8
8
  validates :amount, numericality: { greater_than: 0 }
9
- validates :transaction_type, inclusion: { in: %w[disbursement repayment interest_accrual penalty fee_charge] }
9
+ validates :transaction_type, inclusion: { in: %w[disbursement repayment interest_accrual penalty fee_charge reversal adjustment] }
10
10
  validates :status, inclusion: { in: %w[pending processing completed failed reversed] }
11
11
  validates :transaction_reference, uniqueness: true
12
12
 
13
13
  scope :by_status, ->(status) { where(status: status) }
14
+ scope :completed, -> { where(status: "completed") }
15
+ scope :pending, -> { where(status: "pending") }
14
16
  scope :disbursements, -> { where(transaction_type: "disbursement") }
15
17
  scope :repayments, -> { where(transaction_type: "repayment") }
18
+
19
+ def self.ransackable_attributes(auth_object = nil)
20
+ %w[id transaction_type amount transaction_reference status created_at updated_at]
21
+ end
22
+
23
+ def self.ransackable_associations(auth_object = nil)
24
+ %w[loan]
25
+ end
16
26
  end
17
27
  end
@@ -31,8 +31,9 @@ module Dscf::Credit
31
31
  loan = create_loan_record(credit_line)
32
32
  update_credit_line_limits(loan)
33
33
  lock_other_credit_lines(loan_profile, credit_line)
34
+ loan_transaction = create_disbursement_transaction(loan)
34
35
 
35
- success_result(loan)
36
+ success_result(loan, loan_transaction)
36
37
  end
37
38
  rescue StandardError => e
38
39
  error_result("Disbursement processing failed: #{e.message}")
@@ -132,7 +133,16 @@ module Dscf::Credit
132
133
  eligible_credit_line.update!(available_limit: [ new_available_limit, 0 ].max)
133
134
  end
134
135
 
135
- def success_result(loan)
136
+ def create_disbursement_transaction(loan)
137
+ transaction_service = LoanTransactionCreatorService.new(loan)
138
+ transaction_service.create_transaction(
139
+ transaction_type: "disbursement",
140
+ amount: loan.principal_amount,
141
+ status: "completed"
142
+ )
143
+ end
144
+
145
+ def success_result(loan, loan_transaction)
136
146
  # Reload to get associated accruals
137
147
  loan.reload
138
148
 
@@ -144,12 +154,14 @@ module Dscf::Credit
144
154
  {
145
155
  success: true,
146
156
  loan: loan,
157
+ loan_transaction: loan_transaction,
147
158
  disbursement_details: {
148
159
  principal_amount: loan.principal_amount.to_f,
149
160
  facilitation_fee: facilitation_fee,
150
161
  total_loan_amount: total_amount,
151
162
  due_date: loan.due_date,
152
- disbursed_at: loan.disbursed_at
163
+ disbursed_at: loan.disbursed_at,
164
+ transaction_reference: loan_transaction.transaction_reference
153
165
  },
154
166
  message: "Disbursement processed successfully"
155
167
  }
@@ -0,0 +1,71 @@
1
+ module Dscf::Credit
2
+ # Service for creating loan transaction records
3
+ # Handles transaction creation with automatic reference generation
4
+ #
5
+ # @example Disbursement transaction
6
+ # service = LoanTransactionCreatorService.new(loan)
7
+ # transaction = service.create_transaction(
8
+ # transaction_type: "disbursement",
9
+ # amount: 50000.00,
10
+ # status: "completed"
11
+ # )
12
+ #
13
+ # @example Repayment transaction
14
+ # service = LoanTransactionCreatorService.new(loan)
15
+ # transaction = service.create_transaction(
16
+ # transaction_type: "repayment",
17
+ # amount: 5000.00,
18
+ # status: "completed"
19
+ # )
20
+ class LoanTransactionCreatorService
21
+ attr_reader :loan
22
+
23
+ # Transaction type prefixes for reference generation
24
+ TRANSACTION_PREFIXES = {
25
+ "disbursement" => "DSB",
26
+ "repayment" => "RPY",
27
+ "interest_accrual" => "INT",
28
+ "penalty" => "PEN",
29
+ "fee_charge" => "FEE",
30
+ "reversal" => "REV",
31
+ "adjustment" => "ADJ"
32
+ }.freeze
33
+
34
+ def initialize(loan)
35
+ @loan = loan
36
+ end
37
+
38
+ # Create a loan transaction record
39
+ #
40
+ # @param transaction_type [String] Type of transaction (disbursement, repayment, etc.)
41
+ # @param amount [Numeric] Transaction amount
42
+ # @param status [String] Transaction status (pending, completed, failed, etc.)
43
+ # @return [Dscf::Credit::LoanTransaction] Created transaction record
44
+ def create_transaction(transaction_type:, amount:, status: "completed")
45
+ transaction_reference = generate_transaction_reference(transaction_type)
46
+
47
+ Dscf::Credit::LoanTransaction.create!(
48
+ loan: loan,
49
+ transaction_type: transaction_type,
50
+ amount: amount,
51
+ transaction_reference: transaction_reference,
52
+ status: status
53
+ )
54
+ end
55
+
56
+ private
57
+
58
+ # Generate unique transaction reference
59
+ # Format: PREFIX-LOAN_ID-TIMESTAMP-RANDOM
60
+ #
61
+ # @param transaction_type [String] Type of transaction
62
+ # @return [String] Generated reference
63
+ def generate_transaction_reference(transaction_type)
64
+ prefix = TRANSACTION_PREFIXES[transaction_type]
65
+ timestamp = Time.current.to_i
66
+ random = SecureRandom.hex(4)
67
+
68
+ "#{prefix}-#{loan.id}-#{timestamp}-#{random}"
69
+ end
70
+ end
71
+ end
@@ -85,7 +85,9 @@ module Dscf::Credit
85
85
 
86
86
  reactivate_facilities_if_paid_off
87
87
 
88
- success_result(payment_allocation)
88
+ loan_transaction = create_repayment_transaction(payment_allocation)
89
+
90
+ success_result(payment_allocation, loan_transaction)
89
91
  end
90
92
  rescue StandardError => e
91
93
  error_result("Repayment processing failed: #{e.message}")
@@ -345,11 +347,25 @@ module Dscf::Credit
345
347
  Rails.logger.info "Updated loan profile #{loan_profile.id} total limit to #{total_available_limit}"
346
348
  end
347
349
 
350
+ # Create a loan transaction record for the repayment
351
+ #
352
+ # @param allocation [Hash] The allocation hash with payment details
353
+ # @return [Dscf::Credit::LoanTransaction] The created transaction record
354
+ def create_repayment_transaction(allocation)
355
+ transaction_service = LoanTransactionCreatorService.new(loan)
356
+ transaction_service.create_transaction(
357
+ transaction_type: "repayment",
358
+ amount: payment_amount,
359
+ status: "completed"
360
+ )
361
+ end
362
+
348
363
  # Build success result hash
349
364
  #
350
365
  # @param allocation [Hash] The allocation hash with payment details
366
+ # @param loan_transaction [Dscf::Credit::LoanTransaction] The created transaction record
351
367
  # @return [Hash] Success response with loan, payment details, and message
352
- def success_result(allocation)
368
+ def success_result(allocation, loan_transaction)
353
369
  loan.reload
354
370
  pending_facilitation_fee = loan.loan_accruals.pending.by_type("facilitation_fee").sum(:amount)
355
371
  pending_penalty = loan.loan_accruals.pending.by_type("penalty").sum(:amount)
@@ -358,6 +374,7 @@ module Dscf::Credit
358
374
  {
359
375
  success: true,
360
376
  loan: loan,
377
+ loan_transaction: loan_transaction,
361
378
  payment_details: {
362
379
  payment_amount: payment_amount,
363
380
  allocation: allocation,
@@ -366,7 +383,8 @@ module Dscf::Credit
366
383
  remaining_balance: pending_facilitation_fee +
367
384
  pending_penalty +
368
385
  pending_interest +
369
- (loan.remaining_amount || 0)
386
+ (loan.remaining_amount || 0),
387
+ transaction_reference: loan_transaction.transaction_reference
370
388
  },
371
389
  message: loan.status == "paid" ? "Loan fully paid off" : "Payment processed successfully"
372
390
  }
@@ -124,6 +124,18 @@ en:
124
124
  generate: "Failed to generate loan accruals"
125
125
  statistics: "Failed to retrieve loan accrual statistics"
126
126
 
127
+ loan_transaction:
128
+ success:
129
+ index: "Loan transactions retrieved successfully"
130
+ show: "Loan transaction details retrieved successfully"
131
+ create: "Loan transaction created successfully"
132
+ update: "Loan transaction updated successfully"
133
+ errors:
134
+ index: "Failed to retrieve loan transactions"
135
+ show: "Failed to retrieve loan transaction details"
136
+ create: "Failed to create loan transaction"
137
+ update: "Failed to update loan transaction"
138
+
127
139
  loan:
128
140
  success:
129
141
  index: "Loans retrieved successfully"
data/config/routes.rb CHANGED
@@ -73,6 +73,7 @@ Dscf::Credit::Engine.routes.draw do
73
73
  resources :credit_limit_calculations, only: [ :create ]
74
74
  resources :disbursements, only: [ :create ]
75
75
  resources :repayments, only: [ :create ]
76
+ resources :loan_transactions
76
77
  resources :loan_applications do
77
78
  member do
78
79
  patch "approve"
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Credit
3
- VERSION = "0.3.7"
3
+ VERSION = "0.3.8"
4
4
  end
5
5
  end
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.3.7
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adoniyas
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-10-16 00:00:00.000000000 Z
10
+ date: 2025-10-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: dscf-core
@@ -328,6 +328,7 @@ files:
328
328
  - app/controllers/dscf/credit/loan_accruals_controller.rb
329
329
  - app/controllers/dscf/credit/loan_applications_controller.rb
330
330
  - app/controllers/dscf/credit/loan_profiles_controller.rb
331
+ - app/controllers/dscf/credit/loan_transactions_controller.rb
331
332
  - app/controllers/dscf/credit/loans_controller.rb
332
333
  - app/controllers/dscf/credit/parameter_normalizers_controller.rb
333
334
  - app/controllers/dscf/credit/repayments_controller.rb
@@ -398,6 +399,7 @@ files:
398
399
  - app/services/dscf/credit/facility_limit_calculation_engine.rb
399
400
  - app/services/dscf/credit/loan_accrual_generator_service.rb
400
401
  - app/services/dscf/credit/loan_profile_creation_service.rb
402
+ - app/services/dscf/credit/loan_transaction_creator_service.rb
401
403
  - app/services/dscf/credit/repayment_service.rb
402
404
  - app/services/dscf/credit/risk_application_service.rb
403
405
  - app/services/dscf/credit/scoring_service.rb