dscf-payment 0.1.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.
Files changed (31) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/controllers/dscf/payment/application_controller.rb +25 -0
  6. data/app/controllers/dscf/payment/payment_requests_controller.rb +70 -0
  7. data/app/controllers/dscf/payment/payments_controller.rb +32 -0
  8. data/app/jobs/dscf/payment/application_job.rb +6 -0
  9. data/app/mailers/dscf/payment/application_mailer.rb +8 -0
  10. data/app/models/dscf/payment/application_record.rb +7 -0
  11. data/app/models/dscf/payment/payment.rb +39 -0
  12. data/app/models/dscf/payment/payment_request.rb +64 -0
  13. data/app/serializers/dscf/payment/payment_request_serializer.rb +18 -0
  14. data/app/serializers/dscf/payment/payment_serializer.rb +16 -0
  15. data/app/services/dscf/payment/banking_integration_service.rb +37 -0
  16. data/app/services/dscf/payment/credit_integration_service.rb +56 -0
  17. data/app/services/dscf/payment/payment_service.rb +128 -0
  18. data/app/services/dscf/payment/settlement_account_service.rb +37 -0
  19. data/config/locales/en.yml +21 -0
  20. data/config/routes.rb +8 -0
  21. data/db/migrate/20251002191758_create_dscf_payment_payment_requests.rb +32 -0
  22. data/db/migrate/20251002191802_create_dscf_payment_payments.rb +24 -0
  23. data/db/migrate/20251003005136_make_payment_request_accounts_optional.rb +6 -0
  24. data/lib/dscf/payment/engine.rb +31 -0
  25. data/lib/dscf/payment/errors.rb +10 -0
  26. data/lib/dscf/payment/version.rb +5 -0
  27. data/lib/dscf/payment.rb +8 -0
  28. data/lib/tasks/dscf/payment_tasks.rake +4 -0
  29. data/spec/factories/dscf/payment/payment_requests.rb +56 -0
  30. data/spec/factories/dscf/payment/payments.rb +37 -0
  31. metadata +512 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 510fd8007681aac5a20434463cc546f4b9c108a7e5e53b8fa09c81f939267c6c
