paystack-gateway 0.1.0 → 0.2.0

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -2
  3. data/CHANGELOG.md +57 -0
  4. data/README.md +88 -105
  5. data/lib/paystack_gateway/api_error.rb +12 -2
  6. data/lib/paystack_gateway/apple_pay.rb +92 -0
  7. data/lib/paystack_gateway/balance.rb +62 -0
  8. data/lib/paystack_gateway/bank.rb +181 -0
  9. data/lib/paystack_gateway/bulk_charge.rb +197 -0
  10. data/lib/paystack_gateway/charge.rb +346 -0
  11. data/lib/paystack_gateway/configuration.rb +5 -3
  12. data/lib/paystack_gateway/customer.rb +498 -0
  13. data/lib/paystack_gateway/customers.rb +1 -42
  14. data/lib/paystack_gateway/dedicated_virtual_account.rb +353 -0
  15. data/lib/paystack_gateway/dedicated_virtual_accounts.rb +1 -64
  16. data/lib/paystack_gateway/direct_debit.rb +64 -0
  17. data/lib/paystack_gateway/dispute.rb +380 -0
  18. data/lib/paystack_gateway/extensions/customer_extensions.rb +14 -0
  19. data/lib/paystack_gateway/extensions/plan_extensions.rb +36 -0
  20. data/lib/paystack_gateway/extensions/refund_extensions.rb +43 -0
  21. data/lib/paystack_gateway/extensions/transaction_extensions.rb +40 -0
  22. data/lib/paystack_gateway/extensions/transaction_response_extension.rb +31 -0
  23. data/lib/paystack_gateway/extensions/transfer_extensions.rb +34 -0
  24. data/lib/paystack_gateway/integration.rb +60 -0
  25. data/lib/paystack_gateway/legacy/customers.rb +48 -0
  26. data/lib/paystack_gateway/legacy/dedicated_virtual_accounts.rb +70 -0
  27. data/lib/paystack_gateway/legacy/miscellaneous.rb +30 -0
  28. data/lib/paystack_gateway/legacy/plans.rb +86 -0
  29. data/lib/paystack_gateway/legacy/refunds.rb +65 -0
  30. data/lib/paystack_gateway/legacy/subaccounts.rb +41 -0
  31. data/lib/paystack_gateway/legacy/transaction_response.rb +37 -0
  32. data/lib/paystack_gateway/legacy/transactions.rb +91 -0
  33. data/lib/paystack_gateway/legacy/transfer_recipients.rb +27 -0
  34. data/lib/paystack_gateway/legacy/transfers.rb +63 -0
  35. data/lib/paystack_gateway/legacy/verification.rb +37 -0
  36. data/lib/paystack_gateway/miscellaneous.rb +75 -13
  37. data/lib/paystack_gateway/order.rb +259 -0
  38. data/lib/paystack_gateway/page.rb +317 -0
  39. data/lib/paystack_gateway/payment_request.rb +454 -0
  40. data/lib/paystack_gateway/plan.rb +247 -0
  41. data/lib/paystack_gateway/plans.rb +1 -80
  42. data/lib/paystack_gateway/product.rb +303 -0
  43. data/lib/paystack_gateway/refund.rb +197 -0
  44. data/lib/paystack_gateway/refunds.rb +1 -59
  45. data/lib/paystack_gateway/request_module.rb +20 -15
  46. data/lib/paystack_gateway/settlement.rb +60 -0
  47. data/lib/paystack_gateway/split.rb +286 -0
  48. data/lib/paystack_gateway/storefront.rb +329 -0
  49. data/lib/paystack_gateway/subaccount.rb +263 -0
  50. data/lib/paystack_gateway/subaccounts.rb +1 -35
  51. data/lib/paystack_gateway/subscription.rb +256 -0
  52. data/lib/paystack_gateway/terminal.rb +236 -0
  53. data/lib/paystack_gateway/transaction.rb +592 -0
  54. data/lib/paystack_gateway/transaction_response.rb +1 -33
  55. data/lib/paystack_gateway/transactions.rb +1 -86
  56. data/lib/paystack_gateway/transfer.rb +410 -0
  57. data/lib/paystack_gateway/transfer_recipient.rb +237 -0
  58. data/lib/paystack_gateway/transfer_recipients.rb +1 -21
  59. data/lib/paystack_gateway/transfers.rb +1 -57
  60. data/lib/paystack_gateway/verification.rb +1 -31
  61. data/lib/paystack_gateway/version.rb +1 -1
  62. data/lib/paystack_gateway/virtual_terminal.rb +297 -0
  63. data/lib/paystack_gateway.rb +61 -11
  64. metadata +50 -7
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # The Dedicated Virtual Account API enables Nigerian merchants to manage unique
7
+ # payment accounts of their customers.
8
+ # https://paystack.com/docs/api/dedicated-virtual-account
9
+ #
10
+ # @deprecated Use PaystackGateway::DedicatedVirtualAccount instead.
11
+ module DedicatedVirtualAccounts
12
+ include PaystackGateway::RequestModule
13
+
14
+ # Response from POST /dedicated_account endpoint.
15
+ class CreateDedicatedVirtualAccountResponse < PaystackGateway::Response; end
16
+
17
+ api_method def self.create_dedicated_virtual_account(customer_id_or_code:, subaccount_code:, preferred_bank:)
18
+ use_connection do |connection|
19
+ connection.post(
20
+ '/dedicated_account',
21
+ {
22
+ customer: customer_id_or_code,
23
+ preferred_bank:,
24
+ subaccount: subaccount_code,
25
+ phone: '+2348011111111', # phone number is required by paystack for some reason, use fake phone number
26
+ },
27
+ )
28
+ end
29
+ end
30
+
31
+ # Response from POST /dedicated_account/assign endpoint.
32
+ class AssignDedicatedVirtualAccountResponse < PaystackGateway::Response; end
33
+
34
+ api_method def self.assign_dedicated_virtual_account(
35
+ email:, first_name:, last_name:, subaccount_code:, preferred_bank:
36
+ )
37
+ use_connection do |connection|
38
+ connection.post(
39
+ '/dedicated_account/assign',
40
+ {
41
+ email:,
42
+ first_name:,
43
+ last_name:,
44
+ preferred_bank:,
45
+ country: :NG,
46
+ subaccount: subaccount_code,
47
+ },
48
+ )
49
+ end
50
+ end
51
+
52
+ # Response from POST /dedicated_account/split endpoint
53
+ class SplitDedicatedAccountTransactionResponse < PaystackGateway::Response; end
54
+
55
+ api_method def self.split_dedicated_account_transaction(customer_id_or_code:, subaccount_code:)
56
+ use_connection do |connection|
57
+ connection.post('/dedicated_account/split', { customer: customer_id_or_code, subaccount: subaccount_code })
58
+ end
59
+ end
60
+
61
+ # Response from GET /dedicated_account/requery/:account_number endpoint
62
+ class RequeryDedicatedAccountResponse < PaystackGateway::Response; end
63
+
64
+ api_method def self.requery_dedicated_account(account_number:, bank:)
65
+ use_connection do |connection|
66
+ connection.get('/dedicated_account/requery', { account_number:, provider_slug: bank })
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaystackGateway
4
+ # Backwards-compatible API methods retained from releases before 0.2.0.
5
+ module Miscellaneous
6
+ include PaystackGateway::RequestModule
7
+
8
+ # Successful response from GET /bank.
9
+ class ListBanksResponse < PaystackGateway::Response
10
+ def bank_names = data.map(&:name)
11
+ def bank_slugs = data.map(&:slug)
12
+
13
+ def bank_details(*attributes) = data.map { _1.slice(*attributes) }
14
+
15
+ def by_bank_names = data.index_by(&:name)
16
+ def by_bank_codes = data.index_by(&:code)
17
+ end
18
+
19
+ # Error response from GET /bank.
20
+ class ListBanksError < ApiError; end
21
+
22
+ # https://paystack.com/docs/api/miscellaneous/#bank
23
+ # @deprecated Use PaystackGateway::Bank.list instead.
24
+ api_method def self.list_banks(use_cache: true, pay_with_bank_transfer: false)
25
+ use_connection(cache_options: use_cache ? {} : nil) do |connection|
26
+ connection.get('/bank', pay_with_bank_transfer ? { pay_with_bank_transfer: } : {})
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Create and manage installment payment options
7
+ # https://paystack.com/docs/api/plan/#create
8
+ #
9
+ # @deprecated Use PaystackGateway::Plan instead.
10
+ module Plans
11
+ include PaystackGateway::RequestModule
12
+
13
+ # Response from POST /plan endpoint.
14
+ class CreatePlanResponse < PaystackGateway::Response
15
+ delegate :id, to: :data, prefix: :plan
16
+ delegate :id, :plan_code, to: :data
17
+ end
18
+
19
+ api_method def self.create_plan(name:, amount:, interval:)
20
+ use_connection do |connection|
21
+ connection.post(
22
+ '/plan',
23
+ {
24
+ name:,
25
+ interval:,
26
+ amount: amount * 100,
27
+ send_invoices: false,
28
+ send_sms: false,
29
+ },
30
+ )
31
+ end
32
+ end
33
+
34
+ # Response from GET /plan endpoint.
35
+ class ListPlansResponse < PaystackGateway::Response
36
+ def active_plans = data.select { |plan| !plan.is_deleted && !plan.is_archived }
37
+
38
+ def find_active_plan_by_name(name)
39
+ active_plans.sort_by { -Time.parse(_1.createdAt).to_i }.find { _1.name == name }
40
+ end
41
+ end
42
+
43
+ api_method def self.list_plans
44
+ use_connection do |connection|
45
+ connection.get('/plan')
46
+ end
47
+ end
48
+
49
+ # Response from GET /plan/:code endpoint.
50
+ class FetchPlanResponse < PaystackGateway::Response
51
+ delegate :subscriptions, to: :data
52
+
53
+ def active_subscriptions = subscriptions.select { _1.status.to_sym == :active }
54
+
55
+ def active_subscription_codes(email: nil)
56
+ subscriptions =
57
+ if email
58
+ active_subscriptions.select { _1.customer.email.casecmp?(email) }
59
+ else
60
+ active_subscriptions
61
+ end
62
+ subscriptions.map(&:subscription_code)
63
+ end
64
+ end
65
+
66
+ api_method def self.fetch_plan(code:)
67
+ use_connection do |connection|
68
+ connection.get("/plan/#{code}")
69
+ end
70
+ end
71
+
72
+ class UpdatePlanResponse < PaystackGateway::Response; end
73
+
74
+ api_method def self.update_plan(code:, amount:, interval:)
75
+ use_connection do |connection|
76
+ connection.put(
77
+ "/plan/#{code}",
78
+ {
79
+ amount: amount * 100,
80
+ interval:,
81
+ },
82
+ )
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Create and manage transaction refunds.
7
+ # https://paystack.com/docs/api/refund
8
+ #
9
+ # @deprecated Use PaystackGateway::Refund instead.
10
+ module Refunds
11
+ include PaystackGateway::RequestModule
12
+
13
+ # Common helpers for responses from refunds endpoints
14
+ module TransactionRefundResponse
15
+ def refund_success? = transaction_status == :processed
16
+ def refund_failed? = transaction_status == :failed
17
+ def refund_pending? = transaction_status.in?(%i[pending processing])
18
+ end
19
+
20
+ # Response from POST /refund endpoint.
21
+ class CreateResponse < PaystackGateway::Response
22
+ include TransactionResponse
23
+ include TransactionRefundResponse
24
+ end
25
+
26
+ api_method def self.create(transaction_reference_or_id:)
27
+ use_connection do |connection|
28
+ connection.post('/refund', { transaction: transaction_reference_or_id })
29
+ end
30
+ end
31
+
32
+ # Response from GET /refund endpoint.
33
+ class ListRefundsResponse < PaystackGateway::Response
34
+ def pending_or_successful
35
+ filtered = data.select { _1.status&.to_sym.in?(%i[processed pending processing]) }
36
+
37
+ ListRefundsResponse.new({ **self, data: filtered })
38
+ end
39
+
40
+ def with_amount(amount)
41
+ filtered = data.select { _1.amount == amount * 100 }
42
+
43
+ ListRefundsResponse.new({ **self, data: filtered })
44
+ end
45
+ end
46
+
47
+ api_method def self.list_refunds(transaction_id:)
48
+ use_connection do |connection|
49
+ connection.get('/refund', { transaction: transaction_id })
50
+ end
51
+ end
52
+
53
+ # Response from GET /refund/:id endpoint.
54
+ class FetchRefundResponse < PaystackGateway::Response
55
+ include TransactionResponse
56
+ include TransactionRefundResponse
57
+ end
58
+
59
+ api_method def self.fetch_refund(refund_id:)
60
+ use_connection do |connection|
61
+ connection.get("/refund/#{refund_id}")
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Create and manage subaccounts https://paystack.com/docs/api/subaccount/
7
+ #
8
+ # @deprecated Use PaystackGateway::Subaccount instead.
9
+ module Subaccounts
10
+ include PaystackGateway::RequestModule
11
+
12
+ # Response from POST /subaccount
13
+ class CreateSubaccountResponse < PaystackGateway::Response
14
+ delegate :subaccount_code, to: :data
15
+ end
16
+
17
+ api_method def self.create_subaccount(business_name:, settlement_bank:, account_number:, percentage_charge:)
18
+ use_connection do |connection|
19
+ connection.post(
20
+ '/subaccount',
21
+ { business_name:, settlement_bank:, account_number:, percentage_charge: }.compact,
22
+ )
23
+ end
24
+ end
25
+
26
+ # Response from PUT /subaccount/:id_or_code
27
+ class UpdateSubaccountResponse < CreateSubaccountResponse; end
28
+
29
+ api_method def self.update_subaccount(
30
+ subaccount_code,
31
+ business_name: nil, settlement_bank: nil, account_number: nil, percentage_charge: nil
32
+ )
33
+ use_connection do |connection|
34
+ connection.put(
35
+ "/subaccount/#{subaccount_code}",
36
+ { business_name:, settlement_bank:, account_number:, percentage_charge: }.compact,
37
+ )
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Common helpers for responses from transaction endpoints
7
+ module TransactionResponse
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ delegate :id, :amount, :subaccount, :fees_split, to: :data
12
+
13
+ attr_writer :completed_at
14
+ end
15
+
16
+ def transaction_success? = transaction_status.in?(%i[success reversed reversal_pending])
17
+ def transaction_abandoned? = transaction_status == :abandoned
18
+ def transaction_failed? = transaction_status == :failed
19
+ def transaction_pending? = transaction_status.in?(%i[pending ongoing])
20
+
21
+ def transaction_status = data.status.to_sym
22
+ def transaction_amount = amount / BigDecimal('100')
23
+ def transaction_completed_at = data[:updatedAt] || @completed_at
24
+
25
+ def subaccount_amount
26
+ return if !subaccount || !fees_split
27
+
28
+ fees_split.subaccount / BigDecimal('100')
29
+ end
30
+
31
+ def failure_reason
32
+ return if !transaction_failed? && !transaction_abandoned?
33
+
34
+ data.gateway_response || transaction_status || message
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Create and manage payments https://paystack.com/docs/api/#transaction
7
+ #
8
+ # @deprecated Use PaystackGateway::Transaction instead.
9
+ module Transactions
10
+ include PaystackGateway::RequestModule
11
+
12
+ # Response from POST /transaction/initialize endpoint.
13
+ class InitializeTransactionResponse < PaystackGateway::Response
14
+ delegate :authorization_url, to: :data
15
+
16
+ alias payment_url authorization_url
17
+ end
18
+
19
+ # Raised when an error occurs while calling POST /transaction/initialize
20
+ class InitializeTransactionError < ApiError
21
+ def cancellable? = super || network_error?
22
+ end
23
+
24
+ # Response looks like this.
25
+ # {
26
+ # "status": true,
27
+ # "message": "Authorization URL created",
28
+ # "data": {
29
+ # "authorization_url": "https://checkout.paystack.com/n4ysyedbuseog8c",
30
+ # "access_code": "n4ysyedbuseog8c",
31
+ # "reference": "hlr4bxhypt"
32
+ # }
33
+ # }
34
+ api_method def self.initialize_transaction(**transaction_data)
35
+ raise ApiError.new(:invalid_amount, cancellable: true) if transaction_data[:amount].blank?
36
+ raise ApiError.new(:invalid_reference, cancellable: true) if transaction_data[:reference].blank?
37
+ raise ApiError.new(:invalid_email, cancellable: true) if transaction_data[:email].blank?
38
+
39
+ transaction_data[:amount] = (transaction_data[:amount] * 100).to_i
40
+
41
+ use_connection do |connection|
42
+ connection.post('/transaction/initialize', transaction_data.compact)
43
+ end
44
+ end
45
+
46
+ # Response from GET /transaction/verify/:reference endpoint.
47
+ class VerifyTransactionResponse < PaystackGateway::Response
48
+ include TransactionResponse
49
+
50
+ delegate :paid_at, to: :data
51
+
52
+ def transaction_completed_at
53
+ paid_at || super
54
+ end
55
+ end
56
+
57
+ # Raised when an error occurs while calling /transactions/verify/:reference
58
+ class VerifyTransactionError < ApiError
59
+ def transaction_not_found?
60
+ parsed_response_body[:status] == false &&
61
+ parsed_response_body[:message]&.match?(/transaction reference not found/i)
62
+ end
63
+ end
64
+
65
+ api_method def self.verify_transaction(reference:)
66
+ raise VerifyTransactionError, :invalid_reference if reference.blank?
67
+
68
+ use_connection do |connection|
69
+ connection.get("/transaction/verify/#{reference}")
70
+ end
71
+ end
72
+
73
+ # Response from POST /transaction/charge_authorization endpoint.
74
+ class ChargeAuthorizationResponse < PaystackGateway::Response
75
+ include TransactionResponse
76
+ end
77
+
78
+ api_method def self.charge_authorization(**transaction_data)
79
+ raise ApiError.new(:invalid_amount, cancellable: true) if transaction_data[:amount].blank?
80
+ raise ApiError.new(:invalid_reference, cancellable: true) if transaction_data[:reference].blank?
81
+ raise ApiError.new(:invalid_authorization_code, cancellable: true) if transaction_data[:authorization_code].blank?
82
+ raise ApiError.new(:invalid_email, cancellable: true) if transaction_data[:email].blank?
83
+
84
+ transaction_data[:amount] = (transaction_data[:amount] * 100).to_i
85
+
86
+ use_connection do |connection|
87
+ connection.post('/transaction/charge_authorization', transaction_data.compact)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Create and manage beneficiaries that you send money to
7
+ # https://paystack.com/docs/api/#transfer-recipient
8
+ #
9
+ # @deprecated Use PaystackGateway::TransferRecipient instead.
10
+ module TransferRecipients
11
+ include PaystackGateway::RequestModule
12
+
13
+ # Response from POST /transferrecipient endpoint.
14
+ class CreateTransferRecipientResponse < PaystackGateway::Response
15
+ delegate :id, :recipient_code, to: :data
16
+ end
17
+
18
+ api_method def self.create_transfer_recipient(name:, account_number:, bank_code:)
19
+ use_connection do |connection|
20
+ connection.post(
21
+ '/transferrecipient',
22
+ { type: :nuban, name: name, account_number: account_number, bank_code: bank_code, currency: :NGN },
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Automate sending money https://paystack.com/docs/api/#transfer
7
+ #
8
+ # @deprecated Use PaystackGateway::Transfer instead.
9
+ module Transfers
10
+ include PaystackGateway::RequestModule
11
+
12
+ # Response from POST /transfer endpoint.
13
+ class InitiateTransferResponse < PaystackGateway::Response
14
+ include TransactionResponse
15
+
16
+ delegate :transfer_code, :transferred_at, to: :data
17
+
18
+ def transaction_completed_at
19
+ transferred_at || super
20
+ end
21
+ end
22
+
23
+ # Raised when an error occurs while calling POST /transfer
24
+ class InitiateTransferError < ApiError
25
+ def transaction_failed?
26
+ parsed_response_body[:status] == false && http_code == 400
27
+ end
28
+
29
+ def failure_reason
30
+ parsed_response_body[:message]
31
+ end
32
+ end
33
+
34
+ api_method def self.initiate_transfer(amount:, recipient_code:, reference:, reason: nil)
35
+ response = use_connection do |connection|
36
+ connection.post(
37
+ '/transfer',
38
+ {
39
+ source: :balance, amount: (amount * 100).to_i, recipient: recipient_code,
40
+ reference: reference, reason: reason,
41
+ }.compact,
42
+ )
43
+ end
44
+ response.tap { |r| r.completed_at = Time.current }
45
+ end
46
+
47
+ # Response from GET /transfer/verify/:reference endpoint.
48
+ class VerifyTransferResponse < InitiateTransferResponse; end
49
+
50
+ # Raised when an error occurs while calling GET /transfer/verify/:reference
51
+ class VerifyTransferError < ApiError
52
+ def transaction_not_found?
53
+ parsed_response_body[:status] == false && parsed_response_body[:message]&.match?(/transfer not found/i)
54
+ end
55
+ end
56
+
57
+ api_method def self.verify_transfer(reference:)
58
+ use_connection do |connection|
59
+ connection.get("/transfer/verify/#{reference}")
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Legacy implementation retained for backwards compatibility.
4
+
5
+ module PaystackGateway
6
+ # Perform KYC processes https://paystack.com/docs/api/#verification
7
+ #
8
+ # @deprecated Use PaystackGateway::Bank instead.
9
+ module Verification
10
+ include PaystackGateway::RequestModule
11
+
12
+ # Response from GET /bank/resolve endpoint.
13
+ class ResolveAccountNumberResponse < PaystackGateway::Response
14
+ delegate :account_name, :bank_id, to: :data
15
+
16
+ def account_valid?
17
+ status && account_name.present?
18
+ end
19
+ end
20
+
21
+ # Raised when an error occurs while calling /bank/resolve
22
+ class ResolveAccountNumberError < ApiError
23
+ def invalid_account?
24
+ http_code == 422 && parsed_response_body[:status] == false
25
+ end
26
+ end
27
+
28
+ api_method def self.resolve_account_number(account_number:, bank_code:)
29
+ use_connection(cache_options: {}) do |connection|
30
+ connection.get(
31
+ '/bank/resolve',
32
+ { account_number: account_number, bank_code: bank_code },
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,26 +1,88 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PaystackGateway
4
- # Supporting APIs that can be used to provide more details to other APIs
5
- # https://paystack.com/docs/api/#miscellaneous
4
+ # https://paystack.com/docs/api/miscellaneous
5
+ #
6
+ # Miscellaneous
7
+ # A collection of endpoints that provides utility functions
6
8
  module Miscellaneous
7
9
  include PaystackGateway::RequestModule
8
10
 
9
- # Response from GET /bank endpoint.
10
- class ListBanksResponse < PaystackGateway::Response
11
- def bank_names = data.map(&:name)
12
- def bank_slugs = data.map(&:slug)
11
+ # Successful response from calling #resolve_card_bin.
12
+ class ResolveCardBinResponse < PaystackGateway::Response
13
+ delegate :bin,
14
+ :brand,
15
+ :sub_brand,
16
+ :country_code,
17
+ :country_name,
18
+ :card_type,
19
+ :bank,
20
+ :currency,
21
+ :linked_bank_id, to: :data
22
+ end
13
23
 
14
- def bank_details(*attributes) = data.map { _1.slice(*attributes) }
24
+ # Error response from #resolve_card_bin.
25
+ class ResolveCardBinError < ApiError; end
15
26
 
16
- def by_bank_names = data.index_by(&:name)
17
- def by_bank_codes = data.index_by(&:code)
27
+ # https://paystack.com/docs/api/miscellaneous/#resolve_card_bin
28
+ # Resolve Card BIN: GET /decision/bin/{bin}
29
+ # Get the details of a card BIN
30
+ #
31
+ # @param bin [Integer] (required)
32
+ # The card bank identification number
33
+ #
34
+ # @return [ResolveCardBinResponse] successful response
35
+ # @raise [ResolveCardBinError] if the request fails
36
+ api_method def self.resolve_card_bin(bin:)
37
+ use_connection do |connection|
38
+ connection.get(
39
+ "/decision/bin/#{bin}",
40
+ )
41
+ end
18
42
  end
19
43
 
20
- # https://paystack.com/docs/api/miscellaneous/#bank
21
- api_method def self.list_banks(use_cache: true, pay_with_bank_transfer: false)
22
- use_connection(cache_options: use_cache ? {} : nil) do |connection|
23
- connection.get('/bank', pay_with_bank_transfer ? { pay_with_bank_transfer: } : {})
44
+ # Successful response from calling #list_countries.
45
+ class ListCountriesResponse < PaystackGateway::Response; end
46
+
47
+ # Error response from #list_countries.
48
+ class ListCountriesError < ApiError; end
49
+
50
+ # https://paystack.com/docs/api/miscellaneous/#list_countries
51
+ # List Countries: GET /country
52
+ # List all supported countries on Paystack
53
+ #
54
+ #
55
+ # @return [ListCountriesResponse] successful response
56
+ # @raise [ListCountriesError] if the request fails
57
+ api_method def self.list_countries
58
+ use_connection do |connection|
59
+ connection.get(
60
+ '/country',
61
+ )
62
+ end
63
+ end
64
+
65
+ # Successful response from calling #avs.
66
+ class AvsResponse < PaystackGateway::Response; end
67
+
68
+ # Error response from #avs.
69
+ class AvsError < ApiError; end
70
+
71
+ # https://paystack.com/docs/api/miscellaneous/#avs
72
+ # List States (AVS): GET /address_verification/states
73
+ # Get a list of states for a country for address verification
74
+ #
75
+ # @param country [String]
76
+ # The country code of the states to list. It is gotten after the charge request
77
+ #
78
+ # @return [AvsResponse] successful response
79
+ # @raise [AvsError] if the request fails
80
+ api_method def self.avs(country: nil)
81
+ use_connection do |connection|
82
+ connection.get(
83
+ '/address_verification/states',
84
+ { country: }.compact,
85
+ )
24
86
  end
25
87
  end
26
88
  end