k2-connect-ruby 0.0.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +75 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +7 -0
  6. data/CHANGELOG.md +0 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +4 -0
  9. data/Gemfile.lock +127 -0
  10. data/Guardfile +80 -0
  11. data/LICENSE +21 -0
  12. data/README.md +542 -0
  13. data/Rakefile +8 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/k2-connect-ruby.gemspec +51 -0
  17. data/lib/k2-connect-ruby.rb +34 -0
  18. data/lib/k2-connect-ruby/k2_errors.rb +77 -0
  19. data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_pay.rb +100 -0
  20. data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_settlement.rb +49 -0
  21. data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_stk.rb +48 -0
  22. data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_transfer.rb +45 -0
  23. data/lib/k2-connect-ruby/k2_financial_entity/entity.rb +6 -0
  24. data/lib/k2-connect-ruby/k2_financial_entity/k2_entity.rb +34 -0
  25. data/lib/k2-connect-ruby/k2_financial_entity/k2_subscribe.rb +42 -0
  26. data/lib/k2-connect-ruby/k2_financial_entity/k2_token.rb +37 -0
  27. data/lib/k2-connect-ruby/k2_services/client/k2_client.rb +24 -0
  28. data/lib/k2-connect-ruby/k2_services/payload_process.rb +14 -0
  29. data/lib/k2-connect-ruby/k2_services/payloads/k2_transaction.rb +48 -0
  30. data/lib/k2-connect-ruby/k2_services/payloads/k2_webhooks.rb +59 -0
  31. data/lib/k2-connect-ruby/k2_services/payloads/transactions/incoming_payment.rb +46 -0
  32. data/lib/k2-connect-ruby/k2_services/payloads/transactions/outgoing_payment.rb +15 -0
  33. data/lib/k2-connect-ruby/k2_services/payloads/transactions/transfer.rb +12 -0
  34. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/b2b_received.rb +10 -0
  35. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_received.rb +5 -0
  36. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_reversal.rb +5 -0
  37. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/customer_created.rb +14 -0
  38. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/m2m_transaction.rb +8 -0
  39. data/lib/k2-connect-ruby/k2_services/payloads/webhooks/settlement_webhook.rb +36 -0
  40. data/lib/k2-connect-ruby/k2_utilities/config/k2_config.rb +51 -0
  41. data/lib/k2-connect-ruby/k2_utilities/config/k2_config.yml +14 -0
  42. data/lib/k2-connect-ruby/k2_utilities/k2_authorize.rb +14 -0
  43. data/lib/k2-connect-ruby/k2_utilities/k2_connection.rb +38 -0
  44. data/lib/k2-connect-ruby/k2_utilities/k2_process_result.rb +43 -0
  45. data/lib/k2-connect-ruby/k2_utilities/k2_process_webhook.rb +55 -0
  46. data/lib/k2-connect-ruby/k2_utilities/k2_url_parse.rb +7 -0
  47. data/lib/k2-connect-ruby/k2_utilities/k2_validation.rb +126 -0
  48. data/lib/k2-connect-ruby/k2_utilities/spec_modules/spec_config.rb +41 -0
  49. data/lib/k2-connect-ruby/utilities.rb +19 -0
  50. data/lib/k2-connect-ruby/version.rb +3 -0
  51. metadata +265 -0
