k2-connect-ruby 3.1.0 → 4.0.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +31 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile.lock +38 -5
  5. data/README.md +499 -198
  6. data/k2-connect-ruby.gemspec +39 -35
  7. data/lib/k2-connect-ruby/entity.rb +39 -9
  8. data/lib/k2-connect-ruby/http_client.rb +43 -0
  9. data/lib/k2-connect-ruby/k2_entity/k2_entity.rb +12 -11
  10. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/destination_request.rb +27 -0
  11. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_bank_account.rb +32 -0
  12. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_mpesa_wallet.rb +38 -0
  13. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_paybill.rb +31 -0
  14. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_till.rb +30 -0
  15. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/merchant_bank_account.rb +27 -0
  16. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/destination/merchant_mpesa_wallet.rb +27 -0
  17. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/bank_account.rb +17 -0
  18. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/mobile_wallet.rb +24 -0
  19. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/paybill.rb +17 -0
  20. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/recipient_request.rb +32 -0
  21. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/till.rb +17 -0
  22. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient.rb +54 -0
  23. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/k2_stk.rb +14 -31
  24. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/payment_link.rb +53 -0
  25. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/payment_links/payment_link_request.rb +43 -0
  26. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/reversal.rb +39 -0
  27. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/reversals/reversal_request.rb +39 -0
  28. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/send_money/send_money_request.rb +53 -0
  29. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/send_money.rb +73 -0
  30. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/stk_push/stk_push_request.rb +51 -0
  31. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/merchant_bank_account.rb +35 -0
  32. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/merchant_mpesa_wallet.rb +38 -0
  33. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/transfer_account_request.rb +25 -0
  34. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account.rb +49 -0
  35. data/lib/k2-connect-ruby/k2_entity/k2_polling.rb +16 -13
  36. data/lib/k2-connect-ruby/k2_entity/k2_subscribe.rb +16 -14
  37. data/lib/k2-connect-ruby/k2_entity/k2_token.rb +14 -39
  38. data/lib/k2-connect-ruby/k2_entity/polling/polling_request.rb +48 -0
  39. data/lib/k2-connect-ruby/k2_entity/webhook/webhook_subscription_request.rb +66 -0
  40. data/lib/k2-connect-ruby/k2_errors.rb +15 -71
  41. data/lib/k2-connect-ruby/k2_services/base_service.rb +25 -0
  42. data/lib/k2-connect-ruby/k2_services/k2_client.rb +7 -6
  43. data/lib/k2-connect-ruby/k2_services/payloads/daraja_webhooks.rb +43 -0
  44. data/lib/k2-connect-ruby/k2_services/payloads/k2_transaction.rb +20 -18
  45. data/lib/k2-connect-ruby/k2_services/payloads/k2_webhooks.rb +36 -32
  46. data/lib/k2-connect-ruby/k2_services/payloads/transactions/incoming_payment.rb +31 -29
  47. data/lib/k2-connect-ruby/k2_services/payloads/transactions/outgoing_payment.rb +3 -1
  48. data/lib/k2-connect-ruby/k2_services/payloads/transactions/payment_link.rb +38 -0
  49. data/lib/k2-connect-ruby/k2_services/payloads/transactions/reversal.rb +35 -0
  50. data/lib/k2-connect-ruby/k2_services/payloads/transactions/send_money_payment.rb +25 -0
  51. data/lib/k2-connect-ruby/k2_services/payloads/transactions/transfer.rb +2 -0
  52. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/b2b_transaction_received.rb +9 -3
  53. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/b2b_transaction_reversed.rb +22 -0
  54. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_transaction_received.rb +6 -0
  55. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_transaction_reversed.rb +4 -0
  56. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/card_transaction_received.rb +18 -0
  57. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/card_transaction_reversed.rb +17 -0
  58. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/card_transaction_voided.rb +17 -0
  59. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/customer_created.rb +11 -7
  60. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/transfer_webhook.rb +50 -0
  61. data/lib/k2-connect-ruby/k2_services/send_introspect_token_request_service.rb +56 -0
  62. data/lib/k2-connect-ruby/k2_services/send_k2_connect_get_request_service.rb +42 -0
  63. data/lib/k2-connect-ruby/k2_services/send_k2_connect_post_request_service.rb +44 -0
  64. data/lib/k2-connect-ruby/k2_services/send_request_token_request_service.rb +55 -0
  65. data/lib/k2-connect-ruby/k2_services/send_revoke_token_request_service.rb +56 -0
  66. data/lib/k2-connect-ruby/k2_services/send_token_info_request_service.rb +44 -0
  67. data/lib/k2-connect-ruby/k2_services.rb +29 -0
  68. data/lib/k2-connect-ruby/k2_utilities/config/k2_config.rb +18 -26
  69. data/lib/k2-connect-ruby/k2_utilities/config/k2_config.yml +9 -10
  70. data/lib/k2-connect-ruby/k2_utilities/k2_authenticator.rb +12 -5
  71. data/lib/k2-connect-ruby/k2_utilities/k2_connection.rb +0 -49
  72. data/lib/k2-connect-ruby/k2_utilities/k2_connection_helper.rb +21 -0
  73. data/lib/k2-connect-ruby/k2_utilities/k2_process_result.rb +16 -15
  74. data/lib/k2-connect-ruby/k2_utilities/k2_process_webhook.rb +34 -21
  75. data/lib/k2-connect-ruby/k2_utilities/k2_url_parse.rb +3 -1
  76. data/lib/k2-connect-ruby/k2_utilities/phone_number_validator.rb +15 -0
  77. data/lib/k2-connect-ruby/k2_utilities.rb +9 -20
  78. data/lib/k2-connect-ruby/version.rb +1 -1
  79. data/lib/k2-connect-ruby.rb +14 -13
  80. metadata +101 -33
  81. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/k2_pay.rb +0 -98
  82. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/k2_settlement.rb +0 -48
  83. data/lib/k2-connect-ruby/k2_entity/k2_financial_entities/k2_transfer.rb +0 -44
  84. data/lib/k2-connect-ruby/k2_entity/k2_notification.rb +0 -40
  85. data/lib/k2-connect-ruby/k2_services/payload_process.rb +0 -19
  86. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/settlement_webhook.rb +0 -44
  87. data/lib/k2-connect-ruby/k2_utilities/k2_validation.rb +0 -128