4
+ data.tar.gz: b0f00ba8049489d151673e54f2c5a73f4d3307750a2e65a84f969d5c537fcb43
5
+ SHA512:
6
+ metadata.gz: d87c868934387b69afceb4ed91f78ce1d5a3a7b808ca0d61fdc1201054f33409bcb50166c551d2b88e3acc946c510a9524bf72206a7a540cb4cd028e68ca7362
7
+ data.tar.gz: fb6b47a296c410f4d8ffdef7d2ed39c189458629f76c8c10010dd3755f2bcc6d489b8891bb2286c3e650705d10b9842ca9ce18a3f0c9f9d71f42ff462a476343
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright Asrat
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Dscf::Payment
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "dscf-payment"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install dscf-payment
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ module Dscf
2
+ module Payment
3
+ class ApplicationController < ActionController::API
4
+ include Dscf::Core::Authenticatable
5
+ include Dscf::Core::TokenAuthenticatable
6
+ include Dscf::Core::JsonResponse
7
+
8
+ # Handle CORS for authentication
9
+ before_action :set_cors_headers
10
+
11
+ private
12
+
13
+ def set_cors_headers
14
+ headers["Access-Control-Allow-Origin"] = request.headers["Origin"] || "*"
15
+ headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS"
16
+ headers["Access-Control-Allow-Headers"] = "Origin, Content-Type, Accept, Authorization, X-Requested-With"
17
+ headers["Access-Control-Allow-Credentials"] = "false"
18
+ end
19
+
20
+ def authentication_required?
21
+ false # Override in specific controllers
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,70 @@
1
+ module Dscf::Payment
2
+ class PaymentRequestsController < ApplicationController
3
+ include Dscf::Core::Common
4
+
5
+ rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
6
+
7
+ def create
8
+ super do
9
+ Dscf::Payment::PaymentRequest.new(model_params)
10
+ end
11
+ end
12
+
13
+ def process_payment
14
+ payment_request = Dscf::Payment::PaymentRequest.find(params[:id])
15
+
16
+ unless payment_request.pending?
17
+ return render_error(
18
+ error: "Payment request cannot be processed",
19
+ errors: [ "Payment request status is #{payment_request.status}" ]
20
+ )
21
+ end
22
+
23
+ service = Dscf::Payment::PaymentService.new(payment_request, current_user)
24
+ payment = service.process
25
+
26
+ render_success(
27
+ data: payment,
28
+ message: "Payment processed successfully"
29
+ )
30
+ rescue ActiveRecord::RecordNotFound
31
+ render_error(error: "Payment request not found", status: :not_found)
32
+ rescue => e
33
+ render_error(error: "Payment processing failed", errors: [ e.message ])
34
+ end
35
+
36
+ private
37
+
38
+ def authentication_required?
39
+ true
40
+ end
41
+
42
+ def model_params
43
+ params.require(:payment_request).permit(
44
+ :payment_type,
45
+ :amount,
46
+ :currency,
47
+ :description,
48
+ :from_account_id,
49
+ :to_account_id,
50
+ :payable_type,
51
+ :payable_id,
52
+ metadata: {}
53
+ )
54
+ end
55
+
56
+ def eager_loaded_associations
57
+ [ :from_account, :to_account, :payable, :payments ]
58
+ end
59
+
60
+ def allowed_order_columns
61
+ %w[id payment_type amount currency status reference_number created_at updated_at]
62
+ end
63
+
64
+ private
65
+
66
+ def record_not_found
67
+ render_error(error: "Payment request not found", status: :not_found)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ module Dscf::Payment
2
+ class PaymentsController < ApplicationController
3
+ include Dscf::Core::Common
4
+
5
+ rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
6
+
7
+ private
8
+
9
+ def authentication_required?
10
+ true
11
+ end
12
+
13
+ def model_params
14
+ # Read-only controller - no creation via API
15
+ {}
16
+ end
17
+
18
+ def eager_loaded_associations
19
+ [ :payment_request, :banking_transaction ]
20
+ end
21
+
22
+ def allowed_order_columns
23
+ %w[id transaction_reference amount currency status processed_at created_at updated_at]
24
+ end
25
+
26
+ private
27
+
28
+ def record_not_found
29
+ render_error(error: "Payment not found", status: :not_found)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,6 @@
1
+ module Dscf
2
+ module Payment
3
+ class ApplicationJob < ActiveJob::Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Dscf
2
+ module Payment
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "from@example.com"
5
+ layout "mailer"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Dscf
2
+ module Payment
3
+ class ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ module Dscf::Payment
2
+ class Payment < ApplicationRecord
3
+ self.table_name = "dscf_payment_payments"
4
+
5
+ belongs_to :payment_request, class_name: "Dscf::Payment::PaymentRequest"
6
+ belongs_to :banking_transaction, class_name: "Dscf::Banking::Transaction", optional: true
7
+
8
+ validates :transaction_reference, :amount, presence: true
9
+ validates :amount, numericality: { greater_than: 0 }
10
+ validates :status, inclusion: { in: %w[pending processing completed failed cancelled] }
11
+ validates :transaction_reference, uniqueness: true
12
+ validates :currency, presence: true
13
+
14
+ before_validation :generate_transaction_reference, on: :create
15
+
16
+ scope :by_status, ->(status) { where(status: status) }
17
+ scope :completed, -> { where(status: "completed") }
18
+ scope :failed, -> { where(status: "failed") }
19
+ scope :recent, -> { order(created_at: :desc) }
20
+
21
+ def self.ransackable_attributes(auth_object = nil)
22
+ %w[id transaction_reference amount currency status processed_at failure_reason created_at updated_at]
23
+ end
24
+
25
+ def self.ransackable_associations(auth_object = nil)
26
+ %w[payment_request banking_transaction]
27
+ end
28
+
29
+ private
30
+
31
+ def generate_transaction_reference
32
+ return if transaction_reference.present?
33
+
34
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
35
+ random_suffix = SecureRandom.hex(4).upcase
36
+ self.transaction_reference = "PAY#{timestamp}#{random_suffix}"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,64 @@
1
+ module Dscf::Payment
2
+ class PaymentRequest < ApplicationRecord
3
+ self.table_name = "dscf_payment_payment_requests"
4
+
5
+ belongs_to :from_account, class_name: "Dscf::Banking::Account", optional: true
6
+ belongs_to :to_account, class_name: "Dscf::Banking::Account", optional: true
7
+ belongs_to :payable, polymorphic: true, optional: true
8
+ has_many :payments, class_name: "Dscf::Payment::Payment", foreign_key: "payment_request_id", dependent: :destroy
9
+
10
+ validates :payment_type, :amount, :reference_number, presence: true
11
+ validates :amount, numericality: { greater_than: 0 }
12
+ validates :payment_type, inclusion: { in: %w[disbursement transfer repayment] }
13
+ validates :status, inclusion: { in: %w[pending approved processing completed failed cancelled] }
14
+ validates :reference_number, uniqueness: true
15
+ validates :currency, presence: true
16
+
17
+ before_validation :generate_reference_number, on: :create
18
+
19
+ scope :pending, -> { where(status: "pending") }
20
+ scope :approved, -> { where(status: "approved") }
21
+ scope :processing, -> { where(status: "processing") }
22
+ scope :completed, -> { where(status: "completed") }
23
+ scope :failed, -> { where(status: "failed") }
24
+ scope :by_type, ->(type) { where(payment_type: type) }
25
+
26
+ def pending?
27
+ status == "pending"
28
+ end
29
+
30
+ def approved?
31
+ status == "approved"
32
+ end
33
+
34
+ def processing?
35
+ status == "processing"
36
+ end
37
+
38
+ def completed?
39
+ status == "completed"
40
+ end
41
+
42
+ def failed?
43
+ status == "failed"
44
+ end
45
+
46
+ def self.ransackable_attributes(auth_object = nil)
47
+ %w[id payment_type amount currency status reference_number description created_at updated_at]
48
+ end
49
+
50
+ def self.ransackable_associations(auth_object = nil)
51
+ %w[from_account to_account payable payments]
52
+ end
53
+
54
+ private
55
+
56
+ def generate_reference_number
57
+ return if reference_number.present?
58
+
59
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
60
+ random_suffix = SecureRandom.hex(4).upcase
61
+ self.reference_number = "PAYREQ#{timestamp}#{random_suffix}"
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ module Dscf::Payment
2
+ class PaymentRequestSerializer < ActiveModel::Serializer
3
+ attributes :id,
4
+ :payment_type,
5
+ :amount,
6
+ :currency,
7
+ :status,
8
+ :reference_number,
9
+ :description,
10
+ :created_at,
11
+ :updated_at
12
+
13
+ belongs_to :from_account, serializer: Dscf::Banking::AccountSerializer
14
+ belongs_to :to_account, serializer: Dscf::Banking::AccountSerializer
15
+ belongs_to :payable
16
+ has_many :payments, serializer: Dscf::Payment::PaymentSerializer
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module Dscf::Payment
2
+ class PaymentSerializer < ActiveModel::Serializer
3
+ attributes :id,
4
+ :transaction_reference,
5
+ :amount,
6
+ :currency,
7
+ :status,
8
+ :processed_at,
9
+ :failure_reason,
10
+ :created_at,
11
+ :updated_at
12
+
13
+ belongs_to :payment_request, serializer: Dscf::Payment::PaymentRequestSerializer
14
+ belongs_to :banking_transaction, serializer: Dscf::Banking::TransactionSerializer
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ module Dscf::Payment
2
+ class BankingIntegrationService
3
+ def transfer(from_account, to_account, amount, description, transaction_type_code: "TRANSFER")
4
+ validate_transfer_params(from_account, to_account, amount)
5
+
6
+ transfer_service = Dscf::Banking::TransferService.new(
7
+ debit_account: from_account,
8
+ credit_account: to_account,
9
+ amount: amount,
10
+ description: description,
11
+ transaction_type_code: transaction_type_code
12
+ )
13
+
14
+ result = transfer_service.execute
15
+
16
+ unless result.success?
17
+ raise BankingTransactionError.new("Banking transfer failed: #{result.errors.join(", ")}")
18
+ end
19
+
20
+ result.transaction
21
+ rescue AccountNotActiveError, InvalidAmountError, InsufficientFundsError, BankingTransactionError
22
+ raise
23
+ rescue => e
24
+ raise BankingTransactionError.new("Banking transfer error: #{e.message}")
25
+ end
26
+
27
+ private
28
+
29
+ def validate_transfer_params(from_account, to_account, amount)
30
+ raise InvalidAmountError.new("Amount must be positive") unless amount&.positive?
31
+ raise AccountNotActiveError.new("From account not active") unless from_account&.active? && from_account.status == "active"
32
+ raise AccountNotActiveError.new("To account not active") unless to_account&.active? && to_account.status == "active"
33
+ raise InsufficientFundsError.new("Insufficient funds") unless from_account.sufficient_funds_for_withdrawal?(amount)
34
+ raise BankingTransactionError.new("Currency mismatch") unless from_account.currency == to_account.currency
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,56 @@
1
+ module Dscf::Payment
2
+ class CreditIntegrationService
3
+ def process_disbursement(amount, loan_profile, eligible_credit_line)
4
+ validate_disbursement_params(amount, loan_profile, eligible_credit_line)
5
+
6
+ disbursement_service = Dscf::Credit::DisbursementService.new(
7
+ amount: amount,
8
+ loan_profile: loan_profile,
9
+ eligible_credit_line: eligible_credit_line
10
+ )
11
+
12
+ result = disbursement_service.process_disbursement
13
+
14
+ unless result[:success]
15
+ raise CreditOperationError.new("Disbursement failed: #{result[:error]}")
16
+ end
17
+
18
+ result
19
+ rescue CreditOperationError, InvalidAmountError
20
+ raise
21
+ rescue => e
22
+ raise CreditOperationError.new("Credit disbursement error: #{e.message}")
23
+ end
24
+
25
+ def process_repayment(loan, amount, current_user)
26
+ validate_repayment_params(loan, amount, current_user)
27
+
28
+ repayment_service = Dscf::Credit::RepaymentService.new(loan, amount, current_user)
29
+ result = repayment_service.process_repayment
30
+
31
+ unless result[:success]
32
+ raise CreditOperationError.new("Repayment failed: #{result[:error]}")
33
+ end
34
+
35
+ result
36
+ rescue CreditOperationError, InvalidAmountError
37
+ raise
38
+ rescue => e
39
+ raise CreditOperationError.new("Credit repayment error: #{e.message}")
40
+ end
41
+
42
+ private
43
+
44
+ def validate_disbursement_params(amount, loan_profile, eligible_credit_line)
45
+ raise InvalidAmountError.new("Amount must be positive") unless amount&.positive?
46
+ raise CreditOperationError.new("Loan profile required") unless loan_profile
47
+ raise CreditOperationError.new("Eligible credit line required") unless eligible_credit_line
48
+ end
49
+
50
+ def validate_repayment_params(loan, amount, current_user)
51
+ raise InvalidAmountError.new("Amount must be positive") unless amount&.positive?
52
+ raise CreditOperationError.new("Loan required") unless loan
53
+ raise CreditOperationError.new("Current user required") unless current_user
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,128 @@
1
+ module Dscf::Payment
2
+ class PaymentService
3
+ attr_reader :payment_request, :current_user
4
+
5
+ def initialize(payment_request, current_user = nil)
6
+ @payment_request = payment_request
7
+ @current_user = current_user
8
+ end
9
+
10
+ def process
11
+ validate_payment_request
12
+
13
+ ActiveRecord::Base.transaction do
14
+ payment = create_payment_record
15
+
16
+ case payment_request.payment_type
17
+ when "disbursement"
18
+ process_disbursement(payment)
19
+ when "transfer"
20
+ process_transfer(payment)
21
+ when "repayment"
22
+ process_repayment(payment)
23
+ else
24
+ raise InvalidPaymentTypeError.new("Unknown payment type: #{payment_request.payment_type}")
25
+ end
26
+
27
+ mark_payment_completed(payment)
28
+ payment
29
+ end
30
+ rescue => e
31
+ handle_payment_failure(e)
32
+ raise
33
+ end
34
+
35
+ private
36
+
37
+ def validate_payment_request
38
+ raise InvalidPaymentTypeError.new("Invalid payment type") unless valid_payment_type?
39
+ raise PaymentError.new("Payment request already processed") if payment_request.processing? || payment_request.completed?
40
+ end
41
+
42
+ def valid_payment_type?
43
+ %w[disbursement transfer repayment].include?(payment_request.payment_type)
44
+ end
45
+
46
+ def create_payment_record
47
+ payment_request.payments.create!(
48
+ amount: payment_request.amount,
49
+ currency: payment_request.currency,
50
+ status: "processing"
51
+ )
52
+ end
53
+
54
+ def process_disbursement(payment)
55
+ # For disbursements: settlement account -> customer account
56
+ settlement_account = SettlementAccountService.settlement_account_for(currency: payment_request.currency)
57
+
58
+ # First, process the credit disbursement
59
+ credit_service = CreditIntegrationService.new
60
+ credit_service.process_disbursement(
61
+ payment_request.amount,
62
+ payment_request.payable, # Should be loan_profile
63
+ payment_request.metadata["eligible_credit_line"] # Need to store this in metadata
64
+ )
65
+
66
+ # Then transfer from settlement to customer account
67
+ banking_service = BankingIntegrationService.new
68
+ banking_transaction = banking_service.transfer(
69
+ settlement_account,
70
+ payment_request.to_account,
71
+ payment_request.amount,
72
+ "Loan disbursement for #{payment_request.reference_number}"
73
+ )
74
+
75
+ payment.update!(banking_transaction: banking_transaction)
76
+ end
77
+
78
+ def process_transfer(payment)
79
+ # Direct account to account transfer
80
+ banking_service = BankingIntegrationService.new
81
+ banking_transaction = banking_service.transfer(
82
+ payment_request.from_account,
83
+ payment_request.to_account,
84
+ payment_request.amount,
85
+ "Account transfer for #{payment_request.reference_number}"
86
+ )
87
+
88
+ payment.update!(banking_transaction: banking_transaction)
89
+ end
90
+
91
+ def process_repayment(payment)
92
+ # For repayments: customer account -> settlement account
93
+ settlement_account = SettlementAccountService.settlement_account_for(currency: payment_request.currency)
94
+
95
+ # First transfer to settlement account
96
+ banking_service = BankingIntegrationService.new
97
+ banking_transaction = banking_service.transfer(
98
+ payment_request.from_account,
99
+ settlement_account,
100
+ payment_request.amount,
101
+ "Loan repayment for #{payment_request.reference_number}"
102
+ )
103
+
104
+ credit_service = CreditIntegrationService.new
105
+ credit_service.process_repayment(
106
+ payment_request.payable,
107
+ payment_request.amount,
108
+ current_user
109
+ )
110
+
111
+ payment.update!(banking_transaction: banking_transaction)
112
+ end
113
+
114
+ def mark_payment_completed(payment)
115
+ payment.update!(status: "completed", processed_at: Time.current)
116
+ payment_request.update!(status: "completed")
117
+ end
118
+
119
+ def handle_payment_failure(error)
120
+ payment_request.payments.where(status: "processing").update_all(
121
+ status: "failed",
122
+ failure_reason: error.message,
123
+ processed_at: Time.current
124
+ )
125
+ payment_request.update_column(:status, "failed")
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,37 @@
1
+ module Dscf::Payment
2
+ class SettlementAccountService
3
+ SETTLEMENT_ACCOUNT_NAME = "DSCF Payment Settlement Account"
4
+
5
+ class << self
6
+ def find_or_create_settlement_account(currency: "ETB")
7
+ account = Dscf::Banking::Account.find_by(
8
+ name: SETTLEMENT_ACCOUNT_NAME,
9
+ currency: currency,
10
+ system_account: true
11
+ )
12
+
13
+ return account if account
14
+
15
+ # Create new settlement account
16
+ Dscf::Banking::Account.create!(
17
+ name: SETTLEMENT_ACCOUNT_NAME,
18
+ currency: currency,
19
+ system_account: true,
20
+ current_balance: 0,
21
+ available_balance: 0,
22
+ minimum_balance: 0,
23
+ status: :active,
24
+ active: true
25
+ )
26
+ rescue ActiveRecord::RecordInvalid => e
27
+ raise SettlementAccountError.new("Failed to create settlement account: #{e.message}")
28
+ end
29
+
30
+ def settlement_account_for(currency: "ETB")
31
+ account = find_or_create_settlement_account(currency: currency)
32
+ raise SettlementAccountError.new("Settlement account not found for currency #{currency}") unless account
33
+ account
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ en:
2
+ dscf:
3
+ payment:
4
+ payment_request:
5
+ success:
6
+ create: "Payment request created successfully"
7
+ show: "Payment request retrieved successfully"
8
+ index: "Payment requests retrieved successfully"
9
+ process: "Payment processed successfully"
10
+ errors:
11
+ create: "Failed to create payment request"
12
+ show: "Payment request not found"
13
+ index: "Failed to retrieve payment requests"
14
+ process: "Failed to process payment"
15
+ payment:
16
+ success:
17
+ show: "Payment retrieved successfully"
18
+ index: "Payments retrieved successfully"
19
+ errors:
20
+ show: "Payment not found"
21
+ index: "Failed to retrieve payments"
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ Dscf::Payment::Engine.routes.draw do
2
+ resources :payment_requests do
3
+ member do
4
+ post :process_payment
5
+ end
6
+ end
7
+ resources :payments, only: [ :index, :show ]
8
+ end