fortnox-api 0.7.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.env.template +7 -0
- data/.env.test +11 -3
- data/.gitignore +7 -1
- data/.rubocop.yml +18 -2
- data/.tool-versions +1 -0
- data/.travis.yml +15 -19
- data/CHANGELOG.md +66 -1
- data/CONTRIBUTE.md +21 -9
- data/DEVELOPER_README.md +72 -0
- data/Guardfile +13 -4
- data/README.md +226 -61
- data/Rakefile +133 -0
- data/bin/get_tokens +79 -0
- data/bin/renew_tokens +28 -0
- data/fortnox-api.gemspec +31 -25
- data/lib/fortnox/api/mappers/article.rb +1 -1
- data/lib/fortnox/api/mappers/base/from_json.rb +7 -6
- data/lib/fortnox/api/mappers/base/to_json.rb +4 -5
- data/lib/fortnox/api/mappers/base.rb +3 -3
- data/lib/fortnox/api/mappers/customer.rb +1 -1
- data/lib/fortnox/api/mappers/default_delivery_types.rb +1 -1
- data/lib/fortnox/api/mappers/default_templates.rb +1 -1
- data/lib/fortnox/api/mappers/edi_information.rb +1 -1
- data/lib/fortnox/api/mappers/email_information.rb +1 -1
- data/lib/fortnox/api/mappers/invoice.rb +4 -4
- data/lib/fortnox/api/mappers/invoice_row.rb +1 -1
- data/lib/fortnox/api/mappers/order.rb +4 -4
- data/lib/fortnox/api/mappers/order_row.rb +1 -1
- data/lib/fortnox/api/mappers/project.rb +1 -1
- data/lib/fortnox/api/mappers/terms_of_payment.rb +1 -1
- data/lib/fortnox/api/mappers/unit.rb +1 -1
- data/lib/fortnox/api/mappers/value/country_string.rb +1 -1
- data/lib/fortnox/api/mappers.rb +18 -18
- data/lib/fortnox/api/models/article.rb +2 -2
- data/lib/fortnox/api/models/base.rb +23 -21
- data/lib/fortnox/api/models/customer.rb +57 -57
- data/lib/fortnox/api/models/document.rb +5 -2
- data/lib/fortnox/api/models/invoice.rb +2 -2
- data/lib/fortnox/api/models/label.rb +3 -3
- data/lib/fortnox/api/models/order.rb +2 -2
- data/lib/fortnox/api/models/project.rb +2 -2
- data/lib/fortnox/api/models/terms_of_payment.rb +2 -2
- data/lib/fortnox/api/models/unit.rb +2 -2
- data/lib/fortnox/api/models.rb +7 -7
- data/lib/fortnox/api/repositories/article.rb +3 -3
- data/lib/fortnox/api/repositories/authentication.rb +61 -0
- data/lib/fortnox/api/repositories/base/savers.rb +3 -1
- data/lib/fortnox/api/repositories/base.rb +25 -38
- data/lib/fortnox/api/repositories/customer.rb +3 -3
- data/lib/fortnox/api/repositories/invoice.rb +3 -3
- data/lib/fortnox/api/repositories/order.rb +3 -3
- data/lib/fortnox/api/repositories/project.rb +3 -3
- data/lib/fortnox/api/repositories/terms_of_payment.rb +3 -3
- data/lib/fortnox/api/repositories/unit.rb +3 -3
- data/lib/fortnox/api/repositories.rb +8 -7
- data/lib/fortnox/api/request_handling.rb +30 -18
- data/lib/fortnox/api/types/default_delivery_types.rb +0 -2
- data/lib/fortnox/api/types/default_templates.rb +0 -2
- data/lib/fortnox/api/types/document_row.rb +3 -3
- data/lib/fortnox/api/types/edi_information.rb +0 -2
- data/lib/fortnox/api/types/email_information.rb +0 -2
- data/lib/fortnox/api/types/enums.rb +54 -10
- data/lib/fortnox/api/types/invoice_row.rb +1 -1
- data/lib/fortnox/api/types/model.rb +5 -9
- data/lib/fortnox/api/types/nullable.rb +13 -9
- data/lib/fortnox/api/types/order_row.rb +1 -1
- data/lib/fortnox/api/types/required.rb +3 -3
- data/lib/fortnox/api/types/sized.rb +4 -4
- data/lib/fortnox/api/types.rb +37 -24
- data/lib/fortnox/api/version.rb +1 -1
- data/lib/fortnox/api.rb +21 -39
- data/spec/fortnox/api/mappers/base/canonical_name_sym_spec.rb +13 -11
- data/spec/fortnox/api/mappers/base/from_json_spec.rb +10 -12
- data/spec/fortnox/api/mappers/base/to_json_spec.rb +48 -57
- data/spec/fortnox/api/mappers/base_spec.rb +4 -7
- data/spec/fortnox/api/mappers/contexts/json_conversion.rb +38 -33
- data/spec/fortnox/api/mappers/default_delivery_types_spec.rb +1 -1
- data/spec/fortnox/api/mappers/examples/mapper.rb +1 -1
- data/spec/fortnox/api/mappers/unit_spec.rb +3 -4
- data/spec/fortnox/api/models/base_spec.rb +33 -22
- data/spec/fortnox/api/models/unit_spec.rb +5 -3
- data/spec/fortnox/api/repositories/article_spec.rb +14 -9
- data/spec/fortnox/api/repositories/authentication_spec.rb +103 -0
- data/spec/fortnox/api/repositories/base_spec.rb +105 -326
- data/spec/fortnox/api/repositories/customer_spec.rb +37 -7
- data/spec/fortnox/api/repositories/examples/all.rb +0 -1
- data/spec/fortnox/api/repositories/examples/find.rb +5 -8
- data/spec/fortnox/api/repositories/examples/only.rb +4 -13
- data/spec/fortnox/api/repositories/examples/save.rb +32 -18
- data/spec/fortnox/api/repositories/examples/save_with_nested_model.rb +0 -5
- data/spec/fortnox/api/repositories/examples/save_with_specially_named_attribute.rb +1 -4
- data/spec/fortnox/api/repositories/examples/search.rb +4 -7
- data/spec/fortnox/api/repositories/invoice_spec.rb +72 -29
- data/spec/fortnox/api/repositories/order_spec.rb +11 -9
- data/spec/fortnox/api/repositories/project_spec.rb +7 -6
- data/spec/fortnox/api/repositories/terms_of_payment_spec.rb +9 -7
- data/spec/fortnox/api/repositories/unit_spec.rb +13 -11
- data/spec/fortnox/api/types/country_spec.rb +1 -1
- data/spec/fortnox/api/types/email_spec.rb +2 -2
- data/spec/fortnox/api/types/enums_spec.rb +1 -0
- data/spec/fortnox/api/types/examples/document_row.rb +3 -3
- data/spec/fortnox/api/types/examples/enum.rb +4 -4
- data/spec/fortnox/api/types/examples/types.rb +1 -3
- data/spec/fortnox/api/types/housework_types_spec.rb +124 -43
- data/spec/fortnox/api/types/model_spec.rb +13 -23
- data/spec/fortnox/api/types/nullable_spec.rb +30 -10
- data/spec/fortnox/api/types/order_row_spec.rb +2 -2
- data/spec/fortnox/api/types/required_spec.rb +7 -15
- data/spec/fortnox/api/types/sales_account_spec.rb +57 -0
- data/spec/fortnox/api_spec.rb +19 -124
- data/spec/spec_helper.rb +0 -14
- data/spec/support/helpers/configuration_helper.rb +30 -3
- data/spec/support/helpers.rb +1 -1
- data/spec/support/matchers/type/attribute_matcher.rb +2 -2
- data/spec/support/matchers/type/enum_matcher.rb +1 -1
- data/spec/support/matchers/type/have_account_number_matcher.rb +1 -1
- data/spec/support/matchers/type/have_email_matcher.rb +1 -1
- data/spec/support/matchers/type/have_nullable_date_matcher.rb +7 -5
- data/spec/support/matchers/type/have_nullable_matcher.rb +1 -1
- data/spec/support/matchers/type/have_nullable_string_matcher.rb +5 -5
- data/spec/support/matchers/type/require_attribute_matcher.rb +5 -5
- data/spec/support/matchers/type/type_matcher.rb +1 -1
- data/spec/support/vcr_setup.rb +16 -0
- data/spec/vcr_cassettes/articles/all.yml +41 -42
- data/spec/vcr_cassettes/articles/find_by_hash_failure.yml +36 -19
- data/spec/vcr_cassettes/articles/find_failure.yml +36 -19
- data/spec/vcr_cassettes/articles/find_id_1.yml +38 -20
- data/spec/vcr_cassettes/articles/find_new.yml +39 -22
- data/spec/vcr_cassettes/articles/multi_param_find_by_hash.yml +38 -21
- data/spec/vcr_cassettes/articles/save_new.yml +37 -19
- data/spec/vcr_cassettes/articles/save_old.yml +39 -22
- data/spec/vcr_cassettes/articles/save_with_specially_named_attribute.yml +37 -19
- data/spec/vcr_cassettes/articles/search_by_name.yml +41 -21
- data/spec/vcr_cassettes/articles/search_miss.yml +36 -19
- data/spec/vcr_cassettes/articles/search_with_special_char.yml +36 -19
- data/spec/vcr_cassettes/articles/single_param_find_by_hash.yml +38 -32
- data/spec/vcr_cassettes/authentication/expired_token.yml +54 -0
- data/spec/vcr_cassettes/authentication/invalid_authorization.yml +57 -0
- data/spec/vcr_cassettes/authentication/invalid_refresh_token.yml +58 -0
- data/spec/vcr_cassettes/authentication/valid_request.yml +63 -0
- data/spec/vcr_cassettes/customers/all.yml +44 -132
- data/spec/vcr_cassettes/customers/find_by_hash_failure.yml +36 -19
- data/spec/vcr_cassettes/customers/find_failure.yml +36 -19
- data/spec/vcr_cassettes/customers/find_id_1.yml +39 -21
- data/spec/vcr_cassettes/customers/find_new.yml +38 -21
- data/spec/vcr_cassettes/customers/find_with_sales_account.yml +63 -0
- data/spec/vcr_cassettes/customers/multi_param_find_by_hash.yml +38 -21
- data/spec/vcr_cassettes/customers/save_new.yml +36 -18
- data/spec/vcr_cassettes/customers/save_new_with_country_code_SE.yml +32 -24
- data/spec/vcr_cassettes/customers/save_new_with_sales_account.yml +63 -0
- data/spec/vcr_cassettes/customers/save_old.yml +38 -21
- data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +36 -18
- data/spec/vcr_cassettes/customers/search_by_name.yml +38 -48
- data/spec/vcr_cassettes/customers/search_miss.yml +36 -19
- data/spec/vcr_cassettes/customers/search_with_special_char.yml +36 -19
- data/spec/vcr_cassettes/customers/single_param_find_by_hash.yml +39 -22
- data/spec/vcr_cassettes/invoices/all.yml +71 -114
- data/spec/vcr_cassettes/invoices/filter_hit.yml +39 -24
- data/spec/vcr_cassettes/invoices/filter_invalid.yml +35 -17
- data/spec/vcr_cassettes/invoices/find_by_hash_failure.yml +36 -19
- data/spec/vcr_cassettes/invoices/find_failure.yml +36 -19
- data/spec/vcr_cassettes/invoices/find_id_1.yml +40 -22
- data/spec/vcr_cassettes/invoices/find_new.yml +41 -24
- data/spec/vcr_cassettes/invoices/multi_param_find_by_hash.yml +38 -21
- data/spec/vcr_cassettes/invoices/row_description_limit.yml +65 -0
- data/spec/vcr_cassettes/invoices/save_new.yml +39 -21
- data/spec/vcr_cassettes/invoices/save_new_with_comments.yml +39 -21
- data/spec/vcr_cassettes/invoices/save_new_with_country.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_country_GB.yml +36 -27
- data/spec/vcr_cassettes/invoices/save_new_with_country_Norge.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_country_Norway.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_country_Sverige.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_country_VA.yml +36 -27
- data/spec/vcr_cassettes/invoices/save_new_with_country_VI.yml +36 -27
- data/spec/vcr_cassettes/invoices/save_new_with_country_empty_string.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_country_nil.yml +35 -26
- data/spec/vcr_cassettes/invoices/save_new_with_unsaved_parent.yml +65 -0
- data/spec/vcr_cassettes/invoices/save_old.yml +41 -24
- data/spec/vcr_cassettes/invoices/save_old_with_empty_comments.yml +41 -24
- data/spec/vcr_cassettes/invoices/save_old_with_empty_country.yml +37 -29
- data/spec/vcr_cassettes/invoices/save_old_with_nil_comments.yml +41 -24
- data/spec/vcr_cassettes/invoices/save_old_with_nil_country.yml +37 -29
- data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +40 -21
- data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +39 -20
- data/spec/vcr_cassettes/invoices/search_by_name.yml +38 -27
- data/spec/vcr_cassettes/invoices/search_miss.yml +36 -19
- data/spec/vcr_cassettes/invoices/search_with_special_char.yml +36 -19
- data/spec/vcr_cassettes/invoices/single_param_find_by_hash.yml +39 -22
- data/spec/vcr_cassettes/orders/all.yml +44 -119
- data/spec/vcr_cassettes/orders/filter_hit.yml +39 -26
- data/spec/vcr_cassettes/orders/filter_invalid.yml +35 -17
- data/spec/vcr_cassettes/orders/find_by_hash_failure.yml +36 -19
- data/spec/vcr_cassettes/orders/find_failure.yml +36 -19
- data/spec/vcr_cassettes/orders/find_id_1.yml +42 -23
- data/spec/vcr_cassettes/orders/find_new.yml +41 -24
- data/spec/vcr_cassettes/orders/housework_invalid_tax_reduction_type.yml +61 -0
- data/spec/vcr_cassettes/orders/housework_othercoses_invalid.yml +61 -0
- data/spec/vcr_cassettes/orders/housework_type_babysitting.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_cleaning.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_construction.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_cooking.yml +36 -18
- data/spec/vcr_cassettes/orders/housework_type_electricity.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_gardening.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_glassmetalwork.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_grounddrainagework.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_hvac.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_itservices.yml +65 -0
- data/spec/vcr_cassettes/orders/housework_type_majorappliancerepair.yml +65 -0
- data/spec/vcr_cassettes/orders/housework_type_masonry.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_movingservices.yml +65 -0
- data/spec/vcr_cassettes/orders/housework_type_othercare.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_othercosts.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_paintingwallpapering.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_snowplowing.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_textileclothing.yml +40 -21
- data/spec/vcr_cassettes/orders/housework_type_tutoring.yml +36 -18
- data/spec/vcr_cassettes/orders/multi_param_find_by_hash.yml +38 -21
- data/spec/vcr_cassettes/orders/save_new.yml +40 -22
- data/spec/vcr_cassettes/orders/save_old.yml +41 -24
- data/spec/vcr_cassettes/orders/save_with_nested_model.yml +40 -21
- data/spec/vcr_cassettes/orders/search_by_name.yml +38 -23
- data/spec/vcr_cassettes/orders/search_miss.yml +36 -19
- data/spec/vcr_cassettes/orders/search_with_special_char.yml +36 -19
- data/spec/vcr_cassettes/orders/single_param_find_by_hash.yml +39 -22
- data/spec/vcr_cassettes/projects/all.yml +39 -37
- data/spec/vcr_cassettes/projects/find_by_hash_failure.yml +36 -19
- data/spec/vcr_cassettes/projects/find_failure.yml +36 -19
- data/spec/vcr_cassettes/projects/find_id_1.yml +38 -21
- data/spec/vcr_cassettes/projects/find_new.yml +39 -22
- data/spec/vcr_cassettes/projects/multi_param_find_by_hash.yml +40 -22
- data/spec/vcr_cassettes/projects/save_new.yml +37 -19
- data/spec/vcr_cassettes/projects/save_old.yml +39 -22
- data/spec/vcr_cassettes/projects/single_param_find_by_hash.yml +38 -21
- data/spec/vcr_cassettes/termsofpayments/all.yml +43 -29
- data/spec/vcr_cassettes/termsofpayments/find_failure.yml +36 -19
- data/spec/vcr_cassettes/termsofpayments/find_id_1.yml +38 -22
- data/spec/vcr_cassettes/termsofpayments/find_new.yml +38 -21
- data/spec/vcr_cassettes/termsofpayments/save_new.yml +37 -19
- data/spec/vcr_cassettes/termsofpayments/save_old.yml +38 -21
- data/spec/vcr_cassettes/units/all.yml +38 -26
- data/spec/vcr_cassettes/units/find_failure.yml +36 -19
- data/spec/vcr_cassettes/units/find_id_1.yml +38 -21
- data/spec/vcr_cassettes/units/find_new.yml +38 -21
- data/spec/vcr_cassettes/units/save_new.yml +37 -19
- data/spec/vcr_cassettes/units/save_old.yml +38 -21
- data/spec/vcr_cassettes/units/save_with_specially_named_attribute.yml +37 -19
- metadata +133 -252
- data/lib/fortnox/api/circular_queue.rb +0 -39
- data/spec/fortnox/api/circular_queue_spec.rb +0 -52
- data/spec/support/helpers/dummy_class_helper.rb +0 -38
- data/spec/support/helpers/when_performing_helper.rb +0 -7
- data/spec/vcr_cassettes/invoices/save_new_with_country_KR.yml +0 -57
- data/temp.txt +0 -1
@@ -2,388 +2,167 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
require 'fortnox/api'
|
5
|
+
require 'jwt'
|
6
|
+
require 'dry/container/stub'
|
5
7
|
|
6
|
-
describe Fortnox::API::Repository::Base do
|
7
|
-
|
8
|
-
module Model
|
9
|
-
class RepositoryBaseTest
|
10
|
-
end
|
11
|
-
end
|
12
|
-
module Repository
|
13
|
-
class Test < Fortnox::API::Repository::Base
|
14
|
-
MODEL = Model::RepositoryBaseTest
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
8
|
+
describe Fortnox::API::Repository::Base, integration: true do
|
9
|
+
include Helpers::Configuration
|
18
10
|
|
19
11
|
before do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
after do
|
24
|
-
# HACK: Currently, there is no way to remove keys from the Dry::Container#register.
|
25
|
-
# We could move the register call to a before(:all) hook, but that registered key
|
26
|
-
# would then leak into other tests. Instead, we can simply delete it with this little hack :)
|
27
|
-
Fortnox::API::Registry._container.delete('repositorybasetest')
|
28
|
-
end
|
29
|
-
|
30
|
-
let(:access_token) { '3f08d038-f380-4893-94a0-a08f6e60e67a' }
|
31
|
-
let(:access_token2) { '89feajou-sif8-8f8u-29ja-xdfniokeniod' }
|
32
|
-
let(:client_secret) { 'P5K5vE3Kun' }
|
33
|
-
let(:repository) { Repository::Test.new }
|
34
|
-
let(:application_json) {}
|
35
|
-
let(:headers) do
|
36
|
-
{
|
37
|
-
'Access-Token' => access_token,
|
38
|
-
'Client-Secret' => client_secret,
|
39
|
-
'Content-Type' => 'application/json',
|
40
|
-
'Accept' => 'application/json'
|
41
|
-
}
|
42
|
-
end
|
43
|
-
|
44
|
-
describe 'creation' do
|
45
|
-
shared_examples_for 'missing configuration' do
|
46
|
-
subject { -> { Repository::Test.new(token_store: :store1).get('nonsense') } }
|
47
|
-
|
48
|
-
let(:error) { Fortnox::API::MissingConfiguration }
|
49
|
-
|
50
|
-
it { is_expected.to raise_error(error, /#{message}/) }
|
51
|
-
end
|
52
|
-
|
53
|
-
context 'without base url' do
|
54
|
-
include_examples 'missing configuration' do
|
55
|
-
before do
|
56
|
-
Fortnox::API.configure do |config|
|
57
|
-
config.base_url = nil
|
58
|
-
config.client_secret = client_secret
|
59
|
-
config.access_tokens = { store1: access_token }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
let(:message) { 'have to provide a base url' }
|
64
|
-
end
|
65
|
-
end
|
12
|
+
stub_const('TestModel', Class.new)
|
13
|
+
stub_const('TestRepository', Class.new(described_class))
|
14
|
+
stub_const('TestRepository::MODEL', TestModel)
|
66
15
|
|
67
|
-
|
68
|
-
include_examples 'missing configuration' do
|
69
|
-
before do
|
70
|
-
Fortnox::API.configure do |config|
|
71
|
-
config.client_secret = nil
|
72
|
-
config.access_tokens = { store1: access_token }
|
73
|
-
end
|
74
|
-
end
|
16
|
+
Fortnox::API::Registry.enable_stubs!
|
75
17
|
|
76
|
-
|
77
|
-
end
|
78
|
-
end
|
18
|
+
add_to_registry(:testmodel, TestModel)
|
79
19
|
end
|
80
20
|
|
81
|
-
|
82
|
-
before { Fortnox::API.configure { |conf| conf.client_secret = client_secret } }
|
83
|
-
|
84
|
-
context 'with default token store' do
|
85
|
-
context 'with one access token' do
|
86
|
-
subject { repository.next_access_token }
|
87
|
-
|
88
|
-
before { Fortnox::API.configure { |conf| conf.access_token = access_token } }
|
89
|
-
|
90
|
-
it { is_expected.to eql(access_token) }
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'with one access token and two subsequent requests' do
|
94
|
-
subject { repository.next_access_token }
|
21
|
+
let(:repository) { TestRepository.new }
|
95
22
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
23
|
+
describe '#initialize' do
|
24
|
+
context 'without providing an access token' do
|
25
|
+
before { Fortnox::API.access_token = nil }
|
100
26
|
|
101
|
-
|
102
|
-
|
103
|
-
end
|
27
|
+
it 'raises an error' do
|
28
|
+
expect { TestRepository.new }.to raise_error(Fortnox::API::MissingAccessToken)
|
104
29
|
end
|
105
|
-
|
106
|
-
context 'with multiple access tokens' do
|
107
|
-
subject { access_tokens }
|
108
|
-
|
109
|
-
before { Fortnox::API.configure { |conf| conf.access_tokens = access_tokens } }
|
110
|
-
let(:access_tokens) { [access_token, access_token2] }
|
111
|
-
|
112
|
-
it { is_expected.to include(repository.next_access_token) }
|
113
|
-
|
114
|
-
it 'changes token on next request' do
|
115
|
-
token1 = repository.next_access_token
|
116
|
-
token2 = repository.next_access_token
|
117
|
-
|
118
|
-
expect(token1).not_to eql(token2)
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'circulates tokens' do
|
122
|
-
token1 = repository.next_access_token
|
123
|
-
repository.next_access_token
|
124
|
-
token3 = repository.next_access_token
|
125
|
-
|
126
|
-
expect(token1).to eql(token3)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
context 'with multiple stores' do
|
132
|
-
subject { repository.next_access_token }
|
133
|
-
|
134
|
-
before do
|
135
|
-
Fortnox::API.configure do |config|
|
136
|
-
config.access_tokens = { store1: access_token, store2: access_token2 }
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe 'first token store' do
|
141
|
-
let(:repository) { Repository::Test.new(token_store: :store1) }
|
142
|
-
|
143
|
-
it { is_expected.to eql access_token }
|
144
|
-
end
|
145
|
-
|
146
|
-
describe 'second token store' do
|
147
|
-
let(:repository) { Repository::Test.new(token_store: :store2) }
|
148
|
-
|
149
|
-
it { is_expected.to eql access_token2 }
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
describe '#access_tokens' do
|
155
|
-
subject(:access_tokens) { repository.access_tokens }
|
156
|
-
|
157
|
-
before { Fortnox::API.configure { |conf| conf.client_secret = client_secret } }
|
158
|
-
|
159
|
-
let(:token_store_not_present) do
|
160
|
-
"There is no token store named #{token_store.inspect}. Available stores are #{available_stores}."
|
161
|
-
end
|
162
|
-
|
163
|
-
let(:error) { Fortnox::API::MissingConfiguration }
|
164
|
-
|
165
|
-
context 'with non existing token store' do
|
166
|
-
subject { -> { access_tokens } }
|
167
|
-
|
168
|
-
before do
|
169
|
-
Fortnox::API.configure { |conf| conf.access_tokens = { some_store: [access_token] } }
|
170
|
-
end
|
171
|
-
|
172
|
-
let(:repository) { Repository::Test.new(token_store: token_store) }
|
173
|
-
let(:token_store) { :non_existing_store }
|
174
|
-
let(:available_stores) { [:some_store] }
|
175
|
-
|
176
|
-
it { is_expected.to raise_error(error, token_store_not_present) }
|
177
|
-
end
|
178
|
-
|
179
|
-
context 'with no tokens set' do
|
180
|
-
subject { -> { access_tokens } }
|
181
|
-
|
182
|
-
before { Fortnox::API.configure { |conf| conf.access_tokens = {} } }
|
183
|
-
let(:token_store) { :default }
|
184
|
-
let(:available_stores) { [] }
|
185
|
-
|
186
|
-
it { is_expected.to raise_error(error, token_store_not_present) }
|
187
|
-
end
|
188
|
-
|
189
|
-
context 'with one access token in token store' do
|
190
|
-
before { Fortnox::API.configure { |conf| conf.access_token = access_token } }
|
191
|
-
let(:token_store) { :default }
|
192
|
-
|
193
|
-
it { is_expected.to eql(access_token) }
|
194
|
-
end
|
195
|
-
|
196
|
-
context 'with multiple access tokens' do
|
197
|
-
before do
|
198
|
-
Fortnox::API.configure { |conf| conf.access_tokens = [access_token, access_token2] }
|
199
|
-
end
|
200
|
-
let(:token_store) { :default }
|
201
|
-
|
202
|
-
it { is_expected.to eql([access_token, access_token2]) }
|
203
30
|
end
|
204
31
|
|
205
|
-
context 'with
|
206
|
-
before
|
207
|
-
Fortnox::API.configure do |conf|
|
208
|
-
conf.access_tokens = { store_a: store_a_tokens, store_b: store_b_token }
|
209
|
-
end
|
210
|
-
end
|
211
|
-
let(:store_a_tokens) { %w[token_a1 token_a2] }
|
212
|
-
let(:store_b_token) { 'token_b1' }
|
213
|
-
|
214
|
-
context 'with valid store name' do
|
215
|
-
let(:repository) { Repository::Test.new(token_store: :store_a) }
|
216
|
-
|
217
|
-
it { is_expected.to eql(store_a_tokens) }
|
218
|
-
end
|
219
|
-
|
220
|
-
context 'with non collection' do
|
221
|
-
let(:repository) { Repository::Test.new(token_store: :store_b) }
|
222
|
-
|
223
|
-
it { is_expected.to eql(store_b_token) }
|
224
|
-
end
|
225
|
-
|
226
|
-
context 'with invalid store name' do
|
227
|
-
subject { -> { access_tokens } }
|
32
|
+
context 'with expired access token' do
|
33
|
+
before { Fortnox::API.access_token = ENV.fetch('EXPIRED_ACCESS_TOKEN') }
|
228
34
|
|
229
|
-
|
230
|
-
|
231
|
-
|
35
|
+
it 'raises an error' do
|
36
|
+
expect do
|
37
|
+
VCR.use_cassette('authentication/expired_token') { repository.get('/customers', body: '') }
|
38
|
+
end.to raise_error(Fortnox::API::RemoteServerError, /Unauthorized request(.)*"message":"unauthorized"/)
|
232
39
|
end
|
233
40
|
end
|
234
41
|
end
|
235
42
|
|
236
|
-
describe '#check_access_tokens!' do
|
237
|
-
subject { -> { repository.check_access_tokens!(tokens) } }
|
238
|
-
|
239
|
-
before { Fortnox::API.configure { |conf| conf.client_secret = client_secret } }
|
240
|
-
let(:error) { Fortnox::API::MissingConfiguration }
|
241
|
-
let(:message) { "not provided any access tokens in token store #{token_store.inspect}" }
|
242
|
-
let(:token_store) { :default }
|
243
|
-
|
244
|
-
context 'with nil' do
|
245
|
-
let(:tokens) { nil }
|
246
|
-
|
247
|
-
it { is_expected.to raise_error(error, /#{message}/) }
|
248
|
-
end
|
249
|
-
|
250
|
-
context 'with empty array' do
|
251
|
-
let(:tokens) { [] }
|
252
|
-
|
253
|
-
it { is_expected.to raise_error(error, /#{message}/) }
|
254
|
-
end
|
255
|
-
|
256
|
-
context 'with an empty, non default, token store' do
|
257
|
-
before { Fortnox::API.configure { |conf| conf.access_tokens = { token_store => tokens } } }
|
258
|
-
let(:repository) { Repository::Test.new(token_store: token_store) }
|
259
|
-
let(:tokens) { [] }
|
260
|
-
let(:token_store) { :store1 }
|
261
|
-
|
262
|
-
it { is_expected.to raise_error(error, /#{message}/) }
|
263
|
-
end
|
264
|
-
|
265
|
-
context 'with valid tokens' do
|
266
|
-
let(:tokens) { %w[12345 abcde] }
|
267
|
-
|
268
|
-
it { is_expected.not_to raise_error }
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
43
|
context 'when making a request including the proper headers' do
|
44
|
+
subject { repository.get('/test', body: '') }
|
45
|
+
|
273
46
|
before do
|
274
|
-
|
275
|
-
conf.client_secret = client_secret
|
276
|
-
conf.access_token = access_token
|
277
|
-
end
|
47
|
+
set_api_test_configuration
|
278
48
|
|
279
49
|
stub_request(
|
280
50
|
:get,
|
281
51
|
'https://api.fortnox.se/3/test'
|
282
|
-
).with(
|
283
|
-
headers: headers
|
284
52
|
).to_return(
|
285
53
|
status: 200
|
286
54
|
)
|
287
55
|
end
|
288
56
|
|
289
|
-
subject { repository.get('/test', body: '') }
|
290
|
-
|
291
57
|
it { is_expected.to be_nil }
|
292
58
|
end
|
293
59
|
|
294
|
-
|
60
|
+
context 'when receiving an error from remote server' do
|
295
61
|
before do
|
296
|
-
|
297
|
-
conf.client_secret = client_secret
|
298
|
-
conf.access_tokens = [access_token, access_token2]
|
299
|
-
end
|
62
|
+
set_api_test_configuration
|
300
63
|
|
301
64
|
stub_request(
|
302
|
-
:
|
65
|
+
:post,
|
303
66
|
'https://api.fortnox.se/3/test'
|
304
|
-
).with(
|
305
|
-
headers: {
|
306
|
-
'Access-Token' => access_token,
|
307
|
-
'Client-Secret' => client_secret,
|
308
|
-
'Content-Type' => 'application/json',
|
309
|
-
'Accept' => 'application/json'
|
310
|
-
}
|
311
67
|
).to_return(
|
312
|
-
status:
|
313
|
-
body:
|
68
|
+
status: 500,
|
69
|
+
body: {
|
70
|
+
'ErrorInformation' => {
|
71
|
+
'error' => 1,
|
72
|
+
'message' => 'some-error-message'
|
73
|
+
}
|
74
|
+
}.to_json,
|
75
|
+
headers: { 'Content-Type' => 'application/json' }
|
314
76
|
)
|
77
|
+
end
|
315
78
|
|
316
|
-
|
317
|
-
|
318
|
-
'
|
319
|
-
|
320
|
-
headers: {
|
321
|
-
'Access-Token' => access_token2,
|
322
|
-
'Client-Secret' => client_secret,
|
323
|
-
'Content-Type' => 'application/json',
|
324
|
-
'Accept' => 'application/json'
|
325
|
-
}
|
326
|
-
).to_return(
|
327
|
-
status: 200,
|
328
|
-
body: '2'
|
329
|
-
)
|
79
|
+
it 'raises an error' do
|
80
|
+
expect do
|
81
|
+
repository.post('/test', body: '')
|
82
|
+
end.to raise_error(Fortnox::API::RemoteServerError, /some-error-message/)
|
330
83
|
end
|
331
84
|
|
332
|
-
context 'with
|
333
|
-
|
334
|
-
|
335
|
-
let!(:response3) { repository.get('/test', body: '') }
|
85
|
+
context 'with debugging enabled' do
|
86
|
+
before { Fortnox::API.config.debugging = true }
|
87
|
+
after { Fortnox::API.config.debugging = false }
|
336
88
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
expect(response1).not_to eq(response2)
|
342
|
-
expect(response1).to eq(response3)
|
343
|
-
expect(response3).not_to eq(response2)
|
89
|
+
it do
|
90
|
+
expect do
|
91
|
+
repository.post('/test', body: '')
|
92
|
+
end.to raise_error(/<HTTParty::Request:0x/)
|
344
93
|
end
|
345
|
-
# rubocop:enable RSpec/MultipleExpectations
|
346
94
|
end
|
347
95
|
end
|
348
96
|
|
349
|
-
context 'when
|
350
|
-
error_message = 'Räkenskapsår finns inte upplagt. '\
|
351
|
-
'För att kunna skapa en faktura krävs det att det finns ett räkenskapsår'
|
352
|
-
|
97
|
+
context 'when receiving HTML from remote server' do
|
353
98
|
before do
|
354
|
-
|
355
|
-
conf.client_secret = client_secret
|
356
|
-
conf.access_tokens = [access_token, access_token2]
|
357
|
-
end
|
99
|
+
set_api_test_configuration
|
358
100
|
|
359
101
|
stub_request(
|
360
|
-
:
|
361
|
-
'https://api.fortnox.se/
|
102
|
+
:get,
|
103
|
+
'https://api.fortnox.se/3nonsense'
|
362
104
|
).to_return(
|
363
|
-
status:
|
364
|
-
body:
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
}.to_json,
|
370
|
-
headers: { 'Content-Type' => 'application/json' }
|
105
|
+
status: 404,
|
106
|
+
body: "<html>\r\n" \
|
107
|
+
"<head><title>404 Not Found</title></head>\r\n" \
|
108
|
+
"<body>\r\n<center><h1>404 Not Found</h1></center>\r\n" \
|
109
|
+
"<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n",
|
110
|
+
headers: { 'Content-Type' => 'text/html' }
|
371
111
|
)
|
372
112
|
end
|
373
113
|
|
374
|
-
|
114
|
+
it 'raises an error' do
|
115
|
+
expect do
|
116
|
+
repository.get('nonsense')
|
117
|
+
end.to raise_error(Fortnox::API::RemoteServerError,
|
118
|
+
%r{Fortnox API's response has content type "text/html"})
|
119
|
+
end
|
120
|
+
end
|
375
121
|
|
376
|
-
|
377
|
-
|
122
|
+
describe 'update existing' do
|
123
|
+
context 'with no change' do
|
124
|
+
before do
|
125
|
+
set_api_test_configuration
|
378
126
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
127
|
+
stub_const(
|
128
|
+
'Product',
|
129
|
+
Class.new(Fortnox::API::Model::Base) do
|
130
|
+
attribute :name, 'strict.string'
|
131
|
+
attribute :description, 'string' # nullable
|
132
|
+
end
|
133
|
+
)
|
134
|
+
stub_const('Product::STUB', { name: '' }.freeze)
|
135
|
+
stub_const('Product::UNIQUE_ID', :name)
|
136
|
+
|
137
|
+
stub_const('ProductMapper', Class.new(Fortnox::API::Mapper::Base))
|
138
|
+
stub_const('ProductMapper::JSON_ENTITY_WRAPPER', 'Product')
|
139
|
+
stub_const('ProductMapper::JSON_COLLECTION_WRAPPER', 'Products')
|
140
|
+
stub_const('ProductMapper::KEY_MAP', {})
|
141
|
+
|
142
|
+
stub_const('TestRepository::MODEL', Product)
|
143
|
+
stub_const('TestRepository::MAPPER', ProductMapper)
|
144
|
+
stub_const('TestRepository::URI', '/test/')
|
145
|
+
|
146
|
+
Fortnox::API::Registry.enable_stubs!
|
147
|
+
add_to_registry(:product, ProductMapper)
|
148
|
+
|
149
|
+
stub_request(
|
150
|
+
:post,
|
151
|
+
'https://api.fortnox.se/3/test/'
|
152
|
+
).to_return(
|
153
|
+
status: 200,
|
154
|
+
body: '{"Product" : {"Name": "test", "Desription": null}}',
|
155
|
+
headers: { 'Content-Type' => 'application/json' }
|
156
|
+
).times(1) # Only stub the first save request
|
157
|
+
end
|
158
|
+
|
159
|
+
let(:updated_entity) do
|
160
|
+
repository.save(Product.new(name: 'test')).update({ description: nil })
|
384
161
|
end
|
385
162
|
|
386
|
-
it
|
163
|
+
it 'does not call Fortnox' do
|
164
|
+
expect { repository.save(updated_entity) }.not_to raise_error
|
165
|
+
end
|
387
166
|
end
|
388
167
|
end
|
389
168
|
end
|
@@ -10,13 +10,14 @@ require 'fortnox/api/repositories/examples/save'
|
|
10
10
|
require 'fortnox/api/repositories/examples/save_with_specially_named_attribute'
|
11
11
|
require 'fortnox/api/repositories/examples/search'
|
12
12
|
|
13
|
-
describe Fortnox::API::Repository::Customer,
|
13
|
+
describe Fortnox::API::Repository::Customer, integration: true, order: :defined do
|
14
14
|
include Helpers::Configuration
|
15
|
-
|
16
|
-
before { set_api_test_configuration }
|
15
|
+
include Helpers::Repositories
|
17
16
|
|
18
17
|
subject(:repository) { described_class.new }
|
19
18
|
|
19
|
+
before { set_api_test_configuration }
|
20
|
+
|
20
21
|
include_examples '.save', :name
|
21
22
|
|
22
23
|
include_examples '.save with specially named attribute',
|
@@ -24,11 +25,12 @@ describe Fortnox::API::Repository::Customer, order: :defined, integration: true
|
|
24
25
|
:email_invoice_cc,
|
25
26
|
'test@example.com'
|
26
27
|
|
27
|
-
# It is not yet possible to delete Customers. Therefore, expected nr of
|
28
|
+
# VCR: It is not yet possible to delete Customers. Therefore, expected nr of
|
28
29
|
# Customers when running .all will continue to increase
|
29
30
|
# (until 100, which is max by default).
|
30
|
-
include_examples '.all',
|
31
|
+
include_examples '.all', 7
|
31
32
|
|
33
|
+
# VCR: Searched Customers needs to be created manually
|
32
34
|
include_examples '.find', '1' do
|
33
35
|
let(:find_by_hash_failure) { { city: 'Not Found' } }
|
34
36
|
let(:single_param_find_by_hash) { { find_hash: { city: 'New York' }, matches: 2 } }
|
@@ -38,8 +40,8 @@ describe Fortnox::API::Repository::Customer, order: :defined, integration: true
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
# When recording new VCR casettes, expected matches must be increased
|
42
|
-
include_examples '.search', :name, 'Test',
|
43
|
+
# NOTE: When recording new VCR casettes, expected matches must be increased
|
44
|
+
include_examples '.search', :name, 'Test', 2
|
43
45
|
|
44
46
|
describe 'country reference' do
|
45
47
|
describe 'with valid country code \'SE\'' do
|
@@ -67,4 +69,32 @@ describe Fortnox::API::Repository::Customer, order: :defined, integration: true
|
|
67
69
|
end
|
68
70
|
end
|
69
71
|
end
|
72
|
+
|
73
|
+
describe 'sales account' do
|
74
|
+
# VCR: The Sales Account needs to be created manually in Fortnox
|
75
|
+
context 'when saving a Customer with a Sales Account set' do
|
76
|
+
let(:customer) do
|
77
|
+
VCR.use_cassette("#{vcr_dir}/save_new_with_sales_account") do
|
78
|
+
repository.save(
|
79
|
+
described_class::MODEL.new(
|
80
|
+
name: 'Customer with Sales Account',
|
81
|
+
sales_account: '3001'
|
82
|
+
)
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'when fetching that Customer' do
|
88
|
+
subject { fetched_customer.sales_account }
|
89
|
+
|
90
|
+
let(:fetched_customer) do
|
91
|
+
VCR.use_cassette("#{vcr_dir}/find_with_sales_account") do
|
92
|
+
repository.find(customer.customer_number)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it { is_expected.to eq('3001') }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
70
100
|
end
|
@@ -28,16 +28,13 @@ shared_examples_for '.find' do |searched_entity_id, find_by_hash: true|
|
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'when not found' do
|
31
|
-
|
32
|
-
|
33
|
-
let(:not_found_id) { '123456789' }
|
34
|
-
let(:find_failure) do
|
35
|
-
when_performing do
|
36
|
-
VCR.use_cassette("#{vcr_dir}/find_failure") { repository.find(not_found_id) }
|
37
|
-
end
|
31
|
+
let(:find_with_non_existing_id) do
|
32
|
+
VCR.use_cassette("#{vcr_dir}/find_failure") { repository.find('123456789') }
|
38
33
|
end
|
39
34
|
|
40
|
-
|
35
|
+
specify do
|
36
|
+
expect { find_with_non_existing_id }.to raise_error(Fortnox::API::RemoteServerError, /Kan inte hitta /)
|
37
|
+
end
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
@@ -2,14 +2,8 @@
|
|
2
2
|
|
3
3
|
shared_examples_for '.only' do |matching_filter, expected_matches, missing_filter: nil|
|
4
4
|
describe '.only' do
|
5
|
-
def repository_only(repository, vcr_cassette, filter)
|
6
|
-
VCR.use_cassette("#{vcr_dir}/#{vcr_cassette}") do
|
7
|
-
repository.only(filter)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
5
|
shared_examples '.only response' do |vcr_cassette, expected_entries|
|
12
|
-
subject {
|
6
|
+
subject { VCR.use_cassette("#{vcr_dir}/#{vcr_cassette}") { repository.only(filter) } }
|
13
7
|
|
14
8
|
it { is_expected.to be_instance_of(Array) }
|
15
9
|
it { is_expected.to have(expected_entries).entries }
|
@@ -30,14 +24,11 @@ shared_examples_for '.only' do |matching_filter, expected_matches, missing_filte
|
|
30
24
|
end
|
31
25
|
|
32
26
|
context 'with invalid filter' do
|
33
|
-
|
34
|
-
|
35
|
-
repository_only(repository, 'filter_invalid', 'doesntexist')
|
36
|
-
end
|
27
|
+
let(:only_with_invalid_filter) do
|
28
|
+
VCR.use_cassette("#{vcr_dir}/filter_invalid") { repository.only('doesntexist') }
|
37
29
|
end
|
38
30
|
|
39
|
-
|
31
|
+
specify { expect { only_with_invalid_filter }.to raise_error(Fortnox::API::RemoteServerError, /ogiltigt filter/) }
|
40
32
|
end
|
41
33
|
end
|
42
34
|
end
|
43
|
-
# rubocop:enable RSpec/DescribeClass
|