tide-api 0.2.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 +7 -0
- data/.editorconfig +11 -0
- data/.gitignore +15 -0
- data/.overcommit.yml +33 -0
- data/.rspec +3 -0
- data/.rubocop.yml +33 -0
- data/.tool-versions +1 -0
- data/.travis.yml +22 -0
- data/.yardopts +1 -0
- data/.yardstick.yml +29 -0
- data/CHANGELOG.md +13 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Guardfile +20 -0
- data/LICENSE.md +21 -0
- data/README.md +88 -0
- data/Rakefile +37 -0
- data/bin/console +7 -0
- data/bin/setup +14 -0
- data/lib/tide/api/account.rb +66 -0
- data/lib/tide/api/client.rb +103 -0
- data/lib/tide/api/company.rb +60 -0
- data/lib/tide/api/error.rb +24 -0
- data/lib/tide/api/http_client.rb +42 -0
- data/lib/tide/api/mapper.rb +34 -0
- data/lib/tide/api/response.rb +33 -0
- data/lib/tide/api/tokens.rb +18 -0
- data/lib/tide/api/transaction.rb +127 -0
- data/lib/tide/api/types.rb +14 -0
- data/lib/tide/api/util.rb +41 -0
- data/lib/tide/api/version.rb +5 -0
- data/lib/tide/api.rb +10 -0
- data/tide-api.gemspec +49 -0
- metadata +383 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# A business company owned by the account holder
|
4
|
+
class Company < Dry::Struct::Value
|
5
|
+
# Tide's unique ID of the company.
|
6
|
+
#
|
7
|
+
# @return [Integer]
|
8
|
+
#
|
9
|
+
attribute :company_id, Types::Strict::Integer
|
10
|
+
|
11
|
+
# Registration number in Companies House.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
#
|
15
|
+
attribute :number, Types::Strict::String
|
16
|
+
|
17
|
+
# Legal name of the company.
|
18
|
+
#
|
19
|
+
# @return [Integer]
|
20
|
+
#
|
21
|
+
attribute :name, Types::Strict::String
|
22
|
+
|
23
|
+
# Trading name of the company.
|
24
|
+
#
|
25
|
+
# @return [Integer]
|
26
|
+
#
|
27
|
+
attribute :trading_name, Types::Strict::String
|
28
|
+
|
29
|
+
# SIC code.
|
30
|
+
#
|
31
|
+
# @return [Integer|nil]
|
32
|
+
#
|
33
|
+
attribute :sic_code, Types::Strict::Integer.optional
|
34
|
+
|
35
|
+
# VAT number.
|
36
|
+
#
|
37
|
+
# @return [String|nil]
|
38
|
+
#
|
39
|
+
attribute :vat_number, Types::Strict::String.optional
|
40
|
+
|
41
|
+
# Wether the company is registered or not? TODO
|
42
|
+
#
|
43
|
+
# @return [Boolean]
|
44
|
+
#
|
45
|
+
attribute :registered, Types::Strict::Bool
|
46
|
+
|
47
|
+
# Date when the company was created in Tide.
|
48
|
+
#
|
49
|
+
# @return [DateTime]
|
50
|
+
#
|
51
|
+
attribute :iso_created_on, Types::Params::DateTime
|
52
|
+
|
53
|
+
# Date when the company was was updated in Tide.
|
54
|
+
#
|
55
|
+
# @return [DateTime]
|
56
|
+
#
|
57
|
+
attribute :iso_updated_on, Types::Params::DateTime
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# An error resulting from an API call
|
4
|
+
class Error < Dry::Struct::Value
|
5
|
+
# A code that uniquely identifies the error
|
6
|
+
#
|
7
|
+
# @return [Integer]
|
8
|
+
#
|
9
|
+
attribute :code, Types::Strict::Integer
|
10
|
+
|
11
|
+
# A human readable description of the code
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
#
|
15
|
+
attribute :message, Types::Strict::String
|
16
|
+
|
17
|
+
# A long description of the error. Unfortunately, it is null most of the time.
|
18
|
+
#
|
19
|
+
# @return [String|nil]
|
20
|
+
#
|
21
|
+
attribute :details, Types::Strict::String.optional
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'http'
|
2
|
+
require 'tide/api/response'
|
3
|
+
|
4
|
+
module Tide
|
5
|
+
module API
|
6
|
+
# Responsible for the HTTP interactions. The only entity aware of HTTP concerns such as status codes and headers.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
#
|
10
|
+
class HTTPClient
|
11
|
+
# An OAuth2 access token
|
12
|
+
attr_accessor :access_token
|
13
|
+
|
14
|
+
# An OAuth2 refresh token
|
15
|
+
attr_accessor :refresh_token
|
16
|
+
|
17
|
+
# Performs a GET request to Tide's API. Every request returns the status code 200.
|
18
|
+
#
|
19
|
+
# @example Retrieving a resource
|
20
|
+
# client = HTTPClient.new
|
21
|
+
# result = client.get('https://api.tide.co/tide-backend/rest/api/v1/oauth2/tokens')
|
22
|
+
#
|
23
|
+
# @param [String] endpoint URL of the API endpoint of the GET request
|
24
|
+
#
|
25
|
+
# @return [Response] Generic response of a request to Tide's API
|
26
|
+
#
|
27
|
+
def get(endpoint)
|
28
|
+
response = HTTP.headers(headers).get(endpoint)
|
29
|
+
|
30
|
+
Response.new(JSON.parse(response.body), response.status != 200)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def headers
|
36
|
+
return {} if access_token.nil?
|
37
|
+
|
38
|
+
{ Authorization: "Bearer #{access_token}" }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'tide/api/util'
|
2
|
+
|
3
|
+
module Tide
|
4
|
+
module API
|
5
|
+
# Transforms arrays of hashes into concrete instances of classes.
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
class Mapper
|
10
|
+
# Creates objects from an API response. The objects will be an instance of +object_class+.
|
11
|
+
#
|
12
|
+
# @param [Class] object_class Class of the final objects
|
13
|
+
# @param [Array<Hash>] items Array of attributes to instantiate the final objects
|
14
|
+
#
|
15
|
+
# @return An array of objects of the given class
|
16
|
+
#
|
17
|
+
def map(items, object_class)
|
18
|
+
items.map { |item| map_one(item, object_class) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a single object from an API response. The object will be an instance of +object_class+.
|
22
|
+
#
|
23
|
+
# @param [Class] object_class Class of the final object
|
24
|
+
# @param [Hash] item Attributes to instantiate the final object
|
25
|
+
#
|
26
|
+
# @return An object of the given class
|
27
|
+
#
|
28
|
+
def map_one(item, object_class)
|
29
|
+
attributes = item.transform_keys { |attribute| Util.underscore(attribute) }
|
30
|
+
object_class.new(attributes)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# Generic response of a request to Tide's API
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
class Response
|
8
|
+
# Hash or array of hashes representing each item in the response body.
|
9
|
+
#
|
10
|
+
# @return [Hash|Array<Hash>]
|
11
|
+
#
|
12
|
+
attr_reader :payload
|
13
|
+
|
14
|
+
# Instantiates a new API response
|
15
|
+
#
|
16
|
+
# @param [Hash|Array<Hash>] payload Hash or array of hashes representing each item in the response body.
|
17
|
+
# @param [Boolean] error Whether the request failed
|
18
|
+
#
|
19
|
+
def initialize(payload, error)
|
20
|
+
@payload = payload
|
21
|
+
@error = error
|
22
|
+
end
|
23
|
+
|
24
|
+
# Whether the response contains errors
|
25
|
+
#
|
26
|
+
# @return [Boolean] true if the response has errors and false otherwise
|
27
|
+
#
|
28
|
+
def error?
|
29
|
+
@error
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# OAuth2 access and refresh tokens
|
4
|
+
class Tokens < Dry::Struct::Value
|
5
|
+
# OAuth2 Access Token
|
6
|
+
#
|
7
|
+
# @return [String]
|
8
|
+
#
|
9
|
+
attribute :access_token, Types::Strict::String
|
10
|
+
|
11
|
+
# OAuth2 Refresh Token
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
#
|
15
|
+
attribute :refresh_token, Types::Strict::String
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# Bank account transaction
|
4
|
+
class Transaction < Dry::Struct::Value
|
5
|
+
# Categories of the transaction
|
6
|
+
CategoryType = Types::Strict::String.enum('EXPENDITURE', 'INCOME')
|
7
|
+
|
8
|
+
# Statuses of the transaction
|
9
|
+
Status = Types::Strict::String.enum('cleared', 'pending')
|
10
|
+
|
11
|
+
# Payment type codes
|
12
|
+
Type = Types::Strict::String.enum(
|
13
|
+
'PYI', # Faster Payment In
|
14
|
+
'PYI_REV', # Faster Payment In Reversal
|
15
|
+
'PYO', # Faster Payment Out
|
16
|
+
'TRD', # Inter-Account Transfer Out
|
17
|
+
'TRC', # Inter-Account Transfer In
|
18
|
+
'RED', # Card Payment Out
|
19
|
+
'RED_REV', # Card Payment Reversal
|
20
|
+
'WTH', # Cash Withdrawal
|
21
|
+
'WTH_REV', # Cash Withdrawal Reversal
|
22
|
+
'REF', # Refund
|
23
|
+
'REF_REV', # Refund Reversal
|
24
|
+
'FEE', # Fee
|
25
|
+
'TOP', # Tide Credit
|
26
|
+
'TOP_REV' # Tide Credit Reversal
|
27
|
+
)
|
28
|
+
|
29
|
+
# Tide's unique transaction ID.
|
30
|
+
#
|
31
|
+
# @return [Integer]
|
32
|
+
#
|
33
|
+
attribute :transaction_id, Types::Strict::Integer
|
34
|
+
|
35
|
+
# ID of the parent account.
|
36
|
+
#
|
37
|
+
# @return [Integer]
|
38
|
+
#
|
39
|
+
attribute :account_id, Types::Strict::Integer
|
40
|
+
|
41
|
+
# Transaction amount. Can be positive or negative.
|
42
|
+
#
|
43
|
+
# @return [BigDecimal]
|
44
|
+
#
|
45
|
+
attribute :amount, Types::Params::Decimal
|
46
|
+
|
47
|
+
# Transaction Type code.
|
48
|
+
#
|
49
|
+
# @see +Type+.
|
50
|
+
# @return [String]
|
51
|
+
#
|
52
|
+
attribute :type, Type
|
53
|
+
|
54
|
+
# Unique reference of the transaction.
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
#
|
58
|
+
attribute :txn_ref, Types::Strict::String
|
59
|
+
|
60
|
+
# Time of the transaction.
|
61
|
+
#
|
62
|
+
# @return [DateTime]
|
63
|
+
#
|
64
|
+
attribute :iso_transaction_date_time, Types::Params::DateTime
|
65
|
+
|
66
|
+
# Time when the transaction was applied
|
67
|
+
#
|
68
|
+
# @return [DateTime]
|
69
|
+
#
|
70
|
+
attribute :iso_applied_date_time, Types::Params::DateTime
|
71
|
+
|
72
|
+
# Time when the transaction was cleared.
|
73
|
+
#
|
74
|
+
# @return [DateTime]
|
75
|
+
#
|
76
|
+
attribute :iso_cleared_date_time, Types::Params::DateTime
|
77
|
+
|
78
|
+
# Masked debit/credit card number.
|
79
|
+
#
|
80
|
+
# @return [String]
|
81
|
+
#
|
82
|
+
attribute :masked_pan, Types::Strict::String.optional
|
83
|
+
|
84
|
+
# TODO
|
85
|
+
#
|
86
|
+
# @return [String]
|
87
|
+
#
|
88
|
+
attribute :status, Status
|
89
|
+
|
90
|
+
# TODO
|
91
|
+
#
|
92
|
+
# @return [String]
|
93
|
+
#
|
94
|
+
attribute :description, Types::Strict::String
|
95
|
+
|
96
|
+
# TODO
|
97
|
+
#
|
98
|
+
# @return [DateTime]
|
99
|
+
#
|
100
|
+
attribute :iso_created_on, Types::Params::DateTime
|
101
|
+
|
102
|
+
# TODO
|
103
|
+
#
|
104
|
+
# @return [DateTime]
|
105
|
+
#
|
106
|
+
attribute :iso_updated_on, Types::Params::DateTime
|
107
|
+
|
108
|
+
# TODO
|
109
|
+
#
|
110
|
+
# @return [Integer]
|
111
|
+
#
|
112
|
+
attribute :category_id, Types::Strict::Integer
|
113
|
+
|
114
|
+
# TODO
|
115
|
+
#
|
116
|
+
# @return [String|String]
|
117
|
+
#
|
118
|
+
attribute :category_name, Types::Strict::String.optional
|
119
|
+
|
120
|
+
# TODO
|
121
|
+
#
|
122
|
+
# @return [String|nil]
|
123
|
+
#
|
124
|
+
attribute :category_type, CategoryType.optional
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Tide
|
2
|
+
module API
|
3
|
+
# Provides methods for string manipulation
|
4
|
+
#
|
5
|
+
# @api private
|
6
|
+
#
|
7
|
+
module Util
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Converts a string to snake case
|
11
|
+
#
|
12
|
+
# @param [String|Symbol] term The term to be converted.
|
13
|
+
#
|
14
|
+
# @return [String] A snake-cased version of the input
|
15
|
+
#
|
16
|
+
def underscore(term)
|
17
|
+
term
|
18
|
+
.to_s
|
19
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
20
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
21
|
+
.tr('-', '_')
|
22
|
+
.downcase
|
23
|
+
.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
# Converts a string to camel case
|
27
|
+
#
|
28
|
+
# @param [String|Symbol] term The term to be converted.
|
29
|
+
#
|
30
|
+
# @return [String] A camel-cased version of the input
|
31
|
+
#
|
32
|
+
def camelize(term)
|
33
|
+
string = term.to_s
|
34
|
+
string = string.sub(/^[a-z\d]*/, &:capitalize)
|
35
|
+
string.gsub!(%r{(?:_|(\/))([a-z\d]*)}) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
|
36
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
37
|
+
string
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/tide/api.rb
ADDED
data/tide-api.gemspec
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'tide/api/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'tide-api'
|
7
|
+
spec.version = Tide::API::VERSION
|
8
|
+
spec.authors = ['Wilson Silva']
|
9
|
+
spec.email = ['me@wilsonsilva.net']
|
10
|
+
|
11
|
+
spec.summary = "Client for Tide's bank RESTful API"
|
12
|
+
spec.description = "Client for Tide's bank RESTful API"
|
13
|
+
spec.homepage = 'https://github.com/wilsonsilva/tide-api'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
end
|
21
|
+
|
22
|
+
spec.bindir = 'exe'
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ['lib']
|
25
|
+
|
26
|
+
spec.add_dependency 'dry-struct', '~> 1.0'
|
27
|
+
spec.add_dependency 'http', '~> 4.1'
|
28
|
+
|
29
|
+
spec.add_development_dependency 'bundler', '~> 1.17'
|
30
|
+
spec.add_development_dependency 'bundler-audit', '~> 0.6'
|
31
|
+
spec.add_development_dependency 'guard', '~> 2.15'
|
32
|
+
spec.add_development_dependency 'guard-bundler', '~> 2.2'
|
33
|
+
spec.add_development_dependency 'guard-bundler-audit', '~> 0.1'
|
34
|
+
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
35
|
+
spec.add_development_dependency 'guard-rubocop', '~> 1.3'
|
36
|
+
spec.add_development_dependency 'overcommit', '~> 0.48'
|
37
|
+
spec.add_development_dependency 'pry', '~> 0.12'
|
38
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
39
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
40
|
+
spec.add_development_dependency 'rubocop', '~> 0.72'
|
41
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.33'
|
42
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
43
|
+
spec.add_development_dependency 'simplecov-console', '~> 0.5'
|
44
|
+
spec.add_development_dependency 'vcr', '~> 4.0'
|
45
|
+
spec.add_development_dependency 'webmock', '~> 3.5'
|
46
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
47
|
+
spec.add_development_dependency 'yard-junk', '~> 0.0.7'
|
48
|
+
spec.add_development_dependency 'yardstick', '~> 0.9'
|
49
|
+
end
|