fortnox-api 0.6.2 → 0.8.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.
Files changed (165) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +5 -1
  3. data/.travis.yml +20 -22
  4. data/CHANGELOG.md +48 -0
  5. data/README.md +14 -19
  6. data/Rakefile +5 -0
  7. data/fortnox-api.gemspec +10 -10
  8. data/lib/fortnox/api/mappers.rb +5 -38
  9. data/lib/fortnox/api/mappers/base.rb +2 -24
  10. data/lib/fortnox/api/mappers/base/canonical_name_sym.rb +21 -0
  11. data/lib/fortnox/api/mappers/base/from_json.rb +6 -1
  12. data/lib/fortnox/api/mappers/value/array.rb +18 -0
  13. data/lib/fortnox/api/mappers/value/country_string.rb +24 -0
  14. data/lib/fortnox/api/mappers/value/date.rb +11 -0
  15. data/lib/fortnox/api/mappers/value/hash.rb +16 -0
  16. data/lib/fortnox/api/mappers/value/identity.rb +18 -0
  17. data/lib/fortnox/api/models/document.rb +6 -3
  18. data/lib/fortnox/api/models/invoice.rb +1 -1
  19. data/lib/fortnox/api/models/order.rb +1 -1
  20. data/lib/fortnox/api/repositories/base.rb +9 -11
  21. data/lib/fortnox/api/request_handling.rb +0 -1
  22. data/lib/fortnox/api/types.rb +40 -3
  23. data/lib/fortnox/api/types/enums.rb +36 -31
  24. data/lib/fortnox/api/types/shim/country_string.rb +10 -0
  25. data/lib/fortnox/api/version.rb +1 -1
  26. data/spec/fortnox/api/circular_queue_spec.rb +52 -0
  27. data/spec/fortnox/api/mappers/base/canonical_name_sym_spec.rb +34 -0
  28. data/spec/fortnox/api/mappers/base_spec.rb +33 -43
  29. data/spec/fortnox/api/mappers/contexts/json_conversion.rb +1 -1
  30. data/spec/fortnox/api/repositories/article_spec.rb +4 -2
  31. data/spec/fortnox/api/repositories/base_spec.rb +28 -8
  32. data/spec/fortnox/api/repositories/customer_spec.rb +29 -1
  33. data/spec/fortnox/api/repositories/invoice_spec.rb +147 -3
  34. data/spec/fortnox/api/repositories/order_spec.rb +2 -2
  35. data/spec/fortnox/api/repositories/project_spec.rb +1 -1
  36. data/spec/fortnox/api/repositories/terms_of_payment_spec.rb +4 -2
  37. data/spec/fortnox/api/repositories/unit_spec.rb +6 -3
  38. data/spec/fortnox/api/types/account_number_spec.rb +19 -15
  39. data/spec/fortnox/api/types/country_code_spec.rb +42 -0
  40. data/spec/fortnox/api/types/country_spec.rb +67 -0
  41. data/spec/fortnox/api/types/email_spec.rb +8 -7
  42. data/spec/fortnox/api/types/enums_spec.rb +1 -1
  43. data/spec/fortnox/api/types/examples/document_row.rb +1 -1
  44. data/spec/fortnox/api/types/housework_types_spec.rb +151 -34
  45. data/spec/fortnox/api_spec.rb +3 -1
  46. data/spec/vcr_cassettes/articles/all.yml +40 -10
  47. data/spec/vcr_cassettes/articles/find_by_hash_failure.yml +21 -8
  48. data/spec/vcr_cassettes/articles/find_failure.yml +21 -8
  49. data/spec/vcr_cassettes/articles/find_id_1.yml +22 -9
  50. data/spec/vcr_cassettes/articles/find_new.yml +24 -11
  51. data/spec/vcr_cassettes/articles/multi_param_find_by_hash.yml +21 -8
  52. data/spec/vcr_cassettes/articles/save_new.yml +22 -8
  53. data/spec/vcr_cassettes/articles/save_old.yml +24 -11
  54. data/spec/vcr_cassettes/articles/save_with_specially_named_attribute.yml +22 -8
  55. data/spec/vcr_cassettes/articles/search_by_name.yml +21 -8
  56. data/spec/vcr_cassettes/articles/search_miss.yml +21 -8
  57. data/spec/vcr_cassettes/articles/search_with_special_char.yml +21 -8
  58. data/spec/vcr_cassettes/articles/single_param_find_by_hash.yml +33 -10
  59. data/spec/vcr_cassettes/customers/all.yml +26 -13
  60. data/spec/vcr_cassettes/customers/find_by_hash_failure.yml +21 -8
  61. data/spec/vcr_cassettes/customers/find_failure.yml +21 -8
  62. data/spec/vcr_cassettes/customers/find_id_1.yml +22 -9
  63. data/spec/vcr_cassettes/customers/find_new.yml +24 -11
  64. data/spec/vcr_cassettes/customers/multi_param_find_by_hash.yml +21 -8
  65. data/spec/vcr_cassettes/customers/save_new.yml +21 -7
  66. data/spec/vcr_cassettes/customers/save_new_with_country_code_SE.yml +60 -0
  67. data/spec/vcr_cassettes/customers/save_old.yml +23 -10
  68. data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +21 -7
  69. data/spec/vcr_cassettes/customers/search_by_name.yml +32 -10
  70. data/spec/vcr_cassettes/customers/search_miss.yml +21 -8
  71. data/spec/vcr_cassettes/customers/search_with_special_char.yml +21 -8
  72. data/spec/vcr_cassettes/customers/single_param_find_by_hash.yml +22 -9
  73. data/spec/vcr_cassettes/invoices/all.yml +118 -67
  74. data/spec/vcr_cassettes/invoices/filter_hit.yml +26 -10
  75. data/spec/vcr_cassettes/invoices/filter_invalid.yml +20 -6
  76. data/spec/vcr_cassettes/invoices/find_by_hash_failure.yml +21 -8
  77. data/spec/vcr_cassettes/invoices/find_failure.yml +21 -8
  78. data/spec/vcr_cassettes/invoices/find_id_1.yml +23 -10
  79. data/spec/vcr_cassettes/invoices/find_new.yml +26 -14
  80. data/spec/vcr_cassettes/invoices/multi_param_find_by_hash.yml +23 -10
  81. data/spec/vcr_cassettes/invoices/save_new.yml +23 -10
  82. data/spec/vcr_cassettes/invoices/save_new_with_comments.yml +61 -0
  83. data/spec/vcr_cassettes/invoices/save_new_with_country.yml +60 -0
  84. data/spec/vcr_cassettes/invoices/save_new_with_country_GB.yml +61 -0
  85. data/spec/vcr_cassettes/invoices/save_new_with_country_KR.yml +61 -0
  86. data/spec/vcr_cassettes/invoices/save_new_with_country_Norge.yml +60 -0
  87. data/spec/vcr_cassettes/invoices/save_new_with_country_Norway.yml +60 -0
  88. data/spec/vcr_cassettes/invoices/save_new_with_country_Sverige.yml +60 -0
  89. data/spec/vcr_cassettes/invoices/save_new_with_country_VA.yml +61 -0
  90. data/spec/vcr_cassettes/invoices/save_new_with_country_VI.yml +61 -0
  91. data/spec/vcr_cassettes/invoices/save_new_with_country_empty_string.yml +60 -0
  92. data/spec/vcr_cassettes/invoices/save_new_with_country_nil.yml +60 -0
  93. data/spec/vcr_cassettes/invoices/save_old.yml +25 -13
  94. data/spec/vcr_cassettes/invoices/save_old_with_empty_comments.yml +61 -0
  95. data/spec/vcr_cassettes/invoices/save_old_with_empty_country.yml +60 -0
  96. data/spec/vcr_cassettes/invoices/save_old_with_nil_comments.yml +61 -0
  97. data/spec/vcr_cassettes/invoices/save_old_with_nil_country.yml +60 -0
  98. data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +23 -10
  99. data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +23 -10
  100. data/spec/vcr_cassettes/invoices/search_by_name.yml +28 -11
  101. data/spec/vcr_cassettes/invoices/search_miss.yml +21 -8
  102. data/spec/vcr_cassettes/invoices/search_with_special_char.yml +21 -8
  103. data/spec/vcr_cassettes/invoices/single_param_find_by_hash.yml +24 -11
  104. data/spec/vcr_cassettes/orders/all.yml +120 -107
  105. data/spec/vcr_cassettes/orders/filter_hit.yml +28 -12
  106. data/spec/vcr_cassettes/orders/filter_invalid.yml +20 -6
  107. data/spec/vcr_cassettes/orders/find_by_hash_failure.yml +21 -8
  108. data/spec/vcr_cassettes/orders/find_failure.yml +21 -8
  109. data/spec/vcr_cassettes/orders/find_id_1.yml +23 -10
  110. data/spec/vcr_cassettes/orders/find_new.yml +26 -14
  111. data/spec/vcr_cassettes/orders/housework_invalid_tax_reduction_type.yml +57 -0
  112. data/spec/vcr_cassettes/orders/housework_othercoses_invalid.yml +57 -0
  113. data/spec/vcr_cassettes/orders/housework_type_babysitting.yml +24 -10
  114. data/spec/vcr_cassettes/orders/housework_type_cleaning.yml +24 -10
  115. data/spec/vcr_cassettes/orders/housework_type_construction.yml +24 -10
  116. data/spec/vcr_cassettes/orders/housework_type_cooking.yml +21 -7
  117. data/spec/vcr_cassettes/orders/housework_type_electricity.yml +24 -10
  118. data/spec/vcr_cassettes/orders/housework_type_gardening.yml +24 -10
  119. data/spec/vcr_cassettes/orders/housework_type_glassmetalwork.yml +24 -10
  120. data/spec/vcr_cassettes/orders/housework_type_grounddrainagework.yml +24 -10
  121. data/spec/vcr_cassettes/orders/housework_type_hvac.yml +24 -10
  122. data/spec/vcr_cassettes/orders/housework_type_itservices.yml +60 -0
  123. data/spec/vcr_cassettes/orders/housework_type_majorappliancerepair.yml +60 -0
  124. data/spec/vcr_cassettes/orders/housework_type_masonry.yml +24 -10
  125. data/spec/vcr_cassettes/orders/housework_type_movingservices.yml +60 -0
  126. data/spec/vcr_cassettes/orders/housework_type_othercare.yml +24 -10
  127. data/spec/vcr_cassettes/orders/housework_type_othercosts.yml +24 -10
  128. data/spec/vcr_cassettes/orders/housework_type_paintingwallpapering.yml +24 -10
  129. data/spec/vcr_cassettes/orders/housework_type_snowplowing.yml +24 -10
  130. data/spec/vcr_cassettes/orders/housework_type_textileclothing.yml +24 -10
  131. data/spec/vcr_cassettes/orders/housework_type_tutoring.yml +21 -7
  132. data/spec/vcr_cassettes/orders/housework_without_tax_reduction_type.yml +57 -0
  133. data/spec/vcr_cassettes/orders/multi_param_find_by_hash.yml +22 -9
  134. data/spec/vcr_cassettes/orders/save_new.yml +23 -10
  135. data/spec/vcr_cassettes/orders/save_old.yml +25 -13
  136. data/spec/vcr_cassettes/orders/save_with_nested_model.yml +23 -10
  137. data/spec/vcr_cassettes/orders/search_by_name.yml +25 -11
  138. data/spec/vcr_cassettes/orders/search_miss.yml +21 -8
  139. data/spec/vcr_cassettes/orders/search_with_special_char.yml +21 -8
  140. data/spec/vcr_cassettes/orders/single_param_find_by_hash.yml +23 -10
  141. data/spec/vcr_cassettes/projects/all.yml +41 -16
  142. data/spec/vcr_cassettes/projects/find_by_hash_failure.yml +21 -8
  143. data/spec/vcr_cassettes/projects/find_failure.yml +21 -8
  144. data/spec/vcr_cassettes/projects/find_id_1.yml +21 -8
  145. data/spec/vcr_cassettes/projects/find_new.yml +24 -11
  146. data/spec/vcr_cassettes/projects/multi_param_find_by_hash.yml +23 -10
  147. data/spec/vcr_cassettes/projects/save_new.yml +22 -8
  148. data/spec/vcr_cassettes/projects/save_old.yml +24 -11
  149. data/spec/vcr_cassettes/projects/single_param_find_by_hash.yml +22 -9
  150. data/spec/vcr_cassettes/termsofpayments/all.yml +31 -14
  151. data/spec/vcr_cassettes/termsofpayments/find_failure.yml +21 -8
  152. data/spec/vcr_cassettes/termsofpayments/find_id_1.yml +22 -9
  153. data/spec/vcr_cassettes/termsofpayments/find_new.yml +23 -10
  154. data/spec/vcr_cassettes/termsofpayments/save_new.yml +22 -8
  155. data/spec/vcr_cassettes/termsofpayments/save_old.yml +23 -10
  156. data/spec/vcr_cassettes/units/all.yml +31 -12
  157. data/spec/vcr_cassettes/units/find_failure.yml +21 -8
  158. data/spec/vcr_cassettes/units/find_id_1.yml +21 -8
  159. data/spec/vcr_cassettes/units/find_new.yml +23 -12
  160. data/spec/vcr_cassettes/units/save_new.yml +22 -10
  161. data/spec/vcr_cassettes/units/save_old.yml +23 -12
  162. data/spec/vcr_cassettes/units/save_with_specially_named_attribute.yml +22 -10
  163. data/temp.txt +1 -0
  164. metadata +99 -21
  165. data/spec/support/matchers/type/have_country_code_matcher.rb +0 -15
