tikkie-api 0.1.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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +36 -0
  5. data/.travis.yml +7 -0
  6. data/Gemfile +10 -0
  7. data/Gemfile.lock +67 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +150 -0
  10. data/Rakefile +10 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/lib/tikkie/api.rb +32 -0
  14. data/lib/tikkie/api/access_token.rb +19 -0
  15. data/lib/tikkie/api/authentication.rb +60 -0
  16. data/lib/tikkie/api/client.rb +24 -0
  17. data/lib/tikkie/api/configuration.rb +62 -0
  18. data/lib/tikkie/api/exception.rb +22 -0
  19. data/lib/tikkie/api/request.rb +57 -0
  20. data/lib/tikkie/api/requests/payment_requests.rb +56 -0
  21. data/lib/tikkie/api/requests/platforms.rb +32 -0
  22. data/lib/tikkie/api/requests/users.rb +31 -0
  23. data/lib/tikkie/api/responses/bank_account.rb +22 -0
  24. data/lib/tikkie/api/responses/base.rb +53 -0
  25. data/lib/tikkie/api/responses/error.rb +34 -0
  26. data/lib/tikkie/api/responses/pagination.rb +20 -0
  27. data/lib/tikkie/api/responses/payment.rb +48 -0
  28. data/lib/tikkie/api/responses/payment_request.rb +64 -0
  29. data/lib/tikkie/api/responses/payment_request_created.rb +22 -0
  30. data/lib/tikkie/api/responses/payment_requests.rb +42 -0
  31. data/lib/tikkie/api/responses/platform.rb +44 -0
  32. data/lib/tikkie/api/responses/platforms.rb +30 -0
  33. data/lib/tikkie/api/responses/user.rb +39 -0
  34. data/lib/tikkie/api/responses/users.rb +34 -0
  35. data/lib/tikkie/api/types/payment_request_status.rb +15 -0
  36. data/lib/tikkie/api/types/payment_status.rb +14 -0
  37. data/lib/tikkie/api/types/platform_status.rb +12 -0
  38. data/lib/tikkie/api/types/platform_usage.rb +12 -0
  39. data/lib/tikkie/api/types/user_status.rb +12 -0
  40. data/lib/tikkie/api/version.rb +7 -0
  41. data/tikkie-api.gemspec +31 -0
  42. 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