@@ -0,0 +1,6 @@
1
+ require 'k2-connect-ruby/k2_financial_entity/k2_token'
2
+ require 'k2-connect-ruby/k2_financial_entity/k2_subscribe'
3
+ require 'k2-connect-ruby/k2_financial_entity/entities/k2_stk'
4
+ require 'k2-connect-ruby/k2_financial_entity/entities/k2_pay'
5
+ require 'k2-connect-ruby/k2_financial_entity/entities/k2_transfer'
6
+ require 'k2-connect-ruby/k2_financial_entity/entities/k2_settlement'
@@ -0,0 +1,34 @@
1
+ # Common Class Behaviours for stk, pay and transfers
2
+ class K2Entity
3
+ attr_accessor :access_token, :the_array
4
+ attr_reader :k2_response_body, :query_hash, :location_url
5
+ include K2Validation, K2Utilities
6
+
7
+ # Initialize with access token from Subscriber Class
8
+ def initialize(access_token)
9
+ @access_token = access_token
10
+ @threads = []
11
+ @exception_array = %w[authenticity_token]
12
+ end
13
+
14
+ # Query/Check the status of a previously initiated request
15
+ def query_status(class_type, path_url)
16
+ query(class_type, path_url)
17
+ end
18
+
19
+ # Query Location URL
20
+ def query_resource(class_type, url)
21
+ query(class_type, url)
22
+ end
23
+
24
+ def query(class_type, path_url)
25
+ # TODO: Add back the validation to ensure only https location urls are returned
26
+ # path_url = validate_url(@location_url)
27
+ query_hash = make_hash(path_url, 'get', @access_token, class_type, nil)
28
+ @threads << Thread.new do
29
+ sleep 0.25
30
+ @k2_response_body = K2Connect.make_request(query_hash)
31
+ end
32
+ @threads.each(&:join)
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ # Class for Subscription Service
2
+ class K2Subscribe
3
+ include K2Validation, K2Utilities
4
+ attr_reader :location_url, :k2_response_body
5
+ attr_accessor :access_token, :webhook_secret
6
+
7
+ # Initialize with the event_type
8
+ def initialize(access_token)
9
+ raise ArgumentError, 'Nil or Empty Access Token Given!' if access_token.blank?
10
+ @threads = []
11
+ @access_token = access_token
12
+ end
13
+
14
+ # Implemented a Case condition that minimises repetition
15
+ def webhook_subscribe(params)
16
+ params = validate_webhook_input(params)
17
+ validate_webhook(params)
18
+ k2_request_body = {
19
+ event_type: params[:event_type],
20
+ url: params[:url],
21
+ scope: params[:scope],
22
+ scope_reference: params[:scope_reference]
23
+ }
24
+ subscribe_hash = make_hash(K2Config.path_url('webhook_subscriptions'), 'post', @access_token,'Subscription', k2_request_body)
25
+ @location_url = K2Connect.make_request(subscribe_hash)
26
+ end
27
+
28
+ # Query Recent Webhook
29
+ def query_webhook(location_url = @location_url)
30
+ query_hash = make_hash(location_url, 'get', @access_token, 'Subscription', nil)
31
+ @threads << Thread.new do
32
+ sleep 0.25
33
+ @k2_response_body = K2Connect.make_request(query_hash)
34
+ end
35
+ @threads.each(&:join)
36
+ end
37
+
38
+ # Query Specific Webhook URL
39
+ def query_resource_url(url)
40
+ query_webhook(url)
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ # Class for Gaining Access Token
2
+ class K2AccessToken
3
+ attr_reader :access_token
4
+
5
+ def initialize(client_id, client_secret)
6
+ validate_client_credentials(client_id, client_secret)
7
+ @client_id = client_id
8
+ @client_secret = client_secret
9
+ end
10
+
11
+ # Method for sending the request to K2 sandbox or Mock Server (Receives the access_token)
12
+ def request_token
13
+ token_params = {
14
+ client_id: @client_id,
15
+ client_secret: @client_secret,
16
+ grant_type: 'client_credentials'
17
+ }
18
+ token_hash = K2AccessToken.make_hash(K2Config.path_url('oauth_token'), 'post', 'Access Token', token_params)
19
+ @access_token = K2Connect.make_request(token_hash)
20
+ end
21
+
22
+ def validate_client_credentials(client_id, client_secret)
23
+ raise ArgumentError, 'Nil or Empty Client Id or Secret!' if client_id.blank? || client_secret.blank?
24
+ end
25
+
26
+ class << self
27
+ # Create a Hash containing important details accessible for K2Connect
28
+ def make_hash(path_url, request, class_type, body)
29
+ {
30
+ path_url: path_url,
31
+ request_type: request,
32
+ class_type: class_type,
33
+ params: body
34
+ }.with_indifferent_access
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ # TODO: Uncomment the checking of the request scheme
2
+ class K2Client
3
+ attr_accessor :api_secret_key,
4
+ :hash_body,
5
+ :k2_signature
6
+
7
+ # Initialize method
8
+ def initialize(api_secret_key)
9
+ raise ArgumentError, 'No Secret Key Given!' if api_secret_key.blank?
10
+ @api_secret_key = api_secret_key
11
+ end
12
+
13
+ # Method for parsing the Entire Request. Come back to it later to trim. L8r call it set_client_variables
14
+ def parse_request(the_request)
15
+ raise ArgumentError, 'Nil Request Parameter Input!' if the_request.blank?
16
+
17
+ # The Response Body.
18
+ @hash_body = Yajl::Parser.parse(the_request.body.read.as_json)
19
+ # The Response Header
20
+ hash_header = Yajl::Parser.parse(the_request.env.select { |k, _| k =~ /^HTTP_/ }.to_json)
21
+ # The K2 Signature
22
+ @k2_signature = hash_header['HTTP_X_KOPOKOPO_SIGNATURE']
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ require 'k2-connect-ruby/k2_services/client/k2_client'
2
+
3
+ require 'k2-connect-ruby/k2_services/payloads/k2_webhooks'
4
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/b2b_received'
5
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/m2m_transaction'
6
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/customer_created'
7
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/buygoods_received'
8
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/buygoods_reversal'
9
+ require 'k2-connect-ruby/k2_services/payloads/webhooks/settlement_webhook'
10
+
11
+ require 'k2-connect-ruby/k2_services/payloads/k2_transaction'
12
+ require 'k2-connect-ruby/k2_services/payloads/transactions/transfer'
13
+ require 'k2-connect-ruby/k2_services/payloads/transactions/incoming_payment'
14
+ require 'k2-connect-ruby/k2_services/payloads/transactions/outgoing_payment'
@@ -0,0 +1,48 @@
1
+ class K2Transaction
2
+ attr_reader :id,
3
+ :type,
4
+ :metadata,
5
+ :links_self,
6
+ :callback_url
7
+
8
+ def initialize(payload)
9
+ @id = payload.dig('data', 'id')
10
+ @type = payload.dig('data', 'type')
11
+ @metadata = payload.dig('data', 'attributes', 'metadata')
12
+ @links_self = payload.dig('data', 'attributes', '_links', 'self')
13
+ @callback_url = payload.dig('data', 'attributes', '_links', 'callback_url')
14
+ end
15
+ end
16
+
17
+ class CommonPayment < K2Transaction
18
+ include ActiveModel::Validations
19
+
20
+ attr_reader :status,
21
+ :initiation_time
22
+
23
+ validate :valid_payment_type
24
+
25
+ def initialize(payload)
26
+ super
27
+ @status = payload.dig('data', 'attributes', 'status')
28
+ @initiation_time = payload.dig('data', 'attributes', 'initiation_time') if @type.eql?('incoming_payment')
29
+ end
30
+
31
+ private
32
+
33
+ def valid_payment_type; end
34
+ end
35
+
36
+ class OutgoingTransaction < CommonPayment
37
+ attr_reader :created_at,
38
+ :transfer_batches,
39
+ :total_value
40
+
41
+ def initialize(payload)
42
+ super
43
+ @created_at = payload.dig('data', 'attributes', 'created_at')
44
+ @currency = payload.dig('data', 'attributes', 'amount', 'currency')
45
+ @total_value = payload.dig('data', 'attributes', 'amount', 'value')
46
+ @transfer_batches = payload.dig('data', 'attributes', 'transfer_batches')
47
+ end
48
+ end
@@ -0,0 +1,59 @@
1
+ class Webhook
2
+ attr_reader :id,
3
+ :topic,
4
+ :created_at,
5
+ :links_self,
6
+ :event_type,
7
+ :links_resource,
8
+ :event_resource,
9
+ :resource_id
10
+
11
+ def initialize(payload)
12
+ @id = payload.dig('id')
13
+ @topic = payload.dig('topic')
14
+ @created_at = payload.dig('created_at')
15
+ # Event
16
+ @event_type = payload.dig('event', 'type')
17
+ @resource_id = payload.dig('event', 'resource', 'id') unless @event_type.eql?('Customer Created')
18
+ # Links
19
+ @links_self = payload.dig('_links', 'self')
20
+ @links_resource = payload.dig('_links', 'resource')
21
+ end
22
+ end
23
+
24
+ class K2CommonEvents < Webhook
25
+ REFERENCE_EXCEPTIONS = ["Merchant to Merchant Transaction", "Settlement Transfer"]
26
+
27
+ attr_reader :reference,
28
+ :origination_time,
29
+ :amount,
30
+ :currency,
31
+ :status
32
+
33
+ def initialize(payload)
34
+ super
35
+ @reference = payload.dig('event', 'resource', 'reference') unless REFERENCE_EXCEPTIONS.include?(@event_type)
36
+ @origination_time = payload.dig('event', 'resource', 'origination_time')
37
+ @amount = payload.dig('event', 'resource', 'amount')
38
+ @currency = payload.dig('event', 'resource', 'currency')
39
+ @status = payload.dig('event', 'resource', 'status')
40
+ end
41
+
42
+ end
43
+
44
+ class Buygoods < K2CommonEvents
45
+ attr_reader :system,
46
+ :till_number,
47
+ :sender_phone_number,
48
+ :sender_first_name,
49
+ :sender_last_name
50
+
51
+ def initialize(payload)
52
+ super
53
+ @system = payload.dig('event', 'resource', 'system')
54
+ @till_number = payload.dig('event', 'resource', 'till_number')
55
+ @sender_phone_number = payload.dig('event', 'resource', 'sender_phone_number')
56
+ @sender_first_name = payload.dig('event', 'resource', 'sender_first_name')
57
+ @sender_last_name = payload.dig('event', 'resource', 'sender_last_name')
58
+ end
59
+ end
@@ -0,0 +1,46 @@
1
+ class IncomingPayments < CommonPayment
2
+ attr_reader :event,
3
+ :event_type,
4
+ :transaction_reference,
5
+ :origination_time,
6
+ :sender_phone_number,
7
+ :amount,
8
+ :currency,
9
+ :till_number,
10
+ :system,
11
+ :resource_id,
12
+ :resource_status,
13
+ :sender_first_name,
14
+ :sender_middle_name,
15
+ :sender_last_name,
16
+ :errors
17
+
18
+ def initialize(payload)
19
+ super
20
+ # Event details
21
+ @event = payload.dig('data', 'attributes', 'event')
22
+ @event_type = payload.dig('data', 'attributes', 'event', 'type')
23
+ # Resource details
24
+ @resource_id = payload.dig('data', 'attributes', 'event', 'resource', 'id')
25
+ @transaction_reference = payload.dig('data', 'attributes', 'event', 'resource', 'reference')
26
+ @origination_time = payload.dig('data', 'attributes', 'event', 'resource', 'origination_time')
27
+ @sender_phone_number = payload.dig('data', 'attributes', 'event', 'resource', 'sender_phone_number')
28
+ @amount = payload.dig('data', 'attributes', 'event', 'resource', 'amount')
29
+ @currency = payload.dig('data', 'attributes', 'event', 'resource', 'currency')
30
+ @till_number = payload.dig('data', 'attributes', 'event', 'resource', 'till_number')
31
+ @system = payload.dig('data', 'attributes', 'event', 'resource', 'system')
32
+ @resource_status = payload.dig('data', 'attributes', 'event', 'resource', 'status')
33
+ @sender_first_name = payload.dig('data', 'attributes', 'event', 'resource', 'sender_first_name')
34
+ @sender_middle_name = payload.dig('data', 'attributes', 'event', 'resource', 'sender_middle_name')
35
+ @sender_last_name = payload.dig('data', 'attributes', 'event', 'resource', 'sender_last_name')
36
+ # Errors
37
+ @errors = payload.dig('data', 'attributes', 'event', 'errors')
38
+ end
39
+
40
+ private
41
+
42
+ def valid_payment_type
43
+ raise ArgumentError, "Wrong Payment Type" unless @type.eql?("incoming_payment")
44
+ end
45
+
46
+ end
@@ -0,0 +1,15 @@
1
+ class OutgoingPayment < OutgoingTransaction
2
+ attr_reader :transaction_reference,
3
+ :destination
4
+
5
+ def initialize(payload)
6
+ super
7
+ end
8
+
9
+ private
10
+
11
+ def valid_payment_type
12
+ raise ArgumentError, "Wrong Payment Type" unless @type.eql?("payment")
13
+ end
14
+
15
+ end
@@ -0,0 +1,12 @@
1
+ class Transfer < OutgoingTransaction
2
+
3
+ def initialize(payload)
4
+ super
5
+ end
6
+
7
+ private
8
+
9
+ def valid_payment_type
10
+ raise ArgumentError, "Wrong Payment Type" unless @type.eql?("settlement_transfer")
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ class B2b < K2CommonEvents
2
+ attr_reader :sending_till,
3
+ :till_number
4
+
5
+ def initialize(payload)
6
+ super
7
+ @till_number = payload.dig('event', 'resource', 'till_number')
8
+ @sending_till = payload.dig('event', 'resource', 'sending_till')
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class BuygoodsTransactionReceived < Buygoods
2
+ def initialize(payload)
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class BuygoodsTransactionReversed < Buygoods
2
+ def initialize(payload)
3
+ super
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ class CustomerCreated < Webhook
2
+ attr_reader :resource_first_name,
3
+ :resource_middle_name,
4
+ :resource_last_name,
5
+ :resource_phone_number
6
+
7
+ def initialize(payload)
8
+ super
9
+ @resource_first_name = payload.dig('event', 'resource', 'first_name')
10
+ @resource_middle_name = payload.dig('event', 'resource', 'middle_name')
11
+ @resource_last_name = payload.dig('event', 'resource', 'last_name')
12
+ @resource_phone_number = payload.dig('event', 'resource', 'phone_number')
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ class MerchantToMerchant < K2CommonEvents
2
+ attr_reader :resource_sending_merchant
3
+
4
+ def initialize(payload)
5
+ super
6
+ @resource_sending_merchant = payload.dig('event', 'resource', 'sending_merchant')
7
+ end
8
+ end
@@ -0,0 +1,36 @@
1
+ class SettlementWebhook < K2CommonEvents
2
+ attr_reader :disbursements,
3
+ :destination_type,
4
+ :destination_network,
5
+ :destination_reference,
6
+ :destination_last_name,
7
+ :destination_first_name,
8
+ :destination_account_name,
9
+ :destination_phone_number,
10
+ :destination_account_number,
11
+ :destination_bank_branch_ref,
12
+ :destination_settlement_method
13
+
14
+ def initialize(payload)
15
+ super
16
+ # Destination
17
+ @disbursements = payload.dig('event', 'resource', 'disbursements')
18
+ @destination_type = payload.dig('event', 'resource', 'destination', 'type')
19
+ @destination_reference = payload.dig('event', 'resource', 'destination', 'resource', 'reference')
20
+ destination_assets(payload)
21
+ end
22
+
23
+ def destination_assets(payload)
24
+ if @destination_type.eql?('Mobile Wallet')
25
+ @destination_network = payload.dig('event', 'resource', 'destination', 'resource', 'network')
26
+ @destination_last_name = payload.dig('event', 'resource', 'destination', 'resource', 'last_name')
27
+ @destination_first_name = payload.dig('event', 'resource', 'destination', 'resource', 'first_name')
28
+ @destination_phone_number = payload.dig('event', 'resource', 'destination', 'resource', 'phone_number')
29
+ elsif @destination_type.eql?('Bank Account')
30
+ @destination_account_name = payload.dig('event', 'resource', 'destination', 'resource', 'account_name')
31
+ @destination_account_number = payload.dig('event', 'resource', 'destination', 'resource', 'account_number')
32
+ @destination_bank_branch_ref = payload.dig('event', 'resource', 'destination', 'resource', 'bank_branch_ref')
33
+ @destination_settlement_method = payload.dig('event', 'resource', 'destination', 'resource', 'settlement_method')
34
+ end
35
+ end
36
+ end