@@ -40,7 +40,7 @@ shared_context 'with JSON conversion' do
40
40
  attribute :url, 'strict.string'
41
41
  attribute :name, 'strict.string'
42
42
  attribute :vat, 'strict.float'
43
- attribute :categories, Dry::Types['coercible.array'].member(Test::Category)
43
+ attribute :categories, Dry::Types['coercible.array'].of(Test::Category)
44
44
  attribute :designer, Test::ProductDesigner
45
45
  end
46
46
  end
@@ -26,11 +26,13 @@ describe Fortnox::API::Repository::Article, order: :defined, integration: true d
26
26
  :ean,
27
27
  '5901234123457'
28
28
 
29
- include_examples '.all', 12
29
+ # When recording new VCR cassettes, expected matches must be increased
30
+ include_examples '.all', 29
30
31
 
32
+ # When recording new VCR cassettes, expected matches must be increased
31
33
  include_examples '.find', '1' do
32
34
  let(:find_by_hash_failure) { { description: 'Not Found' } }
33
- let(:single_param_find_by_hash) { { find_hash: { articlenumber: 1 }, matches: 3 } }
35
+ let(:single_param_find_by_hash) { { find_hash: { articlenumber: 1 }, matches: 13 } }
34
36
 
35
37
  let(:multi_param_find_by_hash) do
