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
@@ -8,14 +8,12 @@ describe Fortnox::API::Mapper::FromJSON do
|
|
8
8
|
include_context 'with JSON conversion'
|
9
9
|
|
10
10
|
before do
|
11
|
-
|
12
|
-
|
13
|
-
include Fortnox::API::Mapper::FromJSON
|
14
|
-
end
|
11
|
+
Test::BaseMapper.class_eval do
|
12
|
+
include Fortnox::API::Mapper::FromJSON # rubocop:disable RSpec/DescribedClass
|
15
13
|
end
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
add_to_registry(:categories, Test::CategoryMapper)
|
16
|
+
add_to_registry(:designer, Test::ProductDesignerMapper)
|
19
17
|
end
|
20
18
|
|
21
19
|
let(:mapper) { Test::ProductMapper.new }
|
@@ -26,10 +24,10 @@ describe Fortnox::API::Mapper::FromJSON do
|
|
26
24
|
{
|
27
25
|
'Product' => {
|
28
26
|
'@url': 'someurl@example.com',
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
Name: 'Ford Mustang',
|
28
|
+
VAT: 30_000,
|
29
|
+
Categories: [{ Name: 'Cars', ID: '1' }, { Name: 'Fast cars', ID: '2' }],
|
30
|
+
Designer: { Name: 'John Najjar', ID: '23' }
|
33
31
|
}
|
34
32
|
}
|
35
33
|
end
|
@@ -47,7 +45,7 @@ describe Fortnox::API::Mapper::FromJSON do
|
|
47
45
|
# expect( entity_hash[:url] ).to eq 'someurl@example.com'
|
48
46
|
# end
|
49
47
|
|
50
|
-
|
48
|
+
describe 'nested models' do
|
51
49
|
let(:expected_nested_model_hash) do
|
52
50
|
[{ name: 'Cars', id: '1' }, { name: 'Fast cars', id: '2' }]
|
53
51
|
end
|
@@ -57,7 +55,7 @@ describe Fortnox::API::Mapper::FromJSON do
|
|
57
55
|
end
|
58
56
|
end
|
59
57
|
|
60
|
-
|
58
|
+
describe 'nested model' do
|
61
59
|
let(:expected_nested_model_hash) { { name: 'John Najjar', id: '23' } }
|
62
60
|
|
63
61
|
specify 'is converted correctly' do
|
@@ -5,73 +5,64 @@ require 'fortnox/api/mappers/base/to_json'
|
|
5
5
|
require 'fortnox/api/mappers/contexts/json_conversion'
|
6
6
|
|
7
7
|
describe Fortnox::API::Mapper::ToJSON do
|
8
|
-
|
9
|
-
# "NoMethodError: undefined method `call\' for Test::ProductMapper:Class`"
|
10
|
-
it 'should be tested when random error is fixed!'
|
8
|
+
include_context 'with JSON conversion'
|
11
9
|
|
12
|
-
|
13
|
-
|
10
|
+
before do
|
11
|
+
Test::BaseMapper.class_eval do
|
12
|
+
include Fortnox::API::Mapper::ToJSON # rubocop:disable RSpec/DescribedClass
|
13
|
+
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
let(:mapper) { Test::ProductMapper.new }
|
17
17
|
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
# end
|
24
|
-
# end
|
18
|
+
describe '#entity_to_hash' do
|
19
|
+
let(:product) do
|
20
|
+
category1 = Test::Category.new(name: 'Cars', id: '1')
|
21
|
+
category2 = Test::Category.new(name: 'Fast Cars', id: '2')
|
22
|
+
product_designer = Test::ProductDesigner.new(name: 'John Najjar', id: '23')
|
25
23
|
|
26
|
-
|
24
|
+
Test::Product.new(url: 'someurl@example.com',
|
25
|
+
name: 'Ford Mustang',
|
26
|
+
vat: 30_000.0,
|
27
|
+
categories: [category1, category2],
|
28
|
+
designer: product_designer)
|
29
|
+
end
|
30
|
+
let(:keys_to_filter) { [:url] }
|
31
|
+
let(:returned_hash) { mapper.entity_to_hash(product, keys_to_filter) }
|
32
|
+
let(:inner_hash) { returned_hash['Product'] }
|
27
33
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# let( :product_designer ){ Test::ProductDesigner.new( name: 'John Najjar', id: '23' ) }
|
32
|
-
# let( :product ) do
|
33
|
-
# Test::Product.new( url: 'someurl@example.com',
|
34
|
-
# name: 'Ford Mustang',
|
35
|
-
# vat: 30000.0 ,
|
36
|
-
# categories: [category1, category2],
|
37
|
-
# designer: product_designer )
|
38
|
-
# end
|
39
|
-
# let( :keys_to_filter ){ [:url] }
|
40
|
-
# let( :returned_hash ){ mapper.entity_to_hash( product, keys_to_filter ) }
|
41
|
-
# let( :inner_hash ){ returned_hash['Product'] }
|
34
|
+
it 'includes JSON entity wrapper' do
|
35
|
+
expect(returned_hash).to have_key('Product')
|
36
|
+
end
|
42
37
|
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
describe 'keys without mapping' do
|
39
|
+
specify 'converts correctly' do
|
40
|
+
expect(inner_hash['Name']).to eq('Ford Mustang')
|
41
|
+
end
|
42
|
+
end
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
describe 'keys to filter' do
|
45
|
+
specify 'filteres out those keys' do
|
46
|
+
expect(inner_hash).not_to have_key('@url')
|
47
|
+
end
|
48
|
+
end
|
52
49
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# end
|
50
|
+
describe 'nested models' do
|
51
|
+
let(:expected_nested_model_hash) do
|
52
|
+
[{ 'Name' => 'Cars', 'ID' => '1' }, { 'Name' => 'Fast Cars', 'ID' => '2' }]
|
53
|
+
end
|
58
54
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
specify 'are converted correctly' do
|
56
|
+
expect(inner_hash['Categories']).to eq(expected_nested_model_hash)
|
57
|
+
end
|
58
|
+
end
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
# end
|
67
|
-
# end
|
60
|
+
describe 'nested model' do
|
61
|
+
let(:expected_nested_model_hash) { { 'Name' => 'John Najjar', 'ID' => '23' } }
|
68
62
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
# end
|
75
|
-
# end
|
76
|
-
# end
|
63
|
+
specify 'is converted correctly' do
|
64
|
+
expect(inner_hash['Designer']).to eq(expected_nested_model_hash)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
77
68
|
end
|
@@ -99,6 +99,7 @@ describe Fortnox::API::Mapper::Base do
|
|
99
99
|
let(:value) { true }
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
102
103
|
describe 'falseclass' do
|
103
104
|
include_examples 'identity mapper', :falseclass do
|
104
105
|
let(:value) { false }
|
@@ -126,17 +127,15 @@ describe Fortnox::API::Mapper::Base do
|
|
126
127
|
|
127
128
|
describe 'special cases' do
|
128
129
|
context 'with SE' do
|
129
|
-
subject { mapper.call('SE') }
|
130
|
-
|
131
130
|
it 'translates code to country name in Swedish' do
|
132
|
-
|
131
|
+
expect(mapper.call('SE')).to eq('Sverige')
|
133
132
|
end
|
134
133
|
end
|
135
134
|
|
136
135
|
context 'with nil value' do
|
137
136
|
subject { mapper.call(nil) }
|
138
137
|
|
139
|
-
it { is_expected.to
|
138
|
+
it { is_expected.to be_nil }
|
140
139
|
end
|
141
140
|
|
142
141
|
context 'with empty string' do
|
@@ -146,10 +145,8 @@ describe Fortnox::API::Mapper::Base do
|
|
146
145
|
end
|
147
146
|
|
148
147
|
context 'with nonsense' do
|
149
|
-
subject { -> { mapper.call('nonsense') } }
|
150
|
-
|
151
148
|
it 'is not supported (since input is sanitised) and therefore blows up' do
|
152
|
-
raise_error(NoMethodError)
|
149
|
+
expect { mapper.call('nonsense') }.to raise_error(NoMethodError)
|
153
150
|
end
|
154
151
|
end
|
155
152
|
end
|
@@ -2,56 +2,61 @@
|
|
2
2
|
|
3
3
|
require 'fortnox/api'
|
4
4
|
require 'fortnox/api/mappers'
|
5
|
+
require 'dry/container/stub'
|
5
6
|
|
6
7
|
shared_context 'with JSON conversion' do
|
7
|
-
|
8
|
-
module Test
|
9
|
-
class BaseMapper
|
10
|
-
end
|
11
|
-
|
12
|
-
class CategoryMapper < BaseMapper
|
13
|
-
KEY_MAP = { id: 'ID' }.freeze
|
14
|
-
end
|
15
|
-
|
16
|
-
class ProductDesignerMapper < BaseMapper
|
17
|
-
KEY_MAP = { id: 'ID' }.freeze
|
18
|
-
end
|
19
|
-
|
20
|
-
class ProductMapper < BaseMapper
|
21
|
-
KEY_MAP = {
|
22
|
-
vat: 'VAT',
|
23
|
-
url: '@url' # TODO: How to handle url attribute?
|
24
|
-
}.freeze
|
25
|
-
JSON_ENTITY_WRAPPER = 'Product'
|
26
|
-
JSON_COLLECTION_WRAPPER = 'Products'
|
27
|
-
end
|
8
|
+
include Helpers::Configuration
|
28
9
|
|
29
|
-
|
10
|
+
before do
|
11
|
+
stub_const('Test::BaseMapper', Class.new)
|
12
|
+
|
13
|
+
stub_const('Test::CategoryMapper', Class.new(Test::BaseMapper))
|
14
|
+
stub_const('Test::CategoryMapper::KEY_MAP', { id: 'ID' }.freeze)
|
15
|
+
|
16
|
+
stub_const('Test::ProductDesignerMapper', Class.new(Test::BaseMapper))
|
17
|
+
stub_const('Test::ProductDesignerMapper::KEY_MAP', { id: 'ID' }.freeze)
|
18
|
+
|
19
|
+
stub_const('Test::ProductMapper', Class.new(Test::BaseMapper))
|
20
|
+
stub_const(
|
21
|
+
'Test::ProductMapper::KEY_MAP',
|
22
|
+
{
|
23
|
+
vat: 'VAT',
|
24
|
+
url: '@url' # TODO: How to handle url attribute?
|
25
|
+
}.freeze
|
26
|
+
)
|
27
|
+
stub_const('Test::ProductMapper::JSON_ENTITY_WRAPPER', 'Product')
|
28
|
+
stub_const('Test::ProductMapper::JSON_COLLECTION_WRAPPER', 'Products')
|
29
|
+
|
30
|
+
stub_const(
|
31
|
+
'Test::Category',
|
32
|
+
Class.new(Fortnox::API::Model::Base) do
|
30
33
|
attribute :name, 'strict.string'
|
31
34
|
attribute :id, 'strict.string'
|
32
35
|
end
|
36
|
+
)
|
33
37
|
|
34
|
-
|
38
|
+
stub_const(
|
39
|
+
'Test::ProductDesigner',
|
40
|
+
Class.new(Fortnox::API::Model::Base) do
|
35
41
|
attribute :name, 'strict.string'
|
36
42
|
attribute :id, 'strict.string'
|
37
43
|
end
|
44
|
+
)
|
38
45
|
|
39
|
-
|
46
|
+
stub_const(
|
47
|
+
'Test::Product',
|
48
|
+
Class.new(Fortnox::API::Model::Base) do
|
40
49
|
attribute :url, 'strict.string'
|
41
50
|
attribute :name, 'strict.string'
|
42
51
|
attribute :vat, 'strict.float'
|
43
52
|
attribute :categories, Dry::Types['coercible.array'].of(Test::Category)
|
44
53
|
attribute :designer, Test::ProductDesigner
|
45
54
|
end
|
46
|
-
|
47
|
-
|
48
|
-
def register_mapper(mapper_sym, mapper)
|
49
|
-
return if Fortnox::API::Registry.key? mapper_sym
|
50
|
-
Fortnox::API::Registry.register(mapper_sym, mapper)
|
51
|
-
end
|
55
|
+
)
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
57
|
+
Fortnox::API::Registry.enable_stubs!
|
58
|
+
add_to_registry(:category, Test::CategoryMapper)
|
59
|
+
add_to_registry(:productdesigner, Test::ProductDesignerMapper)
|
60
|
+
add_to_registry(:product, Test::ProductMapper)
|
56
61
|
end
|
57
62
|
end
|
@@ -8,7 +8,7 @@ require 'fortnox/api/mappers/examples/mapper'
|
|
8
8
|
describe Fortnox::API::Mapper::DefaultDeliveryTypes do
|
9
9
|
key_map = {}
|
10
10
|
|
11
|
-
it_behaves_like 'mapper', key_map do
|
11
|
+
it_behaves_like 'mapper', key_map, nil, nil do
|
12
12
|
let(:mapper) { described_class.new }
|
13
13
|
end
|
14
14
|
end
|
@@ -12,7 +12,7 @@ shared_examples_for 'mapper' do |key_map, json_entity_wrapper = nil, json_collec
|
|
12
12
|
describe 'key_map' do
|
13
13
|
subject { described_class::KEY_MAP }
|
14
14
|
|
15
|
-
it {
|
15
|
+
it { expect(subject).to eq(key_map) }
|
16
16
|
end
|
17
17
|
|
18
18
|
unless json_entity_wrapper.nil?
|
@@ -8,7 +8,6 @@ require 'fortnox/api/mappers/examples/mapper'
|
|
8
8
|
|
9
9
|
module Fortnox
|
10
10
|
module API
|
11
|
-
# Shhh Rubocop, we don't need a comment here ... Really
|
12
11
|
module Mapper
|
13
12
|
describe Unit do
|
14
13
|
context 'when mapping model' do
|
@@ -17,13 +16,13 @@ module Fortnox
|
|
17
16
|
let(:model_hash) { { code: 'lbs', description: 'Pounds' } }
|
18
17
|
|
19
18
|
describe '#entity_to_hash' do
|
20
|
-
subject {
|
19
|
+
subject { described_class.new.entity_to_hash(model, {}) }
|
21
20
|
|
22
21
|
it { is_expected.to eq(serialised_model_hash) }
|
23
22
|
end
|
24
23
|
|
25
24
|
describe '#wrapped_json_hash_to_entity_hash' do
|
26
|
-
subject {
|
25
|
+
subject { described_class.new.wrapped_json_hash_to_entity_hash(serialised_model_hash) }
|
27
26
|
|
28
27
|
it { is_expected.to eq(model_hash) }
|
29
28
|
end
|
@@ -46,7 +45,7 @@ module Fortnox
|
|
46
45
|
end
|
47
46
|
|
48
47
|
describe '#wrapped_json_collection_to_entities_hash' do
|
49
|
-
subject {
|
48
|
+
subject { described_class.new.wrapped_json_collection_to_entities_hash(serialised_collection_hash) }
|
50
49
|
|
51
50
|
it { is_expected.to eq(collection_hash) }
|
52
51
|
end
|
@@ -5,8 +5,8 @@ require 'fortnox/api/models/base'
|
|
5
5
|
require 'fortnox/api/types'
|
6
6
|
|
7
7
|
describe Fortnox::API::Model::Base do
|
8
|
-
|
9
|
-
|
8
|
+
let(:entity_class) do
|
9
|
+
Class.new(Fortnox::API::Model::Base) do
|
10
10
|
attribute :private, Fortnox::API::Types::String.is(:read_only)
|
11
11
|
attribute :string, Fortnox::API::Types::Required::String
|
12
12
|
attribute :number, Fortnox::API::Types::Nullable::Integer
|
@@ -16,43 +16,41 @@ describe Fortnox::API::Model::Base do
|
|
16
16
|
|
17
17
|
describe '.new' do
|
18
18
|
context 'with basic attribute' do
|
19
|
-
subject {
|
19
|
+
subject { entity_class.new(string: 'Test') }
|
20
20
|
|
21
|
-
it { is_expected.to be_a
|
21
|
+
it { is_expected.to be_a entity_class }
|
22
22
|
it { is_expected.to be_new }
|
23
23
|
it { is_expected.not_to be_saved }
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'without required attribute' do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
it do
|
28
|
+
expect do
|
29
|
+
entity_class.new({})
|
30
|
+
end.to raise_error Fortnox::API::MissingAttributeError, /Missing attribute :string/
|
31
|
+
end
|
32
32
|
end
|
33
33
|
|
34
34
|
context 'with invalid attribute value' do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
it do
|
36
|
+
expect do
|
37
|
+
entity_class.new(string: 'Test', account: 13_337)
|
38
|
+
end.to raise_error Fortnox::API::AttributeError, /invalid type for :account/
|
39
|
+
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
describe '.update' do
|
44
|
-
let(:original) {
|
44
|
+
let(:original) { entity_class.new(string: 'Test') }
|
45
45
|
|
46
46
|
context 'with new, simple value' do
|
47
|
-
subject {
|
48
|
-
|
49
|
-
let(:updated_model) { original.update(string: 'Variant') }
|
47
|
+
subject(:updated_model) { original.update(string: 'Variant') }
|
50
48
|
|
51
49
|
it { is_expected.to be_new }
|
52
50
|
it { is_expected.not_to be_saved }
|
53
51
|
|
54
52
|
it 'returns a new object' do
|
55
|
-
|
53
|
+
expect(updated_model).not_to eql(original)
|
56
54
|
end
|
57
55
|
|
58
56
|
describe 'updated attribute' do
|
@@ -72,7 +70,7 @@ describe Fortnox::API::Model::Base do
|
|
72
70
|
subject(:updated_model) { original.update(string: 'Test') }
|
73
71
|
|
74
72
|
it 'returns the same object' do
|
75
|
-
|
73
|
+
expect(updated_model).to eql(original)
|
76
74
|
end
|
77
75
|
|
78
76
|
it 'returns a object with the same value' do
|
@@ -83,9 +81,9 @@ describe Fortnox::API::Model::Base do
|
|
83
81
|
it { is_expected.not_to be_saved }
|
84
82
|
end
|
85
83
|
|
86
|
-
context 'when updating' do
|
84
|
+
context 'when updating a saved entity' do
|
87
85
|
let(:updated_entity) do
|
88
|
-
saved_entity =
|
86
|
+
saved_entity = entity_class.new(string: 'Saved', new: false, unsaved: false)
|
89
87
|
saved_entity.update(string: 'Updated')
|
90
88
|
end
|
91
89
|
|
@@ -102,5 +100,18 @@ describe Fortnox::API::Model::Base do
|
|
102
100
|
it { is_expected.to eq('Updated') }
|
103
101
|
end
|
104
102
|
end
|
103
|
+
|
104
|
+
context 'when updating a saved entity with nil values' do
|
105
|
+
subject(:updated_entity) { original.update(number: nil) }
|
106
|
+
|
107
|
+
let(:original) { entity_class.new(string: 'Saved', new: false, unsaved: false) }
|
108
|
+
|
109
|
+
it 'returns the same object' do
|
110
|
+
expect(updated_entity).to eql(original)
|
111
|
+
end
|
112
|
+
|
113
|
+
it { is_expected.not_to be_new }
|
114
|
+
it { is_expected.to be_saved }
|
115
|
+
end
|
105
116
|
end
|
106
117
|
end
|
@@ -9,9 +9,11 @@ module Fortnox
|
|
9
9
|
module Model
|
10
10
|
describe Unit, type: :model do
|
11
11
|
context 'when created from empty hash' do
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
it {
|
13
|
+
expect do
|
14
|
+
described_class.new
|
15
|
+
end.to raise_error(Fortnox::API::MissingAttributeError, /Missing attribute.*:code/)
|
16
|
+
}
|
15
17
|
end
|
16
18
|
|
17
19
|
context 'when created from stub' do
|
@@ -10,13 +10,16 @@ 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::Article,
|
13
|
+
describe Fortnox::API::Repository::Article, 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
|
+
|
21
|
+
# VCR: Requires a Financial Year in Fortnox, otherwise the sales account is not be available.
|
22
|
+
# VCR: Update requires that default accounts exists in the chart of accounts
|
20
23
|
include_examples '.save',
|
21
24
|
:description,
|
22
25
|
additional_attrs: { sales_account: 1250 }
|
@@ -26,18 +29,20 @@ describe Fortnox::API::Repository::Article, order: :defined, integration: true d
|
|
26
29
|
:ean,
|
27
30
|
'5901234123457'
|
28
31
|
|
29
|
-
#
|
30
|
-
include_examples '.all',
|
32
|
+
# VCR: expected matches must be increased
|
33
|
+
include_examples '.all', 6
|
31
34
|
|
32
|
-
#
|
35
|
+
# VCR: Expected matches must be increased
|
36
|
+
# VCR: Create the searched Articles manually in Fortnox
|
33
37
|
include_examples '.find', '1' do
|
34
38
|
let(:find_by_hash_failure) { { description: 'Not Found' } }
|
35
|
-
let(:single_param_find_by_hash) { { find_hash: { articlenumber:
|
39
|
+
let(:single_param_find_by_hash) { { find_hash: { articlenumber: 101 }, matches: 1 } }
|
36
40
|
|
37
41
|
let(:multi_param_find_by_hash) do
|
38
|
-
{ find_hash: { articlenumber:
|
42
|
+
{ find_hash: { articlenumber: 101, description: 'Hammer' }, matches: 1 }
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
|
46
|
+
# VCR: Expected mathes must be updated
|
47
|
+
include_examples '.search', :description, 'Test article', 3
|
43
48
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'fortnox/api'
|
5
|
+
require 'fortnox/api/repositories/authentication'
|
6
|
+
|
7
|
+
describe Fortnox::API::Repository::Authentication, integration: true do
|
8
|
+
include Helpers::Configuration
|
9
|
+
|
10
|
+
subject(:repository) { described_class.new }
|
11
|
+
|
12
|
+
before { set_api_test_configuration }
|
13
|
+
|
14
|
+
let(:vcr_dir) { 'authentication' }
|
15
|
+
|
16
|
+
let(:valid_response) do
|
17
|
+
VCR.use_cassette("#{vcr_dir}/valid_request") do
|
18
|
+
repository.renew_tokens(
|
19
|
+
refresh_token: ENV.fetch('FORTNOX_API_REFRESH_TOKEN'),
|
20
|
+
client_id: ENV.fetch('FORTNOX_API_CLIENT_ID'),
|
21
|
+
client_secret: ENV.fetch('FORTNOX_API_CLIENT_SECRET')
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#renew_tokens' do
|
27
|
+
context 'with invalid authorization' do
|
28
|
+
let(:request_with_nonsense_credentials) do
|
29
|
+
VCR.use_cassette("#{vcr_dir}/invalid_authorization") do
|
30
|
+
repository.renew_tokens(
|
31
|
+
refresh_token: ENV.fetch('FORTNOX_API_REFRESH_TOKEN'),
|
32
|
+
client_id: 'nonsense_id',
|
33
|
+
client_secret: 'nonsense_secret'
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises an error' do
|
39
|
+
expect { request_with_nonsense_credentials }.to(
|
40
|
+
raise_error(Fortnox::API::RemoteServerError, /Unauthorized request(.)*Error:(.)*invalid_client/)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with invalid refresh token' do
|
46
|
+
let(:request_with_invalid_refresh_token) do
|
47
|
+
VCR.use_cassette("#{vcr_dir}/invalid_refresh_token") do
|
48
|
+
repository.renew_tokens(
|
49
|
+
refresh_token: 'invalid_refresh_token',
|
50
|
+
client_id: ENV.fetch('FORTNOX_API_CLIENT_ID'),
|
51
|
+
client_secret: ENV.fetch('FORTNOX_API_CLIENT_SECRET')
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'raises an error' do
|
57
|
+
expect { request_with_invalid_refresh_token }.to(
|
58
|
+
raise_error(Fortnox::API::RemoteServerError, /Bad request(.)*Error:(.)*Invalid refresh token/)
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'returned hash' do
|
64
|
+
subject { valid_response }
|
65
|
+
|
66
|
+
it { is_expected.to include(:access_token, :refresh_token, :expires_in, :token_type, :scope) }
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'access_token' do
|
70
|
+
subject { valid_response[:access_token] }
|
71
|
+
|
72
|
+
it { is_expected.to be_a(String) }
|
73
|
+
it { is_expected.not_to be_empty }
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'refresh_token' do
|
77
|
+
subject { valid_response[:refresh_token] }
|
78
|
+
|
79
|
+
it { is_expected.to be_a(String) }
|
80
|
+
it { is_expected.not_to be_empty }
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'expires_in' do
|
84
|
+
subject { valid_response[:expires_in] }
|
85
|
+
|
86
|
+
it { is_expected.to be_a(Integer) }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'token_type' do
|
90
|
+
subject { valid_response[:token_type] }
|
91
|
+
|
92
|
+
it { is_expected.to be_a(String) }
|
93
|
+
it { is_expected.not_to be_empty }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'scope' do
|
97
|
+
subject { valid_response[:scope] }
|
98
|
+
|
99
|
+
it { is_expected.to be_a(String) }
|
100
|
+
it { is_expected.not_to be_empty }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|