nova-api 0.4.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/.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
|