36
38
  { find_hash: { articlenumber: 1, description: 'Cykelpump' }, matches: 1 }
@@ -6,18 +6,25 @@ require 'fortnox/api'
6
6
  describe Fortnox::API::Repository::Base do
7
7
  using_test_class do
8
8
  module Model
9
- class Test
9
+ class RepositoryBaseTest
10
10
  end
11
11
  end
12
12
  module Repository
13
13
  class Test < Fortnox::API::Repository::Base
14
- MODEL = Model::Test
14
+ MODEL = Model::RepositoryBaseTest
15
15
  end
16
16
  end
17
+ end
18
+
19
+ before do
20
+ Fortnox::API::Registry.register(:repositorybasetest, Model::RepositoryBaseTest)
21
+ end
17
22
 
18
- require 'dry/container/stub'
19
- Fortnox::API::Registry.enable_stubs!
20
- Fortnox::API::Registry.stub(:test, Model::Test)
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')
21
28
  end
22
29
 
23
30
  let(:access_token) { '3f08d038-f380-4893-94a0-a08f6e60e67a' }
@@ -36,7 +43,7 @@ describe Fortnox::API::Repository::Base do
36
43
 
37
44
  describe 'creation' do
38
45
  shared_examples_for 'missing configuration' do
39
- subject { -> { repository } }
46
+ subject { -> { Repository::Test.new(token_store: :store1).get('nonsense') } }
40
47
 
