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.
- checksums.yaml +7 -0
- data/.gitignore +75 -0
- data/.gitmodules +6 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +0 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +127 -0
- data/Guardfile +80 -0
- data/LICENSE +21 -0
- data/README.md +542 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/k2-connect-ruby.gemspec +51 -0
- data/lib/k2-connect-ruby.rb +34 -0
- data/lib/k2-connect-ruby/k2_errors.rb +77 -0
- data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_pay.rb +100 -0
- data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_settlement.rb +49 -0
- data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_stk.rb +48 -0
- data/lib/k2-connect-ruby/k2_financial_entity/entities/k2_transfer.rb +45 -0
- data/lib/k2-connect-ruby/k2_financial_entity/entity.rb +6 -0
- data/lib/k2-connect-ruby/k2_financial_entity/k2_entity.rb +34 -0
- data/lib/k2-connect-ruby/k2_financial_entity/k2_subscribe.rb +42 -0
- data/lib/k2-connect-ruby/k2_financial_entity/k2_token.rb +37 -0
- data/lib/k2-connect-ruby/k2_services/client/k2_client.rb +24 -0
- data/lib/k2-connect-ruby/k2_services/payload_process.rb +14 -0
- data/lib/k2-connect-ruby/k2_services/payloads/k2_transaction.rb +48 -0
- data/lib/k2-connect-ruby/k2_services/payloads/k2_webhooks.rb +59 -0
- data/lib/k2-connect-ruby/k2_services/payloads/transactions/incoming_payment.rb +46 -0
- data/lib/k2-connect-ruby/k2_services/payloads/transactions/outgoing_payment.rb +15 -0
- data/lib/k2-connect-ruby/k2_services/payloads/transactions/transfer.rb +12 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/b2b_received.rb +10 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_received.rb +5 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/buygoods_reversal.rb +5 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/customer_created.rb +14 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/m2m_transaction.rb +8 -0
- data/lib/k2-connect-ruby/k2_services/payloads/webhooks/settlement_webhook.rb +36 -0
- data/lib/k2-connect-ruby/k2_utilities/config/k2_config.rb +51 -0
- data/lib/k2-connect-ruby/k2_utilities/config/k2_config.yml +14 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_authorize.rb +14 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_connection.rb +38 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_process_result.rb +43 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_process_webhook.rb +55 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_url_parse.rb +7 -0
- data/lib/k2-connect-ruby/k2_utilities/k2_validation.rb +126 -0
- data/lib/k2-connect-ruby/k2_utilities/spec_modules/spec_config.rb +41 -0
- data/lib/k2-connect-ruby/utilities.rb +19 -0
- data/lib/k2-connect-ruby/version.rb +3 -0
- 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,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,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
|