@@ -1,54 +1,58 @@
1
- lib = File.expand_path('lib', __dir__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
- require 'k2-connect-ruby/version'
5
+ require "k2-connect-ruby/version"
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = 'k2-connect-ruby'
8
+ spec.name = "k2-connect-ruby"
7
9
  spec.version = K2ConnectRuby::VERSION
8
- spec.authors = ['DavidKar1uk1']
9
- spec.email = ['David.mwangi@kopokopo.com']
10
+ spec.authors = ["DavidKar1uk1"]
11
+ spec.email = ["David.mwangi@kopokopo.com"]
10
12
 
11
- spec.summary = 'Ruby SDK for the Kopo Kopo K2 Connect API.'
12
- spec.description = 'Ruby SDK for the Kopo Kopo K2 Connect API, with webhook subscriptions, STK Push, Pay and Settlement Transfer capabilities. Allows decomposition and break down of results and webhooks returned from the K2 Connect APIx``.'
13
- spec.homepage = 'https://github.com/kopokopo/k2-connect-ruby.git'
14
- spec.license = 'MIT'
15
- spec.required_ruby_version = ['>= 3.3.5', '<= 3.4.7']
13
+ spec.summary = "Ruby SDK for the Kopo Kopo K2 Connect API."
14
+ spec.description = "Ruby SDK for the Kopo Kopo K2 Connect API, with webhook subscriptions, STK Push and Send Money capabilities. Allows decomposition and break down of results and webhooks returned from the K2 Connect API."
15
+ spec.homepage = "https://github.com/kopokopo/k2-connect-ruby.git"
16
+ spec.license = "MIT"
17
+ spec.required_ruby_version = [">= 3.3.5", "<= 3.4.7"]
16
18
 
17
19
 
18
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
20
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
19
21
  # to allow pushing to a single host or delete this section to allow pushing to any host.
20
22
  if spec.respond_to?(:metadata)
21
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
22
24
 
23
- spec.metadata['homepage_uri'] = spec.homepage
24
- spec.metadata['source_code_uri'] = 'https://github.com/kopokopo/k2-connect-ruby.git'
25
- spec.metadata['changelog_uri'] = 'https://github.com/kopokopo/k2-connect-ruby.git/CHANGELOG.MD'
25
+ spec.metadata["homepage_uri"] = spec.homepage
26
+ spec.metadata["source_code_uri"] = "https://github.com/kopokopo/k2-connect-ruby.git"
27
+ spec.metadata["changelog_uri"] = "https://github.com/kopokopo/k2-connect-ruby.git/CHANGELOG.MD"
26
28
  else
27
- raise 'RubyGems 2.0 or newer is required to protect against ' \
28
- 'public gem pushes.'
29
+ raise "RubyGems 2.0 or newer is required to protect against " \
30
+ "public gem pushes."
29
31
  end
30
32
 
31
33
  # Specify which files should be added to the gem when it is released.
32
34
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
33
35
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
34
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
36
+ %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
35
37
  end
36
- spec.bindir = 'exe'
38
+ spec.bindir = "exe"
37
39
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
- spec.require_paths = ['lib']
39
-
40
-
41
- spec.add_dependency 'activesupport', ['>= 7.2.2', '< 8.1.1']
42
- spec.add_dependency 'activemodel', ['>= 7.2.2', '< 8.1.1']
43
- spec.add_dependency 'rest-client', '~> 2.1.0'
44
- spec.add_dependency 'json', '~> 2.8.2'
45
- spec.add_development_dependency 'bundler', '~> 2.5.16'
46
- spec.add_development_dependency "guard", '~> 2.19'
47
- spec.add_development_dependency "guard-rspec", '~> 4.7.3'
48
- spec.add_development_dependency 'rake', '~> 13.2.1'
49
- spec.add_development_dependency 'rspec', '~> 3.13.0'
50
- spec.add_development_dependency "rspec-nc", '~> 0.3.0'
51
- spec.add_development_dependency 'vcr', '~> 6.3.1'
52
- spec.add_development_dependency 'webmock', '~> 3.24'
53
- spec.add_development_dependency 'faker', '~> 3.5.1'
40
+ spec.require_paths = ["lib"]
41
+
42
+
43
+ spec.add_dependency("activemodel", [">= 7.2.2", "<= 8.1.1"])
44
+ spec.add_dependency("activesupport", [">= 7.2.2", "<= 8.1.1"])
45
+ spec.add_dependency("json", "~> 2.8.2")
46
+ spec.add_dependency("rest-client", "~> 2.1.0")
47
+ spec.add_development_dependency("bundler", "~> 4.0.3")
48
+ spec.add_development_dependency("faker", "~> 3.5.1")
49
+ spec.add_development_dependency("guard", "~> 2.19")
50
+ spec.add_development_dependency("guard-rspec", "~> 4.7.3")
51
+ spec.add_development_dependency("rake", "~> 13.2.1")
52
+ spec.add_development_dependency("rspec", "~> 3.13.0")
53
+ spec.add_development_dependency("rspec-nc", "~> 0.3.0")
54
+ spec.add_development_dependency("rubocop", "~> 1.80.1")
55
+ spec.add_development_dependency("rubocop-shopify", "~> 2.17.1")
56
+ spec.add_development_dependency("vcr", "~> 6.3.1")
57
+ spec.add_development_dependency("webmock", "~> 3.24")
54
58
  end
@@ -1,12 +1,42 @@
1
- require 'k2-connect-ruby/k2_entity/k2_entity'
2
- require 'k2-connect-ruby/k2_entity/k2_token'
3
- require 'k2-connect-ruby/k2_entity/k2_polling'
4
- require 'k2-connect-ruby/k2_entity/k2_subscribe'
5
- require 'k2-connect-ruby/k2_entity/k2_notification'
6
- require 'k2-connect-ruby/k2_entity/k2_financial_entities/k2_stk'
7
- require 'k2-connect-ruby/k2_entity/k2_financial_entities/k2_pay'
8
- require 'k2-connect-ruby/k2_entity/k2_financial_entities/k2_transfer'
9
- require 'k2-connect-ruby/k2_entity/k2_financial_entities/k2_settlement'
1
+ require "k2-connect-ruby/k2_entity/k2_entity"
2
+ require "k2-connect-ruby/k2_entity/k2_token"
3
+
4
+ require "k2-connect-ruby/k2_entity/k2_polling"
5
+ require "k2-connect-ruby/k2_entity/polling/polling_request"
6
+
7
+ require "k2-connect-ruby/k2_entity/k2_subscribe"
8
+ require "k2-connect-ruby/k2_entity/webhook/webhook_subscription_request"
9
+
10
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/k2_stk"
11
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/stk_push/stk_push_request"
12
+
13
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient"
14
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/recipient_request"
15
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/till"
16
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/paybill"
17
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/bank_account"
18
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/external_recipient/mobile_wallet"
19
+
20
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/send_money"
21
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/send_money/send_money_request"
22
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/destination_request"
23
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_till"
24
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_paybill"
25
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_bank_account"
26
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/external_mpesa_wallet"
27
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/merchant_bank_account"
28
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/destination/merchant_mpesa_wallet"
29
+
30
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account"
31
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/transfer_account_request"
32
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/merchant_bank_account"
33
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/transfer_account/merchant_mpesa_wallet"
34
+
35
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/reversal"
36
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/reversals/reversal_request"
37
+
38
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/payment_link"
39
+ require "k2-connect-ruby/k2_entity/k2_financial_entities/payment_links/payment_link_request"
10
40
 
11
41
  module K2ConnectRuby
12
42
  module Entity; end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ class HttpClient
5
+ class << self
6
+ def post(url, payload:, headers:)
7
+ request { RestClient.post(url, payload, headers) }
8
+ end
9
+
10
+ def get(url, headers:)
11
+ request { RestClient.get(url, headers) }
12
+ end
13
+
14
+ private
15
+
16
+ def request
17
+ yield
18
+ rescue RestClient::Unauthorized
19
+ raise K2ConnectRuby::K2Errors::UnauthorizedError, "Invalid or expired token"
20
+ rescue RestClient::RequestTimeout
21
+ raise K2ConnectRuby::K2Errors::TimeoutError, "Request timed out"
22
+ rescue RestClient::NotFound
23
+ raise K2ConnectRuby::K2Errors::NotFoundError, "Entity not found"
24
+ rescue Errno::ECONNREFUSED
25
+ raise K2ConnectRuby::K2Errors::ConnectionError, "Connection refused"
26
+ rescue RestClient::Exception => e
27
+ body = parse_body(e)
28
+
29
+ raise K2ConnectRuby::K2Errors::ApiError.new(
30
+ message: body&.dig("error_message") || body&.dig("error_description") || "API error",
31
+ code: e.http_code,
32
+ details: body,
33
+ )
34
+ end
35
+
36
+ def parse_body(exception)
37
+ JSON.parse(exception.response.body)
38
+ rescue StandardError
39
+ nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,31 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Common Class Behaviours for stk, pay and transfers
2
4
  module K2ConnectRuby
3
5
  module K2Entity
4
6
  class K2Entity
5
- attr_accessor :access_token, :the_array
7
+ attr_accessor :access_token
6
8
  attr_reader :k2_response_body, :query_hash, :location_url
7
- include K2ConnectRuby::K2Utilities::K2Validation, K2ConnectRuby::K2Utilities
9
+
10
+ include K2ConnectRuby::K2Utilities
8
11
 
9
12
  # Initialize with access token from Subscriber Class
10
13
  def initialize(access_token)
11
14
  @access_token = access_token
12
- @exception_array = %w[authenticity_token]
13
15
  end
14
16
 
15
17
  # Query/Check the status of a previously initiated request
16
- def query_status(class_type, path_url)
17
- query(class_type, path_url)
18
+ def query_status(endpoint)
19
+ query(endpoint)
18
20
  end
19
21
 
20
22
  # Query Location URL
21
- def query_resource(class_type, url)
22
- query(class_type, url)
23
+ def query_resource(endpoint)
24
+ query(endpoint)
23
25
  end
24
26
 
25
- def query(class_type, path_url)
26
- path_url = validate_url(path_url)
27
- query_hash = make_hash(path_url, 'get', @access_token, class_type, nil)
28
- @k2_response_body = K2ConnectRuby::K2Utilities::K2Connection.make_request(query_hash)
27
+ def query(endpoint)
28
+ result = K2ConnectRuby::K2Services::SendK2ConnectGetRequestService.call(access_token, endpoint)
29
+ @k2_response_body = result.data[:response_body]
29
30
  end
30
31
  end
31
32
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module Destination
7
+ class DestinationRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :type, :nickname, :amount, :description, :favourite
11
+
12
+ validates :type, :amount, presence: true
13
+ validates :favourite, inclusion: { in: [true, false, 'true', 'false', 1, 0, 'T', 'F'],
14
+ message: 'is not a valid boolean' }, if: -> { favourite.present? }
15
+
16
+ def initialize(kwargs)
17
+ kwargs.each do |key, value|
18
+ instance_variable_set("@#{key}", value)
19
+ end
20
+ end
21
+
22
+ def destination_payload; end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for external bank accounts
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class ExternalBankAccount < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :account_name, :account_number, :bank_branch_ref
13
+
14
+ validates :account_name, :account_number, :bank_branch_ref, :description, presence: true
15
+
16
+ def destination_payload
17
+ {
18
+ type: type,
19
+ nickname: nickname,
20
+ account_name: account_name,
21
+ account_number: account_number,
22
+ bank_branch_ref: bank_branch_ref,
23
+ amount: amount,
24
+ description: description,
25
+ favourite: ActiveModel::Type::Boolean.new.cast(favourite)
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for external M-PESA numbers
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class ExternalMpesaWallet < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :phone_number, :network
13
+
14
+ validates :phone_number, :description, presence: true
15
+ validate :phone_number_format
16
+
17
+ def destination_payload
18
+ {
19
+ type: type,
20
+ nickname: nickname,
21
+ phone_number: phone_number,
22
+ network: network,
23
+ amount: amount,
24
+ description: description,
25
+ favourite: ActiveModel::Type::Boolean.new.cast(favourite),
26
+ }
27
+ end
28
+
29
+ def phone_number_format
30
+ unless phone_number&.match?(/^(254\d{9})$/)
31
+ errors.add(:phone_number, "#{phone_number} has an invalid length or format. Must be 254XXXXXXXXX.")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for external paybills
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class ExternalPaybill < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :paybill_number, :paybill_account_number
13
+
14
+ validates :paybill_number, :paybill_account_number, :description, presence: true
15
+
16
+ def destination_payload
17
+ {
18
+ type: type,
19
+ nickname: nickname,
20
+ paybill_number: paybill_number,
21
+ paybill_account_number: paybill_account_number,
22
+ amount: amount,
23
+ description: description,
24
+ favourite: ActiveModel::Type::Boolean.new.cast(favourite)
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for external till
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class ExternalTill < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :till_number
13
+
14
+ validates :till_number, :description, presence: true
15
+
16
+ def destination_payload
17
+ {
18
+ type: type,
19
+ nickname: nickname,
20
+ till_number: till_number,
21
+ amount: amount,
22
+ description: description,
23
+ favourite: ActiveModel::Type::Boolean.new.cast(favourite)
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for my bank account
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class MerchantBankAccount < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :reference
13
+
14
+ validates :reference, presence: true
15
+
16
+ def destination_payload
17
+ {
18
+ type: type,
19
+ reference: reference,
20
+ amount: amount,
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for collecting destination details for my M-PESA phone
4
+
5
+ module K2ConnectRuby
6
+ module K2Entity
7
+ module K2FinancialEntities
8
+ module Destination
9
+ class MerchantMpesaWallet < DestinationRequest
10
+ include ActiveModel::Validations
11
+
12
+ attr_accessor :reference
13
+
14
+ validates :reference, presence: true
15
+
16
+ def destination_payload
17
+ {
18
+ type: type,
19
+ reference: reference,
20
+ amount: amount,
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module ExternalRecipient
7
+ class BankAccount < RecipientRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :account_name, :account_number, :bank_branch_ref
11
+
12
+ validates :account_name, :account_number, :bank_branch_ref, presence: true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module ExternalRecipient
7
+ class MobileWallet < RecipientRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :first_name, :last_name, :phone_number, :email, :network
11
+
12
+ validates :first_name, :last_name, :email, presence: true
13
+ validates :phone_number, presence: true, length: { maximum: 13 }
14
+ validates :email, format: {
15
+ with: URI::MailTo::EMAIL_REGEXP,
16
+ message: "is invalid."
17
+ }
18
+
19
+ validates_with K2ConnectRuby::K2Utilities::PhoneNumberValidator
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module ExternalRecipient
7
+ class Paybill < RecipientRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :paybill_name, :paybill_number, :paybill_account_number
11
+
12
+ validates :paybill_name, :paybill_number, :paybill_account_number, presence: true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module ExternalRecipient
7
+ class RecipientRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :type, :nickname
11
+
12
+ def initialize(kwargs)
13
+ kwargs.each do |key, value|
14
+ instance_variable_set("@#{key}", value)
15
+ end
16
+ end
17
+
18
+ def endpoint
19
+ K2ConnectRuby::K2Utilities::Config::K2Config.endpoint("external_recipient")
20
+ end
21
+
22
+ def request_body
23
+ {
24
+ type: type,
25
+ external_recipient: self.as_json
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module K2ConnectRuby
4
+ module K2Entity
5
+ module K2FinancialEntities
6
+ module ExternalRecipient
7
+ class Till < RecipientRequest
8
+ include ActiveModel::Validations
9
+
10
+ attr_accessor :till_name, :till_number
11
+
12
+ validates :till_name, :till_number, presence: true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Adding external recipients with either mobile_wallets, bank_accounts, till or paybill
4
+ module K2ConnectRuby
5
+ module K2Entity
6
+ class ExternalRecipient < K2ConnectRuby::K2Entity::K2Entity
7
+ attr_accessor :recipients_location_url
8
+
9
+ def add_external_recipient(params)
10
+ params = params.with_indifferent_access
11
+ external_recipient = build_recipient(params)
12
+ raise(ArgumentError, external_recipient.errors.full_messages.first) unless external_recipient.valid?
13
+
14
+ result = K2ConnectRuby::K2Services::SendK2ConnectPostRequestService.call(
15
+ access_token,
16
+ external_recipient.endpoint,
17
+ external_recipient.request_body,
18
+ )
19
+ if result.success?
20
+ @recipients_location_url = result.data[:response_headers][:location]
21
+ else
22
+ raise(result.errors.first)
23
+ end
24
+ end
25
+
26
+ # Query/Check the status of a recently initiated Send money request
27
+ def query_status
28
+ super(recipients_location_url)
29
+ end
30
+
31
+ # Query specific URL
32
+ def query_resource(url)
33
+ super(url)
34
+ end
35
+
36
+ private
37
+
38
+ def build_recipient(params)
39
+ case params[:type]
40
+ when "mobile_wallet"
41
+ K2ConnectRuby::K2Entity::K2FinancialEntities::ExternalRecipient::MobileWallet.new(params)
42
+ when "bank_account"
43
+ K2ConnectRuby::K2Entity::K2FinancialEntities::ExternalRecipient::BankAccount.new(params)
44
+ when "till"
45
+ K2ConnectRuby::K2Entity::K2FinancialEntities::ExternalRecipient::Till.new(params)
46
+ when "paybill"
47
+ K2ConnectRuby::K2Entity::K2FinancialEntities::ExternalRecipient::Paybill.new(params)
48
+ else
49
+ raise(ArgumentError, "Undefined payment method.")
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end