41
48
  let(:error) { Fortnox::API::MissingConfiguration }
42
49
 
@@ -45,14 +52,27 @@ describe Fortnox::API::Repository::Base do
45
52
 
46
53
  context 'without base url' do
47
54
  include_examples 'missing configuration' do
48
- before { Fortnox::API.configure { |conf| conf.base_url = nil } }
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
+
49
63
  let(:message) { 'have to provide a base url' }
50
64
  end
51
65
  end
52
66
 
53
67
  context 'without client secret' do
54
68
  include_examples 'missing configuration' do
55
- before { Fortnox::API.configure { |conf| conf.client_secret = nil } }
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
75
+
56
76
  let(:message) { 'have to provide your client secret' }
57
77
  end
58
78
  end
@@ -38,5 +38,33 @@ describe Fortnox::API::Repository::Customer, order: :defined, integration: true
38
38
  end
39
39
  end
40
40
 
41
- include_examples '.search', :name, 'Test', 23
41
+ # When recording new VCR casettes, expected matches must be increased
42
+ include_examples '.search', :name, 'Test', 31
43
+
44
+ describe 'country reference' do
45
+ describe 'with valid country code \'SE\'' do
46
+ subject(:customer) do
47
+ VCR.use_cassette("#{vcr_dir}/save_new_with_country_code_SE") do
48
+ repository.save(
49
+ described_class::MODEL.new(
50
+ name: 'Customer with Swedish country code',
51
+ country_code: 'SE'
52
+ )
53
+ )
54
+ end
55
+ end
56
+
57
+ describe 'country code' do
58
+ subject { customer.country_code }
59
+
60
+ it { is_expected.to eq('SE') }
61
+ end
62
+
63
+ describe 'country' do
64
+ subject { customer.country }
65
+
66
+ it { is_expected.to eq('Sverige') }
67
+ end
68
+ end
69
+ end
42
70
  end
