tikkie-api 0.1.0 → 2.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.
- checksums.yaml +5 -5
- data/.rubocop.yml +31 -7
- data/.travis.yml +8 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +39 -33
- data/LICENSE.txt +1 -1
- data/README.md +211 -61
- data/lib/tikkie/api.rb +52 -25
- data/lib/tikkie/api/amount.rb +35 -0
- data/lib/tikkie/api/client.rb +16 -8
- data/lib/tikkie/api/clients/base.rb +16 -0
- data/lib/tikkie/api/clients/payment_requests.rb +25 -0
- data/lib/tikkie/api/clients/payment_requests_subscription.rb +20 -0
- data/lib/tikkie/api/clients/payments.rb +20 -0
- data/lib/tikkie/api/clients/refunds.rb +20 -0
- data/lib/tikkie/api/clients/sandbox_apps.rb +15 -0
- data/lib/tikkie/api/configuration.rb +8 -47
- data/lib/tikkie/api/exception.rb +28 -8
- data/lib/tikkie/api/request.rb +51 -27
- data/lib/tikkie/api/resources/base.rb +66 -0
- data/lib/tikkie/api/{responses → resources}/error.rb +11 -9
- data/lib/tikkie/api/resources/list.rb +52 -0
- data/lib/tikkie/api/resources/payment.rb +68 -0
- data/lib/tikkie/api/resources/payment_request.rb +97 -0
- data/lib/tikkie/api/resources/payment_requests.rb +40 -0
- data/lib/tikkie/api/resources/payment_requests_subscription.rb +24 -0
- data/lib/tikkie/api/resources/payments.rb +48 -0
- data/lib/tikkie/api/resources/refund.rb +71 -0
- data/lib/tikkie/api/resources/sandbox_app.rb +20 -0
- data/lib/tikkie/api/response.rb +64 -0
- data/lib/tikkie/api/v1/access_token.rb +21 -0
- data/lib/tikkie/api/v1/authentication.rb +67 -0
- data/lib/tikkie/api/v1/client.rb +26 -0
- data/lib/tikkie/api/v1/configuration.rb +64 -0
- data/lib/tikkie/api/v1/exception.rb +24 -0
- data/lib/tikkie/api/v1/request.rb +59 -0
- data/lib/tikkie/api/v1/requests/payment_requests.rb +59 -0
- data/lib/tikkie/api/v1/requests/platforms.rb +34 -0
- data/lib/tikkie/api/v1/requests/users.rb +33 -0
- data/lib/tikkie/api/v1/responses/bank_account.rb +24 -0
- data/lib/tikkie/api/v1/responses/base.rb +69 -0
- data/lib/tikkie/api/v1/responses/error.rb +36 -0
- data/lib/tikkie/api/v1/responses/pagination.rb +22 -0
- data/lib/tikkie/api/v1/responses/payment.rb +50 -0
- data/lib/tikkie/api/v1/responses/payment_request.rb +68 -0
- data/lib/tikkie/api/v1/responses/payment_request_created.rb +24 -0
- data/lib/tikkie/api/v1/responses/payment_requests.rb +44 -0
- data/lib/tikkie/api/v1/responses/platform.rb +46 -0
- data/lib/tikkie/api/v1/responses/platforms.rb +34 -0
- data/lib/tikkie/api/v1/responses/user.rb +43 -0
- data/lib/tikkie/api/v1/responses/users.rb +38 -0
- data/lib/tikkie/api/v1/types/payment_request_status.rb +17 -0
- data/lib/tikkie/api/v1/types/payment_status.rb +16 -0
- data/lib/tikkie/api/v1/types/platform_status.rb +14 -0
- data/lib/tikkie/api/v1/types/platform_usage.rb +14 -0
- data/lib/tikkie/api/v1/types/user_status.rb +14 -0
- data/lib/tikkie/api/version.rb +1 -1
- data/lib/tikkie/notification.rb +23 -0
- data/lib/tikkie/notifications/bundle_notification.rb +28 -0
- data/lib/tikkie/notifications/payment_notification.rb +32 -0
- data/lib/tikkie/notifications/refund_notification.rb +36 -0
- data/tikkie-api.gemspec +4 -3
- metadata +69 -44
- data/lib/tikkie/api/access_token.rb +0 -19
- data/lib/tikkie/api/authentication.rb +0 -60
- data/lib/tikkie/api/requests/payment_requests.rb +0 -56
- data/lib/tikkie/api/requests/platforms.rb +0 -32
- data/lib/tikkie/api/requests/users.rb +0 -31
- data/lib/tikkie/api/responses/bank_account.rb +0 -22
- data/lib/tikkie/api/responses/base.rb +0 -53
- data/lib/tikkie/api/responses/pagination.rb +0 -20
- data/lib/tikkie/api/responses/payment.rb +0 -48
- data/lib/tikkie/api/responses/payment_request.rb +0 -64
- data/lib/tikkie/api/responses/payment_request_created.rb +0 -22
- data/lib/tikkie/api/responses/payment_requests.rb +0 -42
- data/lib/tikkie/api/responses/platform.rb +0 -44
- data/lib/tikkie/api/responses/platforms.rb +0 -30
- data/lib/tikkie/api/responses/user.rb +0 -39
- data/lib/tikkie/api/responses/users.rb +0 -34
- data/lib/tikkie/api/types/payment_request_status.rb +0 -15
- data/lib/tikkie/api/types/payment_status.rb +0 -14
- data/lib/tikkie/api/types/platform_status.rb +0 -12
- data/lib/tikkie/api/types/platform_usage.rb +0 -12
- data/lib/tikkie/api/types/user_status.rb +0 -12
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Resources
|
6
|
+
# Resource for a Sandbox App.
|
7
|
+
class SandboxApp < Base
|
8
|
+
def app_token
|
9
|
+
body[:appToken]
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def create_resource(attributes)
|
15
|
+
request.post("sandboxapps", options, attributes)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Tikkie
|
7
|
+
module Api
|
8
|
+
# Parses and wraps the response from the Tikkie API.
|
9
|
+
class Response
|
10
|
+
attr_reader :response, :body
|
11
|
+
|
12
|
+
def initialize(response)
|
13
|
+
@response = response
|
14
|
+
@body = response.body ? parse_body(response.body) : {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def success?
|
18
|
+
http_code == 200 || http_code == 201 || http_code == 204
|
19
|
+
end
|
20
|
+
|
21
|
+
def error?
|
22
|
+
!success?
|
23
|
+
end
|
24
|
+
|
25
|
+
def invalid?
|
26
|
+
body.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def request_uri
|
30
|
+
response.uri
|
31
|
+
end
|
32
|
+
|
33
|
+
def http_code
|
34
|
+
response.code.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def http_message
|
38
|
+
response.message
|
39
|
+
end
|
40
|
+
|
41
|
+
def errors
|
42
|
+
@errors ||= begin
|
43
|
+
errors = []
|
44
|
+
|
45
|
+
if body[:errors]
|
46
|
+
body[:errors].each do |error|
|
47
|
+
errors << Tikkie::Api::Resources::Error.new(error)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
errors
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def parse_body(body)
|
58
|
+
JSON.parse(body, symbolize_names: true)
|
59
|
+
rescue JSON::ParserError
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
# Access token that can be used to make API calls.
|
7
|
+
class AccessToken
|
8
|
+
attr_accessor :token
|
9
|
+
|
10
|
+
def initialize(token, expires_in)
|
11
|
+
@token = token
|
12
|
+
@expires_at = Time.now + expires_in.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def expired?
|
16
|
+
Time.now > @expires_at
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'jwt'
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module Tikkie
|
9
|
+
module Api
|
10
|
+
module V1
|
11
|
+
# Provides authentication for the ABN AMRO OAuth API.
|
12
|
+
# see https://developer.abnamro.com/get-started#authentication
|
13
|
+
class Authentication
|
14
|
+
def initialize(config)
|
15
|
+
@config = config
|
16
|
+
end
|
17
|
+
|
18
|
+
def authenticate
|
19
|
+
uri = URI.parse(File.join(@config.api_url, "/oauth/token"))
|
20
|
+
|
21
|
+
request = Net::HTTP::Post.new(uri)
|
22
|
+
request["Api-Key"] = @config.api_key
|
23
|
+
|
24
|
+
request.set_form_data(
|
25
|
+
client_assertion: jwt_token,
|
26
|
+
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
|
27
|
+
grant_type: "client_credentials",
|
28
|
+
scope: "tikkie"
|
29
|
+
)
|
30
|
+
|
31
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
|
32
|
+
http.request(request)
|
33
|
+
end
|
34
|
+
|
35
|
+
if response.is_a?(Net::HTTPSuccess)
|
36
|
+
json = JSON.parse(response.body, symbolize_names: true)
|
37
|
+
|
38
|
+
Tikkie::Api::V1::AccessToken.new(json[:access_token], json[:expires_in])
|
39
|
+
else
|
40
|
+
raise Tikkie::Api::V1::AuthenticationException, response
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def jwt_token
|
47
|
+
now = Time.now.to_i
|
48
|
+
|
49
|
+
payload = {
|
50
|
+
nbf: now - 120,
|
51
|
+
exp: now + 120, # Token is valid for 2 minutes
|
52
|
+
iss: "Ruby Tikkie client",
|
53
|
+
sub: @config.api_key,
|
54
|
+
aud: @config.oauth_token_url
|
55
|
+
}
|
56
|
+
|
57
|
+
# Send header typ as String, not symbol (JWT version 1.x adds "typ" as String by default).
|
58
|
+
headers = {
|
59
|
+
"typ" => "JWT"
|
60
|
+
}
|
61
|
+
|
62
|
+
JWT.encode(payload, @config.private_data, @config.jwt_hashing_algorithm, headers)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
# Tikkie API client.
|
7
|
+
class Client
|
8
|
+
def initialize(config)
|
9
|
+
@request = Tikkie::Api::V1::Request.new(config)
|
10
|
+
end
|
11
|
+
|
12
|
+
def platforms
|
13
|
+
Tikkie::Api::V1::Requests::Platforms.new(@request)
|
14
|
+
end
|
15
|
+
|
16
|
+
def users
|
17
|
+
Tikkie::Api::V1::Requests::Users.new(@request)
|
18
|
+
end
|
19
|
+
|
20
|
+
def payment_requests
|
21
|
+
Tikkie::Api::V1::Requests::PaymentRequests.new(@request)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
# Tikkie API Configuration. An API Key and private key are mandatory.
|
7
|
+
# see https://developer.abnamro.com/get-started
|
8
|
+
class Configuration
|
9
|
+
SANDBOX_API_URL = "https://api-sandbox.abnamro.com/v1/"
|
10
|
+
PRODUCTION_API_URL = "https://api.abnamro.com/v1/"
|
11
|
+
|
12
|
+
SANDBOX_OAUTH_TOKEN_URL = "https://auth-sandbox.abnamro.com/oauth/token"
|
13
|
+
PRODUCTION_OAUTH_TOKEN_URL = "https://auth.abnamro.com/oauth/token"
|
14
|
+
|
15
|
+
DEFAULT_HASHING_ALGORITHM = "RS256"
|
16
|
+
VALID_HASHING_ALGORITHMS = %w[RS256 RS384 RS512].freeze
|
17
|
+
|
18
|
+
attr_reader :api_key, :private_key, :options
|
19
|
+
|
20
|
+
def initialize(api_key, private_key, options = {})
|
21
|
+
@api_key = api_key
|
22
|
+
@private_key = private_key
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
def private_data
|
27
|
+
unless File.exist?(@private_key)
|
28
|
+
raise Tikkie::Api::V1::Exception, "Private key does not exist: #{@private_key}"
|
29
|
+
end
|
30
|
+
|
31
|
+
OpenSSL::PKey::RSA.new(File.read(@private_key))
|
32
|
+
end
|
33
|
+
|
34
|
+
def jwt_hashing_algorithm
|
35
|
+
if @options[:hashing_algorithm]
|
36
|
+
unless VALID_HASHING_ALGORITHMS.include?(@options[:hashing_algorithm])
|
37
|
+
raise Tikkie::Api::V1::Exception, "Invalid hashing algorithm provided: #{@options[:hashing_algorithm]} (expected: #{VALID_HASHING_ALGORITHMS.join(', ')})"
|
38
|
+
end
|
39
|
+
|
40
|
+
@options[:hashing_algorithm]
|
41
|
+
else
|
42
|
+
DEFAULT_HASHING_ALGORITHM
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def api_url
|
47
|
+
if @options[:test]
|
48
|
+
SANDBOX_API_URL
|
49
|
+
else
|
50
|
+
PRODUCTION_API_URL
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def oauth_token_url
|
55
|
+
if @options[:test]
|
56
|
+
SANDBOX_OAUTH_TOKEN_URL
|
57
|
+
else
|
58
|
+
PRODUCTION_OAUTH_TOKEN_URL
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
# Tikkie base exception.
|
7
|
+
class Exception < RuntimeError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Exception when the authentication fails.
|
11
|
+
class AuthenticationException < Tikkie::Api::V1::Exception
|
12
|
+
attr_reader :response, :body
|
13
|
+
|
14
|
+
def initialize(response)
|
15
|
+
@response = response
|
16
|
+
@body = response.body
|
17
|
+
|
18
|
+
message = "Authentication failure at Tikkie"
|
19
|
+
super(message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Tikkie
|
7
|
+
module Api
|
8
|
+
module V1
|
9
|
+
# Make authenticated HTTP requests to the Tikkie API.
|
10
|
+
class Request
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(path, params = {})
|
16
|
+
uri = URI.parse(File.join(@config.api_url, path))
|
17
|
+
uri.query = URI.encode_www_form(params) unless params.empty?
|
18
|
+
|
19
|
+
request = Net::HTTP::Get.new(uri)
|
20
|
+
request["Api-Key"] = @config.api_key
|
21
|
+
request["Authorization"] = "Bearer #{access_token}"
|
22
|
+
|
23
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
|
24
|
+
http.request(request)
|
25
|
+
end
|
26
|
+
|
27
|
+
response
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(path, params = {})
|
31
|
+
uri = URI.parse(File.join(@config.api_url, path))
|
32
|
+
|
33
|
+
request = Net::HTTP::Post.new(uri)
|
34
|
+
request["Api-Key"] = @config.api_key
|
35
|
+
request["Authorization"] = "Bearer #{access_token}"
|
36
|
+
request["Content-Type"] = "application/json"
|
37
|
+
request.body = params.to_json
|
38
|
+
|
39
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
|
40
|
+
http.request(request)
|
41
|
+
end
|
42
|
+
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def access_token
|
49
|
+
if @access_token.nil? || @access_token.expired?
|
50
|
+
@authentication ||= Tikkie::Api::V1::Authentication.new(@config)
|
51
|
+
@access_token = @authentication.authenticate
|
52
|
+
end
|
53
|
+
|
54
|
+
@access_token.token
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
|
5
|
+
module Tikkie
|
6
|
+
module Api
|
7
|
+
module V1
|
8
|
+
module Requests
|
9
|
+
# Payment requests operations at Tikkie.
|
10
|
+
class PaymentRequests
|
11
|
+
def initialize(request)
|
12
|
+
@request = request
|
13
|
+
end
|
14
|
+
|
15
|
+
def list(platform_token, user_token, options = {})
|
16
|
+
offset = options[:offset] || 0
|
17
|
+
limit = options[:limit] || 20
|
18
|
+
from_date = options[:from_date]
|
19
|
+
to_date = options[:to_date]
|
20
|
+
|
21
|
+
params = { offset: offset, limit: limit }
|
22
|
+
params[:fromDate] = from_date.respond_to?(:utc) ? from_date.utc.iso8601 : from_date if from_date
|
23
|
+
params[:toDate] = to_date.respond_to?(:utc) ? to_date.utc.iso8601 : to_date if to_date
|
24
|
+
|
25
|
+
response = @request.get("/tikkie/platforms/#{platform_token}/users/#{user_token}/paymentrequests", params)
|
26
|
+
Tikkie::Api::V1::Responses::PaymentRequests.new(response, offset: offset, limit: limit)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get(platform_token, user_token, payment_request_token)
|
30
|
+
response = @request.get("/tikkie/platforms/#{platform_token}/users/#{user_token}/paymentrequests/#{payment_request_token}")
|
31
|
+
|
32
|
+
Tikkie::Api::V1::Responses::PaymentRequest.new(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def create(platform_token, user_token, bank_account_token, options = {})
|
36
|
+
params = {
|
37
|
+
currency: options.fetch(:currency),
|
38
|
+
description: options.fetch(:description)
|
39
|
+
}
|
40
|
+
params[:amountInCents] = to_cents(options[:amount]) if options.key?(:amount)
|
41
|
+
params[:externalId] = options[:external_id] if options.key?(:external_id)
|
42
|
+
|
43
|
+
response = @request.post("/tikkie/platforms/#{platform_token}/users/#{user_token}/bankaccounts/#{bank_account_token}/paymentrequests", params)
|
44
|
+
|
45
|
+
Tikkie::Api::V1::Responses::PaymentRequestCreated.new(response)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def to_cents(amount)
|
51
|
+
decimal = BigDecimal(amount.to_s)
|
52
|
+
decimal *= 100 # to cents
|
53
|
+
decimal.to_i
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
module Requests
|
7
|
+
# Platforms operations at Tikkie.
|
8
|
+
class Platforms
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
end
|
12
|
+
|
13
|
+
def list
|
14
|
+
response = @request.get("/tikkie/platforms")
|
15
|
+
Tikkie::Api::V1::Responses::Platforms.new(response)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(options = {})
|
19
|
+
params = {
|
20
|
+
name: options.fetch(:name),
|
21
|
+
phoneNumber: options.fetch(:phone_number),
|
22
|
+
platformUsage: options.fetch(:platform_usage),
|
23
|
+
email: options[:email],
|
24
|
+
notificationUrl: options[:notification_url]
|
25
|
+
}
|
26
|
+
response = @request.post("/tikkie/platforms", params)
|
27
|
+
|
28
|
+
Tikkie::Api::V1::Responses::Platform.new(response)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|