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
@@ -0,0 +1,32 @@
1
+ class CreateDscfPaymentPaymentRequests < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_payment_payment_requests do |t|
4
+ t.string :payment_type, null: false
5
+ t.references :from_account, null: false, foreign_key: { to_table: :dscf_banking_accounts }
6
+ t.references :to_account, null: false, foreign_key: { to_table: :dscf_banking_accounts }
7
+ t.decimal :amount, precision: 15, scale: 2, null: false
8
+ t.string :currency, default: "ETB"
9
+ t.string :status, default: "pending"
10
+ t.string :reference_number, null: false
11
+ t.text :description
12
+ t.jsonb :metadata, default: {}
13
+ t.references :payable, polymorphic: true
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :dscf_payment_payment_requests, :reference_number,
19
+ unique: true,
20
+ name: "reference_number_on_dscf_payment_payment_requests_indx"
21
+ add_index :dscf_payment_payment_requests, :payment_type,
22
+ name: "payment_type_on_dscf_payment_payment_requests_indx"
23
+ add_index :dscf_payment_payment_requests, :status,
24
+ name: "status_on_dscf_payment_payment_requests_indx"
25
+ add_index :dscf_payment_payment_requests, :from_account_id,
26
+ name: "from_account_id_on_dscf_payment_payment_requests_indx"
27
+ add_index :dscf_payment_payment_requests, :to_account_id,
28
+ name: "to_account_id_on_dscf_payment_payment_requests_indx"
29
+ add_index :dscf_payment_payment_requests, [ :payable_type, :payable_id ],
30
+ name: "payable_on_dscf_payment_payment_requests_indx"
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ class CreateDscfPaymentPayments < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_payment_payments do |t|
4
+ t.references :payment_request, null: false, foreign_key: { to_table: :dscf_payment_payment_requests }
5
+ t.string :transaction_reference, null: false
6
+ t.decimal :amount, precision: 15, scale: 2, null: false
7
+ t.string :currency, default: "ETB"
8
+ t.string :status, default: "pending"
9
+ t.datetime :processed_at
10
+ t.text :failure_reason
11
+ t.references :banking_transaction, foreign_key: { to_table: :dscf_banking_transactions }
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :dscf_payment_payments, :transaction_reference,
17
+ unique: true,
18
+ name: "transaction_reference_on_dscf_payment_payments_indx"
19
+ add_index :dscf_payment_payments, :status,
20
+ name: "status_on_dscf_payment_payments_indx"
21
+ add_index :dscf_payment_payments, :processed_at,
22
+ name: "processed_at_on_dscf_payment_payments_indx"
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ class MakePaymentRequestAccountsOptional < ActiveRecord::Migration[8.0]
2
+ def change
3
+ change_column_null :dscf_payment_payment_requests, :from_account_id, true
4
+ change_column_null :dscf_payment_payment_requests, :to_account_id, true
5
+ end
6
+ end
@@ -0,0 +1,31 @@
1
+ require "dscf/payment/errors"
2
+
3
+ module Dscf
4
+ module Payment
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Dscf::Payment
7
+ config.generators.api_only = true
8
+
9
+ # Load dependent engines and their migrations for testing
10
+ initializer :load_dependent_engines do
11
+ require "dscf/core"
12
+ require "dscf/banking"
13
+ require "dscf/credit"
14
+ end
15
+
16
+ # Ensure dependent engine migrations are available in test environment
17
+ initializer :append_dependent_migrations, after: :load_dependent_engines do |app|
18
+ # Append migrations from dependent engines
19
+ if defined?(Dscf::Core::Engine)
20
+ app.config.paths["db/migrate"].concat(Dscf::Core::Engine.config.paths["db/migrate"].expanded)
21
+ end
22
+ if defined?(Dscf::Banking::Engine)
23
+ app.config.paths["db/migrate"].concat(Dscf::Banking::Engine.config.paths["db/migrate"].expanded)
24
+ end
25
+ if defined?(Dscf::Credit::Engine)
26
+ app.config.paths["db/migrate"].concat(Dscf::Credit::Engine.config.paths["db/migrate"].expanded)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,10 @@
1
+ module Dscf::Payment
2
+ class PaymentError < StandardError; end
3
+ class InsufficientFundsError < PaymentError; end
4
+ class AccountNotActiveError < PaymentError; end
5
+ class InvalidPaymentTypeError < PaymentError; end
6
+ class InvalidAmountError < PaymentError; end
7
+ class SettlementAccountError < PaymentError; end
8
+ class BankingTransactionError < PaymentError; end
9
+ class CreditOperationError < PaymentError; end
10
+ end
@@ -0,0 +1,5 @@
1
+ module Dscf
2
+ module Payment
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require "dscf/payment/version"
2
+ require "dscf/payment/engine"
3
+
4
+ module Dscf
5
+ module Payment
6
+ # Your code goes here...
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :dscf_payment do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,56 @@
1
+ FactoryBot.define do
2
+ factory :dscf_payment_payment_request, class: "Dscf::Payment::PaymentRequest" do
3
+ association :from_account, factory: :dscf_banking_account
4
+ association :to_account, factory: :dscf_banking_account
5
+
6
+ payment_type { "transfer" }
7
+ amount { 1000.00 }
8
+ currency { "ETB" }
9
+ status { "pending" }
10
+ description { "Test payment request" }
11
+ metadata { {} }
12
+
13
+ trait :disbursement do
14
+ payment_type { "disbursement" }
15
+ # Add associations for disbursement-specific data
16
+ end
17
+
18
+ trait :transfer do
19
+ payment_type { "transfer" }
20
+ end
21
+
22
+ trait :repayment do
23
+ payment_type { "repayment" }
24
+ # Add associations for repayment-specific data
25
+ end
26
+
27
+ trait :approved do
28
+ status { "approved" }
29
+ end
30
+
31
+ trait :processing do
32
+ status { "processing" }
33
+ end
34
+
35
+ trait :completed do
36
+ status { "completed" }
37
+ end
38
+
39
+ trait :failed do
40
+ status { "failed" }
41
+ end
42
+ end
43
+
44
+ # Alias for shared spec compatibility
45
+ factory :payment_request, class: "Dscf::Payment::PaymentRequest" do
46
+ association :from_account, factory: :dscf_banking_account
47
+ association :to_account, factory: :dscf_banking_account
48
+
49
+ payment_type { "transfer" }
50
+ amount { 1000.00 }
51
+ currency { "ETB" }
52
+ status { "pending" }
53
+ description { "Test payment request" }
54
+ metadata { {} }
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ FactoryBot.define do
2
+ factory :dscf_payment_payment, class: "Dscf::Payment::Payment" do
3
+ association :payment_request, factory: :dscf_payment_payment_request
4
+
5
+ amount { 1000.00 }
6
+ currency { "ETB" }
7
+ status { "pending" }
8
+
9
+ trait :processing do
10
+ status { "processing" }
11
+ end
12
+
13
+ trait :completed do
14
+ status { "completed" }
15
+ processed_at { Time.current }
16
+ end
17
+
18
+ trait :failed do
19
+ status { "failed" }
20
+ failure_reason { "Test failure reason" }
21
+ processed_at { Time.current }
22
+ end
23
+
24
+ trait :with_banking_transaction do
25
+ association :banking_transaction, factory: :dscf_banking_transaction
26
+ end
27
+ end
28
+
29
+ # Alias for shared spec compatibility
30
+ factory :payment, class: "Dscf::Payment::Payment" do
31
+ association :payment_request, factory: :dscf_payment_payment_request
32
+
33
+ amount { 1000.00 }
34
+ currency { "ETB" }
35
+ status { "pending" }
36
+ end
37
+ end