@@ -37,7 +37,7 @@ describe Fortnox::API::Repository::Invoice, order: :defined, integration: true d
37
37
 
38
38
  # It is not possible to delete Invoces. Therefore, expected nr of Orders
39
39
  # when running .all will continue to increase (until 100, which is max by default).
40
- include_examples '.all', 60
40
+ include_examples '.all', 100
41
41
 
42
42
  include_examples '.find', 1 do
43
43
  let(:find_by_hash_failure) { { yourreference: 'Not found' } }
@@ -51,7 +51,151 @@ describe Fortnox::API::Repository::Invoice, order: :defined, integration: true d
51
51
  end
52
52
  end
53
53
 
54
- include_examples '.search', :customername, 'Test', 3
54
+ include_examples '.search', :customername, 'Test', 7
55
55
 
56
- include_examples '.only', :fullypaid, 1
56
+ include_examples '.only', :fullypaid, 4
57
+
58
+ describe 'country attribute' do
59
+ def new_invoice(country:)
60
+ described_class::MODEL.new(customer_number: 1, country: country)
61
+ end
62
+
63
+ context 'with valid country' do
64
+ def save_invoice(country:, vcr_cassette: country)
65
+ VCR.use_cassette("#{vcr_dir}/save_new_with_country_#{vcr_cassette}") do
66
+ repository.save(new_invoice(country: country))
67
+ end
68
+ end
69
+
70
+ it 'accepts English country names' do
71
+ expect(save_invoice(country: 'Norway').country).to eq('NO')
72
+ end
73
+
74
+ it 'translates Swedish country names to English' do
75
+ expect(save_invoice(country: 'Norge').country).to eq('NO')
76
+ end
77
+
78
+ it 'skips nil values' do
79
+ expect(save_invoice(country: nil, vcr_cassette: 'nil').country).to eq('')
80
+ end
81
+
82
+ it 'skips empty string values' do
83
+ expect(save_invoice(country: '', vcr_cassette: 'empty_string').country).to eq('')
84
+ end
85
+
86
+ describe 'GB' do
87
+ subject { save_invoice(country: 'GB').country }
88
+
89
+ it { is_expected.to eq('GB') }
90
+ end
91
+
92
+ describe 'KR' do
93
+ subject { save_invoice(country: 'KR').country }
94
+
95
+ it { is_expected.to eq('KR') }
96
+ end
97
+
98
+ describe 'VA' do
99
+ subject { save_invoice(country: 'VA').country }
100
+
101
+ it { is_expected.to eq('VA') }
102
+ end
103
+
104
+ describe 'VI' do
105
+ subject { save_invoice(country: 'VI').country }
106
+
107
+ it { is_expected.to eq('VI') }
108
+ end
109
+
110
+ describe 'special cases Sverige' do
111
+ subject { save_invoice(country: 'Sverige').country }
112
+
113
+ it { is_expected.to eq('SE') }
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'resetting values in Fortnox' do
119
+ context 'with String values' do
120
+ def new_invoice(comments:)
121
+ described_class::MODEL.new(customer_number: 1, comments: comments)
122
+ end
123
+
124
+ let(:persisted_invoice) do
125
+ VCR.use_cassette("#{vcr_dir}/save_new_with_comments") do
126
+ repository.save(new_invoice(comments: 'A comment to be reset'))
127
+ end
128
+ end
129
+
130
+ before { persisted_invoice }
131
+
132
+ context 'when setting value to nil' do
133
+ subject { updated_persisted_invoice.comments }
134
+
135
+ let(:updated_persisted_invoice) do
136
+ VCR.use_cassette("#{vcr_dir}/save_old_with_nil_comments") do
137
+ repository.save(persisted_invoice.update(comments: nil))
138
+ end
139
+ end
140
+
141
+ pending { is_expected.to eq(nil) }
142
+ end
143
+
144
+ context 'when setting value to empty string' do
145
+ subject { updated_persisted_invoice.comments }
146
+
147
+ let(:updated_persisted_invoice) do
148
+ VCR.use_cassette("#{vcr_dir}/save_old_with_empty_comments") do
149
+ repository.save(persisted_invoice.update(comments: ''))
150
+ end
151
+ end
152
+
153
+ it 'does not reset the value' do
154
+ is_expected.to eq('A comment to be reset')
155
+ end
156
+ end
157
+ end
158
+
159
+ context 'with other values' do
160
+ def new_invoice(country:)
161
+ described_class::MODEL.new(customer_number: 1, country: country)
162
+ end
163
+
164
+ let(:persisted_invoice) do
165
+ VCR.use_cassette("#{vcr_dir}/save_new_with_country") do
166
+ repository.save(new_invoice(country: 'Sverige'))
167
+ end
168
+ end
169
+
170
+ before { persisted_invoice }
171
+
172
+ context 'when setting value to nil' do
173
+ subject { updated_persisted_invoice.country }
174
+
175
+ let(:updated_persisted_invoice) do
176
+ # TODO: This VCR cassette needs to be re-recorded again
177
+ # when the we fix #172.
178
+ VCR.use_cassette("#{vcr_dir}/save_old_with_nil_country") do
179
+ repository.save(persisted_invoice.update(country: nil))
180
+ end
181
+ end
182
+
183
+ pending { is_expected.to eq(nil) }
184
+ end
185
+
186
+ context 'when setting value to empty string' do
187
+ subject { updated_persisted_invoice.country }
188
+
189
+ let(:updated_persisted_invoice) do
190
+ VCR.use_cassette("#{vcr_dir}/save_old_with_empty_country") do
191
+ repository.save(persisted_invoice.update(country: ''))
192
+ end
193
+ end
194
+
195
+ it 'does not reset the country' do
196
+ is_expected.to eq('SE')
197
+ end
198
+ end
199
+ end
200
+ end
57
201
  end
