nova-api 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +43 -0
- data/.circleci/setup-rubygems.sh +3 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +96 -0
- data/LICENSE.txt +21 -0
- data/README.md +65 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/nova/api.rb +84 -0
- data/lib/nova/api/base.rb +126 -0
- data/lib/nova/api/list_response.rb +42 -0
- data/lib/nova/api/resource/apportionment.rb +80 -0
- data/lib/nova/api/resource/apportionment_value.rb +74 -0
- data/lib/nova/api/resource/bank.rb +28 -0
- data/lib/nova/api/resource/card.rb +20 -0
- data/lib/nova/api/resource/cash.rb +19 -0
- data/lib/nova/api/resource/company.rb +21 -0
- data/lib/nova/api/resource/current_asset.rb +33 -0
- data/lib/nova/api/resource/financial_account.rb +84 -0
- data/lib/nova/api/resource/response/current_asset_statement.rb +12 -0
- data/lib/nova/api/resource/third_party.rb +97 -0
- data/lib/nova/api/resource/write_off.rb +14 -0
- data/lib/nova/api/response.rb +39 -0
- data/lib/nova/api/search_params/apportionment.rb +10 -0
- data/lib/nova/api/search_params/current_asset.rb +10 -0
- data/lib/nova/api/search_params/current_asset_statement.rb +12 -0
- data/lib/nova/api/search_params/third_party.rb +9 -0
- data/lib/nova/api/utils/base_struct.rb +14 -0
- data/lib/nova/api/version.rb +5 -0
- data/lib/nova/configuration.rb +9 -0
- data/nova-api.gemspec +50 -0
- metadata +224 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Nova
|
5
|
+
module API
|
6
|
+
class Base < Nova::API::Utils::BaseStruct
|
7
|
+
extend Forwardable
|
8
|
+
include HTTParty
|
9
|
+
|
10
|
+
format :json
|
11
|
+
|
12
|
+
SCHEME = 'https'
|
13
|
+
HOST = 'nova.money'
|
14
|
+
|
15
|
+
def self.endpoint
|
16
|
+
raise EndpointNotConfiguredError, 'Each class must implement its own endpoint'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.base_url
|
20
|
+
raise Nova::API::MissingSubdomainError, 'The subdomain must be informed' if configuration.subdomain.nil? || configuration.subdomain.empty?
|
21
|
+
|
22
|
+
"#{SCHEME}://#{configuration.subdomain}.#{HOST}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def endpoint
|
26
|
+
raise EndpointNotConfiguredError, 'Each class must implement its own endpoint'
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def allowed_attributes
|
32
|
+
return attributes unless self.class.const_defined?('ALLOWED_ATTRIBUTES')
|
33
|
+
|
34
|
+
data = attributes.dup
|
35
|
+
|
36
|
+
data.keys.each { |key| data.delete(key.to_sym) unless self.class.const_get('ALLOWED_ATTRIBUTES').include?(key.to_sym) }
|
37
|
+
|
38
|
+
data
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.initialize_empty_model_with_id(klass, id, additional_attributes = {})
|
42
|
+
data = klass.attribute_names.map { |key| additional_attributes[key] ? [key, additional_attributes[key]] : [key, nil] }
|
43
|
+
|
44
|
+
klass.new(Hash[*data.flatten].merge(id: id))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.do_get_search(endpoint, query, object = self)
|
48
|
+
response = perform_get(endpoint, query, headers)
|
49
|
+
|
50
|
+
Nova::API::ListResponse.build(response, object)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.do_get(endpoint, query, object = self)
|
54
|
+
response = perform_get(endpoint, query, headers)
|
55
|
+
|
56
|
+
Nova::API::Response.build(response, object)
|
57
|
+
end
|
58
|
+
def_delegator self, :do_get
|
59
|
+
|
60
|
+
def do_delete(endpoint)
|
61
|
+
set_base_uri
|
62
|
+
|
63
|
+
response = self.class.delete(endpoint, headers: authorization_header)
|
64
|
+
|
65
|
+
Nova::API::Response.build(response)
|
66
|
+
end
|
67
|
+
|
68
|
+
def do_patch(endpoint, data)
|
69
|
+
set_base_uri
|
70
|
+
|
71
|
+
if data.nil? || data.empty?
|
72
|
+
response = self.class.patch(endpoint, headers: authorization_header)
|
73
|
+
|
74
|
+
Nova::API::Response.build(response)
|
75
|
+
else
|
76
|
+
payload = data.dup
|
77
|
+
payload.delete(:id)
|
78
|
+
|
79
|
+
response = self.class.patch(endpoint, body: payload, headers: authorization_header)
|
80
|
+
|
81
|
+
Nova::API::Response.build(response, self)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def do_post(endpoint, data)
|
86
|
+
set_base_uri
|
87
|
+
|
88
|
+
response = self.class.post(endpoint, body: data, headers: authorization_header)
|
89
|
+
|
90
|
+
Nova::API::Response.build(response, self)
|
91
|
+
end
|
92
|
+
|
93
|
+
def protect_operation_from_missing_value(attribute = :id)
|
94
|
+
raise Nova::API::MissingIdError, 'This operation requires an ID to be set' if send(attribute).nil?
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def self.perform_get(endpoint, query, headers = {})
|
100
|
+
set_base_uri
|
101
|
+
|
102
|
+
response =
|
103
|
+
if query
|
104
|
+
self.get(endpoint, query: query, headers: headers.merge(authorization_header))
|
105
|
+
else
|
106
|
+
self.get(endpoint, headers: headers.merge(authorization_header))
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.authorization_header
|
111
|
+
{ 'Persistent-Token': configuration.api_key }
|
112
|
+
end
|
113
|
+
def_delegator self, :authorization_header
|
114
|
+
|
115
|
+
def self.configuration
|
116
|
+
Nova::API.configuration
|
117
|
+
end
|
118
|
+
def_delegator self, :configuration
|
119
|
+
|
120
|
+
def self.set_base_uri
|
121
|
+
base_uri base_url
|
122
|
+
end
|
123
|
+
def_delegator self, :set_base_uri
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'dry-struct'
|
3
|
+
require 'dry-types'
|
4
|
+
|
5
|
+
module Nova
|
6
|
+
module API
|
7
|
+
class ListResponse < Nova::API::Utils::BaseStruct
|
8
|
+
attribute :records, Dry::Types['strict.array'].of(Dry::Types['nominal.any']).optional
|
9
|
+
attribute :errors, Dry::Types['strict.array'].of(Dry::Types['coercible.string'])
|
10
|
+
attribute :success, Dry::Types['strict.bool']
|
11
|
+
|
12
|
+
def self.build(response, klass)
|
13
|
+
success = response.success?
|
14
|
+
|
15
|
+
parsed_response = response.parsed_response
|
16
|
+
|
17
|
+
records = nil
|
18
|
+
|
19
|
+
if parsed_response.is_a?(Array)
|
20
|
+
records = klass.nil? ? nil : parsed_response.map { |object| klass.new(object) }
|
21
|
+
else
|
22
|
+
parsed_response = parsed_response.to_h
|
23
|
+
|
24
|
+
errors = extract_error_from_response('error', parsed_response)
|
25
|
+
errors ||= extract_error_from_response('errors', parsed_response)
|
26
|
+
end
|
27
|
+
|
28
|
+
errors ||= []
|
29
|
+
|
30
|
+
new(success: success, errors: errors, records: records)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.extract_error_from_response(field, response)
|
36
|
+
return unless response.has_key?(field)
|
37
|
+
|
38
|
+
response[field].is_a?(Array) ? response[field] : [response[field]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class Apportionment < Nova::API::Base
|
5
|
+
ALLOWED_ATTRIBUTES = %i[name]
|
6
|
+
|
7
|
+
attribute? :id, Dry::Types['coercible.integer'].optional
|
8
|
+
attribute :name, Dry::Types['coercible.string']
|
9
|
+
attribute? :active, Dry::Types['strict.bool'].optional
|
10
|
+
attribute? :values, Dry::Types['strict.array'].of(Nova::API::Resource::ApportionmentValue).optional
|
11
|
+
|
12
|
+
def self.endpoint
|
13
|
+
'/api/apportionments'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.list(parameters = {})
|
17
|
+
do_get_search(endpoint, parameters.to_h)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.create(parameters)
|
21
|
+
model = new parameters
|
22
|
+
|
23
|
+
model.attributes.delete(:id)
|
24
|
+
|
25
|
+
model.save
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.update(id, parameters)
|
29
|
+
model = new parameters.merge(id: id)
|
30
|
+
|
31
|
+
model.update
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.destroy(id)
|
35
|
+
model = initialize_empty_model_with_id(self, id)
|
36
|
+
|
37
|
+
model.destroy
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.reactivate(id)
|
41
|
+
model = initialize_empty_model_with_id(self, id)
|
42
|
+
|
43
|
+
model.reactivate
|
44
|
+
end
|
45
|
+
|
46
|
+
def endpoint
|
47
|
+
protect_operation_from_missing_value
|
48
|
+
|
49
|
+
"/api/apportionments/#{id}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def save
|
53
|
+
if id.nil?
|
54
|
+
do_post(self.class.endpoint, allowed_attributes)
|
55
|
+
else
|
56
|
+
do_patch("#{endpoint}", allowed_attributes)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def update
|
61
|
+
protect_operation_from_missing_value
|
62
|
+
|
63
|
+
do_patch("#{endpoint}", allowed_attributes)
|
64
|
+
end
|
65
|
+
|
66
|
+
def destroy
|
67
|
+
protect_operation_from_missing_value
|
68
|
+
|
69
|
+
do_delete("#{endpoint}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def reactivate
|
73
|
+
protect_operation_from_missing_value
|
74
|
+
|
75
|
+
do_patch("#{endpoint}/reactivate", {})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class ApportionmentValue < Nova::API::Base
|
5
|
+
ALLOWED_ATTRIBUTES = %i[name]
|
6
|
+
|
7
|
+
attribute? :id, Dry::Types['coercible.integer'].optional
|
8
|
+
attribute :name, Dry::Types['coercible.string']
|
9
|
+
attribute? :active, Dry::Types['strict.bool'].optional
|
10
|
+
attribute? :apportionment_id, Dry::Types['coercible.integer']
|
11
|
+
|
12
|
+
def self.endpoint(apportionment_id)
|
13
|
+
"/api/apportionments/#{apportionment_id}/apportionment_values"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.create(apportionment_id, parameters)
|
17
|
+
model = new parameters.merge(apportionment_id: apportionment_id)
|
18
|
+
|
19
|
+
model.attributes.delete(:id)
|
20
|
+
|
21
|
+
model.save
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.update(apportionment_id, id, parameters)
|
25
|
+
model = new parameters.merge(id: id, apportionment_id: apportionment_id)
|
26
|
+
|
27
|
+
model.update
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.destroy(apportionment_id, id)
|
31
|
+
model = initialize_empty_model_with_id(self, id, apportionment_id: apportionment_id)
|
32
|
+
|
33
|
+
model.destroy
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.reactivate(apportionment_id, id)
|
37
|
+
model = initialize_empty_model_with_id(self, id, apportionment_id: apportionment_id)
|
38
|
+
|
39
|
+
model.reactivate
|
40
|
+
end
|
41
|
+
|
42
|
+
def endpoint
|
43
|
+
"/api/apportionments/#{apportionment_id}/apportionment_values/#{id}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def save
|
47
|
+
if id.nil?
|
48
|
+
do_post(self.class.endpoint(apportionment_id), allowed_attributes)
|
49
|
+
else
|
50
|
+
do_patch("#{endpoint}", allowed_attributes)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def update
|
55
|
+
protect_operation_from_missing_value
|
56
|
+
|
57
|
+
do_patch("#{endpoint}", allowed_attributes)
|
58
|
+
end
|
59
|
+
|
60
|
+
def destroy
|
61
|
+
protect_operation_from_missing_value
|
62
|
+
|
63
|
+
do_delete("#{endpoint}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def reactivate
|
67
|
+
protect_operation_from_missing_value
|
68
|
+
|
69
|
+
do_patch("#{endpoint}/reactivate", {})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class Bank < Nova::API::Resource::CurrentAsset
|
5
|
+
ALLOWED_ATTRIBUTES = %i[]
|
6
|
+
|
7
|
+
attribute? :agency, Dry::Types['coercible.string'].optional
|
8
|
+
attribute? :current_account, Dry::Types['coercible.string'].optional
|
9
|
+
attribute? :institution do
|
10
|
+
attribute :code, Dry::Types['coercible.string'].optional
|
11
|
+
attribute :name, Dry::Types['coercible.string'].optional
|
12
|
+
end
|
13
|
+
attribute? :usage do
|
14
|
+
attribute :code, Dry::Types['coercible.integer'].optional
|
15
|
+
attribute :name, Dry::Types['coercible.string'].optional
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.endpoint
|
19
|
+
'/api/banks'
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.list(parameters = {})
|
23
|
+
do_get_search(endpoint, parameters.to_h)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class Card < Nova::API::Resource::CurrentAsset
|
5
|
+
ALLOWED_ATTRIBUTES = %i[]
|
6
|
+
|
7
|
+
attribute? :description, Dry::Types['coercible.string'].optional
|
8
|
+
attribute? :institution, Dry::Types['coercible.string'].optional
|
9
|
+
|
10
|
+
def self.endpoint
|
11
|
+
'/api/cards'
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.list(parameters = {})
|
15
|
+
do_get_search(endpoint, parameters.to_h)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class Cash < Nova::API::Resource::CurrentAsset
|
5
|
+
ALLOWED_ATTRIBUTES = %i[]
|
6
|
+
|
7
|
+
attribute? :description, Dry::Types['coercible.string'].optional
|
8
|
+
|
9
|
+
def self.endpoint
|
10
|
+
'/api/cashes'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.list(parameters = {})
|
14
|
+
do_get_search(endpoint, parameters.to_h)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class Company < Nova::API::Base
|
5
|
+
ALLOWED_ATTRIBUTES = %i[]
|
6
|
+
|
7
|
+
attribute? :id, Dry::Types['coercible.integer'].optional
|
8
|
+
attribute? :name, Dry::Types['coercible.string'].optional
|
9
|
+
attribute? :trading_name, Dry::Types['coercible.string'].optional
|
10
|
+
|
11
|
+
def self.endpoint
|
12
|
+
'/api/companies'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.list
|
16
|
+
do_get_search(endpoint, nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nova
|
2
|
+
module API
|
3
|
+
module Resource
|
4
|
+
class CurrentAsset < Nova::API::Base
|
5
|
+
ALLOWED_ATTRIBUTES = %i[]
|
6
|
+
|
7
|
+
attribute? :id, Dry::Types['coercible.integer'].optional
|
8
|
+
attribute? :company, Nova::API::Resource::Company.optional
|
9
|
+
attribute? :active, Dry::Types['strict.bool'].optional
|
10
|
+
attribute? :image, Dry::Types['coercible.string'].optional
|
11
|
+
attribute? :balance, Dry::Types['coercible.decimal'].optional
|
12
|
+
|
13
|
+
def self.endpoint
|
14
|
+
'/api/current_assets'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.statement(parameters = {})
|
18
|
+
do_get("#{endpoint}/statement", parameters.to_h, Nova::API::Resource::Response::CurrentAssetStatement.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
def statement(initial_date, final_date)
|
22
|
+
protect_operation_from_missing_value
|
23
|
+
|
24
|
+
self.class.do_get("#{endpoint}/statement", { company_id: company.id, current_asset_id: id, final_date: final_date, initial_date: initial_date }, Nova::API::Resource::Response::CurrentAssetStatement.new)
|
25
|
+
end
|
26
|
+
|
27
|
+
def endpoint
|
28
|
+
"/api/current_assets"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|