tikkie-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +36 -0
- data/.travis.yml +7 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/Rakefile +10 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/tikkie/api.rb +32 -0
- data/lib/tikkie/api/access_token.rb +19 -0
- data/lib/tikkie/api/authentication.rb +60 -0
- data/lib/tikkie/api/client.rb +24 -0
- data/lib/tikkie/api/configuration.rb +62 -0
- data/lib/tikkie/api/exception.rb +22 -0
- data/lib/tikkie/api/request.rb +57 -0
- data/lib/tikkie/api/requests/payment_requests.rb +56 -0
- data/lib/tikkie/api/requests/platforms.rb +32 -0
- data/lib/tikkie/api/requests/users.rb +31 -0
- data/lib/tikkie/api/responses/bank_account.rb +22 -0
- data/lib/tikkie/api/responses/base.rb +53 -0
- data/lib/tikkie/api/responses/error.rb +34 -0
- data/lib/tikkie/api/responses/pagination.rb +20 -0
- data/lib/tikkie/api/responses/payment.rb +48 -0
- data/lib/tikkie/api/responses/payment_request.rb +64 -0
- data/lib/tikkie/api/responses/payment_request_created.rb +22 -0
- data/lib/tikkie/api/responses/payment_requests.rb +42 -0
- data/lib/tikkie/api/responses/platform.rb +44 -0
- data/lib/tikkie/api/responses/platforms.rb +30 -0
- data/lib/tikkie/api/responses/user.rb +39 -0
- data/lib/tikkie/api/responses/users.rb +34 -0
- data/lib/tikkie/api/types/payment_request_status.rb +15 -0
- data/lib/tikkie/api/types/payment_status.rb +14 -0
- data/lib/tikkie/api/types/platform_status.rb +12 -0
- data/lib/tikkie/api/types/platform_usage.rb +12 -0
- data/lib/tikkie/api/types/user_status.rb +12 -0
- data/lib/tikkie/api/version.rb +7 -0
- data/tikkie-api.gemspec +31 -0
- metadata +168 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
# Tikkie API client.
|
6
|
+
class Client
|
7
|
+
def initialize(config)
|
8
|
+
@request = Tikkie::Api::Request.new(config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def platforms
|
12
|
+
Tikkie::Api::Requests::Platforms.new(@request)
|
13
|
+
end
|
14
|
+
|
15
|
+
def users
|
16
|
+
Tikkie::Api::Requests::Users.new(@request)
|
17
|
+
end
|
18
|
+
|
19
|
+
def payment_requests
|
20
|
+
Tikkie::Api::Requests::PaymentRequests.new(@request)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
# Tikkie API Configuration. An API Key and private key are mandatory.
|
6
|
+
# see https://developer.abnamro.com/get-started
|
7
|
+
class Configuration
|
8
|
+
SANDBOX_API_URL = "https://api-sandbox.abnamro.com/v1/"
|
9
|
+
PRODUCTION_API_URL = "https://api.abnamro.com/v1/"
|
10
|
+
|
11
|
+
SANDBOX_OAUTH_TOKEN_URL = "https://auth-sandbox.abnamro.com/oauth/token"
|
12
|
+
PRODUCTION_OAUTH_TOKEN_URL = "https://auth.abnamro.com/oauth/token"
|
13
|
+
|
14
|
+
DEFAULT_HASHING_ALGORITHM = "RS256"
|
15
|
+
VALID_HASHING_ALGORITHMS = %w[RS256 RS384 RS512].freeze
|
16
|
+
|
17
|
+
attr_reader :api_key, :private_key, :options
|
18
|
+
|
19
|
+
def initialize(api_key, private_key, options = {})
|
20
|
+
@api_key = api_key
|
21
|
+
@private_key = private_key
|
22
|
+
@options = options
|
23
|
+
end
|
24
|
+
|
25
|
+
def private_data
|
26
|
+
unless File.exist?(@private_key)
|
27
|
+
raise Tikkie::Api::Exception, "Private key does not exist: #{@private_key}"
|
28
|
+
end
|
29
|
+
|
30
|
+
OpenSSL::PKey::RSA.new(File.read(@private_key))
|
31
|
+
end
|
32
|
+
|
33
|
+
def jwt_hashing_algorithm
|
34
|
+
if @options[:hashing_algorithm]
|
35
|
+
unless VALID_HASHING_ALGORITHMS.include?(@options[:hashing_algorithm])
|
36
|
+
raise Tikkie::Api::Exception, "Invalid hashing algorithm provided: #{@options[:hashing_algorithm]} (expected: #{VALID_HASHING_ALGORITHMS.join(', ')})"
|
37
|
+
end
|
38
|
+
|
39
|
+
@options[:hashing_algorithm]
|
40
|
+
else
|
41
|
+
DEFAULT_HASHING_ALGORITHM
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def api_url
|
46
|
+
if @options[:test]
|
47
|
+
SANDBOX_API_URL
|
48
|
+
else
|
49
|
+
PRODUCTION_API_URL
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def oauth_token_url
|
54
|
+
if @options[:test]
|
55
|
+
SANDBOX_OAUTH_TOKEN_URL
|
56
|
+
else
|
57
|
+
PRODUCTION_OAUTH_TOKEN_URL
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
# Tikkie base exception.
|
6
|
+
class Exception < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Exception when the authentication fails.
|
10
|
+
class AuthenticationException < Tikkie::Api::Exception
|
11
|
+
attr_reader :response, :body
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
15
|
+
@body = response.body
|
16
|
+
|
17
|
+
message = "Authentication failure at Tikkie"
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Tikkie
|
7
|
+
module Api
|
8
|
+
# Make authenticated HTTP requests to the Tikkie API.
|
9
|
+
class Request
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(path, params = {})
|
15
|
+
uri = URI.parse(File.join(@config.api_url, path))
|
16
|
+
uri.query = URI.encode_www_form(params) unless params.empty?
|
17
|
+
|
18
|
+
request = Net::HTTP::Get.new(uri)
|
19
|
+
request["Api-Key"] = @config.api_key
|
20
|
+
request["Authorization"] = "Bearer #{access_token}"
|
21
|
+
|
22
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
|
23
|
+
http.request(request)
|
24
|
+
end
|
25
|
+
|
26
|
+
response
|
27
|
+
end
|
28
|
+
|
29
|
+
def post(path, params = {})
|
30
|
+
uri = URI.parse(File.join(@config.api_url, path))
|
31
|
+
|
32
|
+
request = Net::HTTP::Post.new(uri)
|
33
|
+
request["Api-Key"] = @config.api_key
|
34
|
+
request["Authorization"] = "Bearer #{access_token}"
|
35
|
+
request["Content-Type"] = "application/json"
|
36
|
+
request.body = params.to_json
|
37
|
+
|
38
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
|
39
|
+
http.request(request)
|
40
|
+
end
|
41
|
+
|
42
|
+
response
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def access_token
|
48
|
+
if @access_token.nil? || @access_token.expired?
|
49
|
+
@authentication ||= Tikkie::Api::Authentication.new(@config)
|
50
|
+
@access_token = @authentication.authenticate
|
51
|
+
end
|
52
|
+
|
53
|
+
@access_token.token
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
|
5
|
+
module Tikkie
|
6
|
+
module Api
|
7
|
+
module Requests
|
8
|
+
# Payment requests operations at Tikkie.
|
9
|
+
class PaymentRequests
|
10
|
+
def initialize(request)
|
11
|
+
@request = request
|
12
|
+
end
|
13
|
+
|
14
|
+
def list(platform_token, user_token, options = {})
|
15
|
+
offset = options[:offset] || 0
|
16
|
+
limit = options[:limit] || 20
|
17
|
+
from_date = options[:from_date]
|
18
|
+
to_date = options[:to_date]
|
19
|
+
|
20
|
+
params = { offset: offset, limit: limit }
|
21
|
+
params[:fromDate] = from_date.respond_to?(:utc) ? from_date.utc.iso8601 : from_date if from_date
|
22
|
+
params[:toDate] = to_date.respond_to?(:utc) ? to_date.utc.iso8601 : to_date if to_date
|
23
|
+
|
24
|
+
response = @request.get("/tikkie/platforms/#{platform_token}/users/#{user_token}/paymentrequests", params)
|
25
|
+
Tikkie::Api::Responses::PaymentRequests.new(response, offset: offset, limit: limit)
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(platform_token, user_token, payment_request_token)
|
29
|
+
response = @request.get("/tikkie/platforms/#{platform_token}/users/#{user_token}/paymentrequests/#{payment_request_token}")
|
30
|
+
|
31
|
+
Tikkie::Api::Responses::PaymentRequest.new(response)
|
32
|
+
end
|
33
|
+
|
34
|
+
def create(platform_token, user_token, bank_account_token, options = {})
|
35
|
+
params = {
|
36
|
+
amountInCents: to_cents(options.fetch(:amount)),
|
37
|
+
currency: options.fetch(:currency),
|
38
|
+
description: options.fetch(:description),
|
39
|
+
externalId: options[:external_id]
|
40
|
+
}
|
41
|
+
response = @request.post("/tikkie/platforms/#{platform_token}/users/#{user_token}/bankaccounts/#{bank_account_token}/paymentrequests", params)
|
42
|
+
|
43
|
+
Tikkie::Api::Responses::PaymentRequestCreated.new(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def to_cents(amount)
|
49
|
+
decimal = BigDecimal.new(amount.to_s)
|
50
|
+
decimal *= 100 # to cents
|
51
|
+
decimal.to_i
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Requests
|
6
|
+
# Platforms operations at Tikkie.
|
7
|
+
class Platforms
|
8
|
+
def initialize(request)
|
9
|
+
@request = request
|
10
|
+
end
|
11
|
+
|
12
|
+
def list
|
13
|
+
response = @request.get("/tikkie/platforms")
|
14
|
+
Tikkie::Api::Responses::Platforms.new(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(options = {})
|
18
|
+
params = {
|
19
|
+
name: options.fetch(:name),
|
20
|
+
phoneNumber: options.fetch(:phone_number),
|
21
|
+
platformUsage: options.fetch(:platform_usage),
|
22
|
+
email: options[:email],
|
23
|
+
notificationUrl: options[:notification_url]
|
24
|
+
}
|
25
|
+
response = @request.post("/tikkie/platforms", params)
|
26
|
+
|
27
|
+
Tikkie::Api::Responses::Platform.new(response)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Requests
|
6
|
+
# Users operations at Tikkie.
|
7
|
+
class Users
|
8
|
+
def initialize(request)
|
9
|
+
@request = request
|
10
|
+
end
|
11
|
+
|
12
|
+
def list(platform_token)
|
13
|
+
response = @request.get("/tikkie/platforms/#{platform_token}/users")
|
14
|
+
Tikkie::Api::Responses::Users.new(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(platform_token, options = {})
|
18
|
+
params = {
|
19
|
+
name: options.fetch(:name),
|
20
|
+
phoneNumber: options.fetch(:phone_number),
|
21
|
+
iban: options.fetch(:iban),
|
22
|
+
bankAccountLabel: options.fetch(:bank_account_label)
|
23
|
+
}
|
24
|
+
response = @request.post("/tikkie/platforms/#{platform_token}/users", params)
|
25
|
+
|
26
|
+
Tikkie::Api::Responses::User.new(response)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Responses
|
6
|
+
# Bank account of a user.
|
7
|
+
class BankAccount < Base
|
8
|
+
def bank_account_token
|
9
|
+
data[:bankAccountToken]
|
10
|
+
end
|
11
|
+
|
12
|
+
def bank_account_label
|
13
|
+
data[:bankAccountLabel]
|
14
|
+
end
|
15
|
+
|
16
|
+
def iban
|
17
|
+
data[:iban]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Tikkie
|
6
|
+
module Api
|
7
|
+
module Responses
|
8
|
+
# Base class for all responses.
|
9
|
+
class Base
|
10
|
+
attr_reader :response, :data
|
11
|
+
|
12
|
+
def initialize(response)
|
13
|
+
if response.respond_to?(:body)
|
14
|
+
@response = response
|
15
|
+
@data = JSON.parse(response.body, symbolize_names: true)
|
16
|
+
else
|
17
|
+
@data = response
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def response_code
|
22
|
+
response.code.to_i if response
|
23
|
+
end
|
24
|
+
|
25
|
+
def success?
|
26
|
+
response_code == 200 || response_code == 201
|
27
|
+
end
|
28
|
+
|
29
|
+
def error?
|
30
|
+
!success?
|
31
|
+
end
|
32
|
+
|
33
|
+
def trace_id
|
34
|
+
response["Trace-Id"] if response
|
35
|
+
end
|
36
|
+
|
37
|
+
def errors
|
38
|
+
@errors ||= begin
|
39
|
+
errors = []
|
40
|
+
|
41
|
+
if data[:errors]
|
42
|
+
data[:errors].each do |error|
|
43
|
+
errors << Tikkie::Api::Responses::Error.new(error)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
errors
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Responses
|
6
|
+
# Error response from Tikkie.
|
7
|
+
class Error < Base
|
8
|
+
def code
|
9
|
+
data[:code]
|
10
|
+
end
|
11
|
+
|
12
|
+
def message
|
13
|
+
data[:message]
|
14
|
+
end
|
15
|
+
|
16
|
+
def reference
|
17
|
+
data[:reference]
|
18
|
+
end
|
19
|
+
|
20
|
+
def trace_id
|
21
|
+
data[:traceId]
|
22
|
+
end
|
23
|
+
|
24
|
+
def status
|
25
|
+
data[:status]
|
26
|
+
end
|
27
|
+
|
28
|
+
def category
|
29
|
+
data[:category]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tikkie
|
4
|
+
module Api
|
5
|
+
module Responses
|
6
|
+
# Helper for paginated responses.
|
7
|
+
module Pagination
|
8
|
+
attr_accessor :offset, :limit, :elements, :total_elements
|
9
|
+
|
10
|
+
def more_elements?
|
11
|
+
@total_elements && @total_elements > @offset + @elements
|
12
|
+
end
|
13
|
+
|
14
|
+
def next_offset
|
15
|
+
@offset + @limit if more_elements?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Tikkie
|
7
|
+
module Api
|
8
|
+
module Responses
|
9
|
+
# Payment that is associated with a payment request.
|
10
|
+
class Payment < Base
|
11
|
+
def payment_token
|
12
|
+
data[:paymentToken]
|
13
|
+
end
|
14
|
+
|
15
|
+
def counter_party_name
|
16
|
+
data[:counterPartyName]
|
17
|
+
end
|
18
|
+
|
19
|
+
def amount
|
20
|
+
decimal = BigDecimal.new(data[:amountInCents])
|
21
|
+
decimal /= 100.0
|
22
|
+
decimal
|
23
|
+
end
|
24
|
+
|
25
|
+
def currency
|
26
|
+
data[:amountCurrency]
|
27
|
+
end
|
28
|
+
|
29
|
+
def description
|
30
|
+
data[:description]
|
31
|
+
end
|
32
|
+
|
33
|
+
def created_at
|
34
|
+
Time.parse(data[:created]) if data[:created]
|
35
|
+
end
|
36
|
+
|
37
|
+
# See PaymentStatus
|
38
|
+
def online_payment_status
|
39
|
+
data[:onlinePaymentStatus]
|
40
|
+
end
|
41
|
+
|
42
|
+
def paid?
|
43
|
+
online_payment_status == Tikkie::Api::Types::PaymentStatus::PAID
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|