@@ -45,7 +45,7 @@ describe Fortnox::API::Repository::Order, order: :defined, integration: true do
45
45
  end
46
46
  end
47
47
 
48
- include_examples '.search', :customername, 'A customer', 2
48
+ include_examples '.search', :customername, 'A customer', 3
49
49
 
50
- include_examples '.only', :cancelled, 3
50
+ include_examples '.only', :cancelled, 6
51
51
  end
@@ -22,7 +22,7 @@ describe Fortnox::API::Repository::Project, order: :defined, integration: true d
22
22
  # It is not yet possible to delete Projects. Therefore, expected nr of
23
23
  # Projects when running .all will continue to increase
24
24
  # (until 100, which is max by default).
25
- include_examples '.all', 8
25
+ include_examples '.all', 33
26
26
 
27
27
  include_examples '.find', '1' do
28
28
  let(:find_by_hash_failure) { { offset: 10_000 } }
@@ -17,11 +17,13 @@ describe Fortnox::API::Repository::TermsOfPayment, order: :defined, integration:
17
17
 
18
18
  before { set_api_test_configuration }
19
19
 
20
- required_hash = { code: '15DAYS' }
20
+ # When recording new VCR cassettes, code must be changed to a new unique one
21
+ required_hash = { code: '19DAYS' }
21
22
 
22
23
  include_examples '.save', :description, additional_attrs: required_hash
23
24
 
24
- include_examples '.all', 9
25
+ # When recording new VCR cassettes, expected matches needs to be increased
26
+ include_examples '.all', 13
25
27
 
26
28
  include_examples '.find', '15DAYS', find_by_hash: false do
27
29
  let(:find_by_hash_failure) { { code: '15days' } }
@@ -16,16 +16,19 @@ describe Fortnox::API::Repository::Unit, order: :defined, integration: true do
16
16
 
17
17
  subject(:repository) { described_class.new }
18
18
 
19
+ # When recording new VCR cassettes, code needs to be changed to a unique value
19
20
  include_examples '.save',
20
21
  :description,
21
- additional_attrs: { code: 'blarg' }
22
+ additional_attrs: { code: 'blarg5' }
22
23
 
24
+ # When recording new VCR cassettes, code needs to be changed to a unique value
23
25
  include_examples '.save with specially named attribute',
24
26
  { description: 'Happy clouds' },
25
27
  :code,
26
- 'woooh'
28
+ 'woooh5'
27
29
 
28
- include_examples '.all', 6
30
+ # When recording new VCR cassettes, expected number must be updated
31
+ include_examples '.all', 14
29
32
 
30
33
  include_examples '.find', 'blarg', find_by_hash: false do
31
34
  let(:find_by_hash_failure) { { code: 'notfound' } }
@@ -7,25 +7,29 @@ require 'fortnox/api/types/examples/types'
7
7
  describe Fortnox::API::Types do
8
8
  let(:klass) { Fortnox::API::Types::AccountNumber }
9
9
 
10
- context 'when AccountNumber created with nil' do
11
- subject { klass[nil] }
10
+ describe 'AccountNumber' do
11
+ context 'when created with nil' do
12
+ subject { klass[nil] }
12
13
 
13
- it { is_expected.to be_nil }
14
- end
14
+ it { is_expected.to be_nil }
15
+ end
15
16
 
16
- context 'when AccountNumber created with empty string' do
17
- include_examples 'raises ConstraintError', ''
18
- end
17
+ context 'when created with empty string' do
18
+ subject { klass[''] }
19
19
 
20
- context 'when AccountNumber created with valid number' do
21
- include_examples 'equals input', 1234
22
- end
20
+ it { is_expected.to be_nil }
21
+ end
23
22
 
24
- context 'when AccountNumber created with a too large number' do
25
- include_examples 'raises ConstraintError', 10_000
26
- end
23
+ context 'when created with valid number' do
24
+ include_examples 'equals input', 1234
25
+ end
26
+
27
+ context 'when created with a too large number' do
28
+ include_examples 'raises ConstraintError', 10_000
29
+ end
27
30
 
28
- context 'when AccountNumber created with a negative number' do
29
- include_examples 'raises ConstraintError', -1
31
+ context 'when created with a negative number' do
32
+ include_examples 'raises ConstraintError', -1
33
+ end
30
34
  end
31
35
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fortnox/api/types'
5
+
6
+ describe Fortnox::API::Types::CountryCode do
7
+ context 'with nil' do
8
+ subject { described_class[nil] }
9
+
10
+ it { is_expected.to be_nil }
11
+ end
12
+
13
+ context 'with empty string' do
14
+ subject { described_class[''] }
15
+
16
+ it { is_expected.to eq('') }
17
+ end
18
+
19
+ context 'with valid input' do
20
+ it 'accepts country codes' do
21
+ expect(described_class['NO']).to eq 'NO'
22
+ end
23
+ end
24
+
25
+ context 'with invalid input' do
26
+ describe 'valid country name' do
27
+ it do
28
+ expect do
29
+ described_class['Norway']
30
+ end.to raise_error(Dry::Types::ConstraintError)
31
+ end
32
+ end
33
+
34
+ describe 'invalid country code' do
35
+ it do
36
+ expect do
37
+ described_class['XX']
38
+ end.to raise_error(Dry::Types::ConstraintError)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fortnox/api/types'
5
+
6
+ describe Fortnox::API::Types::Country do
7
+ context 'with nil' do
8
+ subject { described_class[nil] }
9
+
10
+ it { is_expected.to be_nil }
11
+ end
12
+
13
+ context 'with empty string' do
14
+ subject { described_class[''] }
15
+
16
+ it { is_expected.to eq('') }
17
+ end
18
+
19
+ context 'with valid input' do
20
+ it 'accepts country codes' do
21
+ expect(described_class['NO']).to eq 'NO'
22
+ end
23
+
24
+ it 'translates English country names to country code' do
25
+ expect(described_class['Norway']).to eq 'NO'
26
+ end
27
+
28
+ it 'translates Swedish country names to country code' do
29
+ expect(described_class['Norge']).to eq 'NO'
30
+ end
31
+
32
+ describe 'special cases' do
33
+ valid_sweden_inputs = [
34
+ 'SE', 'se', 'Sweden', 'sweden', 'Sverige', 'sverige',
35
+ :SE, :se, :Sweden, :sweden, :Sverige, :sverige
36
+ ].freeze
37
+
38
+ valid_sweden_inputs.each do |sweden_input|
39
+ it "converts \"#{sweden_input}\" to \"SE\"" do
40
+ expect(described_class[sweden_input]).to eq 'SE'
41
+ end
42
+ end
43
+
44
+ it 'accepts country code for El Salvador' do
45
+ expect(described_class['SV']).to eq 'SV'
46
+ end
47
+
48
+ it 'translated Switzerland to ' do
49
+ expect(described_class['Switzerland']).to eq 'CH'
50
+ end
51
+ end
52
+ end
53
+
54
+ context 'with invalid input' do
55
+ invalid_inputs = [
56
+ 'SEA', 'S', 'nonsense', :s
57
+ ].freeze
58
+
59
+ invalid_inputs.each do |invalid_input|
60
+ it "#{invalid_input} raises Dry::Types::ConstraintError" do
61
+ expect do
62
+ described_class[invalid_input]
63
+ end.to raise_error(Dry::Types::ConstraintError)
64
+ end
65
+ end
66
+ end
67
+ end