fortnox-api 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.env.template +7 -0
  4. data/.env.test +11 -3
  5. data/.gitignore +7 -1
  6. data/.rubocop.yml +18 -2
  7. data/.tool-versions +1 -0
  8. data/.travis.yml +15 -12
  9. data/CHANGELOG.md +58 -3
  10. data/CONTRIBUTE.md +21 -9
  11. data/DEVELOPER_README.md +72 -0
  12. data/Guardfile +13 -4
  13. data/README.md +226 -64
  14. data/Rakefile +128 -0
  15. data/bin/get_tokens +79 -0
  16. data/bin/renew_tokens +28 -0
  17. data/fortnox-api.gemspec +31 -25
  18. data/lib/fortnox/api/mappers/article.rb +1 -1
  19. data/lib/fortnox/api/mappers/base/from_json.rb +5 -4
  20. data/lib/fortnox/api/mappers/base/to_json.rb +4 -5
  21. data/lib/fortnox/api/mappers/base.rb +3 -3
  22. data/lib/fortnox/api/mappers/customer.rb +1 -1
  23. data/lib/fortnox/api/mappers/default_delivery_types.rb +1 -1
  24. data/lib/fortnox/api/mappers/default_templates.rb +1 -1
  25. data/lib/fortnox/api/mappers/edi_information.rb +1 -1
  26. data/lib/fortnox/api/mappers/email_information.rb +1 -1
  27. data/lib/fortnox/api/mappers/invoice.rb +4 -4
  28. data/lib/fortnox/api/mappers/invoice_row.rb +1 -1
  29. data/lib/fortnox/api/mappers/order.rb +4 -4
  30. data/lib/fortnox/api/mappers/order_row.rb +1 -1
  31. data/lib/fortnox/api/mappers/project.rb +1 -1
  32. data/lib/fortnox/api/mappers/terms_of_payment.rb +1 -1
  33. data/lib/fortnox/api/mappers/unit.rb +1 -1
  34. data/lib/fortnox/api/mappers/value/country_string.rb +1 -1
  35. data/lib/fortnox/api/mappers.rb +18 -18
  36. data/lib/fortnox/api/models/article.rb +2 -2
  37. data/lib/fortnox/api/models/base.rb +23 -21
  38. data/lib/fortnox/api/models/customer.rb +57 -57
  39. data/lib/fortnox/api/models/document.rb +2 -2
  40. data/lib/fortnox/api/models/invoice.rb +2 -2
  41. data/lib/fortnox/api/models/label.rb +3 -3
  42. data/lib/fortnox/api/models/order.rb +2 -2
  43. data/lib/fortnox/api/models/project.rb +2 -2
  44. data/lib/fortnox/api/models/terms_of_payment.rb +2 -2
  45. data/lib/fortnox/api/models/unit.rb +2 -2
  46. data/lib/fortnox/api/models.rb +7 -7
  47. data/lib/fortnox/api/repositories/article.rb +3 -3
  48. data/lib/fortnox/api/repositories/authentication.rb +61 -0
  49. data/lib/fortnox/api/repositories/base/savers.rb +3 -1
  50. data/lib/fortnox/api/repositories/base.rb +25 -38
  51. data/lib/fortnox/api/repositories/customer.rb +3 -3
  52. data/lib/fortnox/api/repositories/invoice.rb +3 -3
  53. data/lib/fortnox/api/repositories/order.rb +3 -3
  54. data/lib/fortnox/api/repositories/project.rb +3 -3
  55. data/lib/fortnox/api/repositories/terms_of_payment.rb +3 -3
  56. data/lib/fortnox/api/repositories/unit.rb +3 -3
  57. data/lib/fortnox/api/repositories.rb +8 -7
  58. data/lib/fortnox/api/request_handling.rb +30 -18
  59. data/lib/fortnox/api/types/default_delivery_types.rb +0 -2
  60. data/lib/fortnox/api/types/default_templates.rb +0 -2
  61. data/lib/fortnox/api/types/document_row.rb +3 -3
  62. data/lib/fortnox/api/types/edi_information.rb +0 -2
  63. data/lib/fortnox/api/types/email_information.rb +0 -2
  64. data/lib/fortnox/api/types/enums.rb +27 -11
  65. data/lib/fortnox/api/types/invoice_row.rb +1 -1
  66. data/lib/fortnox/api/types/model.rb +5 -9
  67. data/lib/fortnox/api/types/nullable.rb +13 -9
  68. data/lib/fortnox/api/types/order_row.rb +1 -1
  69. data/lib/fortnox/api/types/required.rb +3 -3
  70. data/lib/fortnox/api/types/sized.rb +4 -4
  71. data/lib/fortnox/api/types.rb +31 -23
  72. data/lib/fortnox/api/version.rb +1 -1
  73. data/lib/fortnox/api.rb +21 -39
  74. data/spec/fortnox/api/mappers/base/canonical_name_sym_spec.rb +13 -11
  75. data/spec/fortnox/api/mappers/base/from_json_spec.rb +10 -12
  76. data/spec/fortnox/api/mappers/base/to_json_spec.rb +48 -57
  77. data/spec/fortnox/api/mappers/base_spec.rb +4 -7
  78. data/spec/fortnox/api/mappers/contexts/json_conversion.rb +38 -33
  79. data/spec/fortnox/api/mappers/default_delivery_types_spec.rb +1 -1
  80. data/spec/fortnox/api/mappers/examples/mapper.rb +1 -1
  81. data/spec/fortnox/api/mappers/unit_spec.rb +3 -4
  82. data/spec/fortnox/api/models/base_spec.rb +33 -22
  83. data/spec/fortnox/api/models/unit_spec.rb +5 -3
  84. data/spec/fortnox/api/repositories/article_spec.rb +14 -9
  85. data/spec/fortnox/api/repositories/authentication_spec.rb +103 -0
  86. data/spec/fortnox/api/repositories/base_spec.rb +105 -326
  87. data/spec/fortnox/api/repositories/customer_spec.rb +37 -7
  88. data/spec/fortnox/api/repositories/examples/all.rb +0 -1
  89. data/spec/fortnox/api/repositories/examples/find.rb +5 -8
  90. data/spec/fortnox/api/repositories/examples/only.rb +4 -13
  91. data/spec/fortnox/api/repositories/examples/save.rb +32 -18
  92. data/spec/fortnox/api/repositories/examples/save_with_nested_model.rb +0 -5
  93. data/spec/fortnox/api/repositories/examples/save_with_specially_named_attribute.rb +1 -4
  94. data/spec/fortnox/api/repositories/examples/search.rb +4 -7
  95. data/spec/fortnox/api/repositories/invoice_spec.rb +64 -21
  96. data/spec/fortnox/api/repositories/order_spec.rb +11 -9
  97. data/spec/fortnox/api/repositories/project_spec.rb +7 -6
  98. data/spec/fortnox/api/repositories/terms_of_payment_spec.rb +9 -7
  99. data/spec/fortnox/api/repositories/unit_spec.rb +13 -11
  100. data/spec/fortnox/api/types/country_spec.rb +1 -1
  101. data/spec/fortnox/api/types/email_spec.rb +2 -2
  102. data/spec/fortnox/api/types/examples/document_row.rb +3 -3
  103. data/spec/fortnox/api/types/examples/enum.rb +4 -4
  104. data/spec/fortnox/api/types/examples/types.rb +1 -3
  105. data/spec/fortnox/api/types/housework_types_spec.rb +54 -90
  106. data/spec/fortnox/api/types/model_spec.rb +13 -23
  107. data/spec/fortnox/api/types/nullable_spec.rb +30 -10
  108. data/spec/fortnox/api/types/order_row_spec.rb +2 -2
  109. data/spec/fortnox/api/types/required_spec.rb +7 -15
  110. data/spec/fortnox/api/types/sales_account_spec.rb +57 -0
  111. data/spec/fortnox/api_spec.rb +19 -124
  112. data/spec/spec_helper.rb +0 -14
  113. data/spec/support/helpers/configuration_helper.rb +30 -3
  114. data/spec/support/helpers.rb +1 -1
  115. data/spec/support/matchers/type/attribute_matcher.rb +2 -2
  116. data/spec/support/matchers/type/enum_matcher.rb +1 -1
  117. data/spec/support/matchers/type/have_account_number_matcher.rb +1 -1
  118. data/spec/support/matchers/type/have_email_matcher.rb +1 -1
  119. data/spec/support/matchers/type/have_nullable_date_matcher.rb +7 -5
  120. data/spec/support/matchers/type/have_nullable_matcher.rb +1 -1
  121. data/spec/support/matchers/type/have_nullable_string_matcher.rb +5 -5
  122. data/spec/support/matchers/type/require_attribute_matcher.rb +5 -5
  123. data/spec/support/matchers/type/type_matcher.rb +1 -1
  124. data/spec/support/vcr_setup.rb +16 -0
  125. data/spec/vcr_cassettes/articles/all.yml +32 -49
  126. data/spec/vcr_cassettes/articles/find_by_hash_failure.yml +27 -23
  127. data/spec/vcr_cassettes/articles/find_failure.yml +27 -23
  128. data/spec/vcr_cassettes/articles/find_id_1.yml +29 -24
  129. data/spec/vcr_cassettes/articles/find_new.yml +30 -26
  130. data/spec/vcr_cassettes/articles/multi_param_find_by_hash.yml +29 -25
  131. data/spec/vcr_cassettes/articles/save_new.yml +29 -25
  132. data/spec/vcr_cassettes/articles/save_old.yml +30 -26
  133. data/spec/vcr_cassettes/articles/save_with_specially_named_attribute.yml +29 -25
  134. data/spec/vcr_cassettes/articles/search_by_name.yml +32 -25
  135. data/spec/vcr_cassettes/articles/search_miss.yml +27 -23
  136. data/spec/vcr_cassettes/articles/search_with_special_char.yml +27 -23
  137. data/spec/vcr_cassettes/articles/single_param_find_by_hash.yml +29 -36
  138. data/spec/vcr_cassettes/authentication/expired_token.yml +54 -0
  139. data/spec/vcr_cassettes/authentication/invalid_authorization.yml +57 -0
  140. data/spec/vcr_cassettes/authentication/invalid_refresh_token.yml +58 -0
  141. data/spec/vcr_cassettes/authentication/valid_request.yml +63 -0
  142. data/spec/vcr_cassettes/customers/all.yml +35 -136
  143. data/spec/vcr_cassettes/customers/find_by_hash_failure.yml +27 -23
  144. data/spec/vcr_cassettes/customers/find_failure.yml +27 -23
  145. data/spec/vcr_cassettes/customers/find_id_1.yml +30 -25
  146. data/spec/vcr_cassettes/customers/find_new.yml +29 -25
  147. data/spec/vcr_cassettes/customers/find_with_sales_account.yml +63 -0
  148. data/spec/vcr_cassettes/customers/multi_param_find_by_hash.yml +29 -25
  149. data/spec/vcr_cassettes/customers/save_new.yml +28 -24
  150. data/spec/vcr_cassettes/customers/save_new_with_country_code_SE.yml +28 -24
  151. data/spec/vcr_cassettes/customers/save_new_with_sales_account.yml +63 -0
  152. data/spec/vcr_cassettes/customers/save_old.yml +29 -25
  153. data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +28 -24
  154. data/spec/vcr_cassettes/customers/search_by_name.yml +29 -53
  155. data/spec/vcr_cassettes/customers/search_miss.yml +27 -23
  156. data/spec/vcr_cassettes/customers/search_with_special_char.yml +27 -23
  157. data/spec/vcr_cassettes/customers/single_param_find_by_hash.yml +30 -26
  158. data/spec/vcr_cassettes/invoices/all.yml +62 -121
  159. data/spec/vcr_cassettes/invoices/filter_hit.yml +30 -28
  160. data/spec/vcr_cassettes/invoices/filter_invalid.yml +27 -23
  161. data/spec/vcr_cassettes/invoices/find_by_hash_failure.yml +27 -23
  162. data/spec/vcr_cassettes/invoices/find_failure.yml +27 -23
  163. data/spec/vcr_cassettes/invoices/find_id_1.yml +31 -26
  164. data/spec/vcr_cassettes/invoices/find_new.yml +32 -28
  165. data/spec/vcr_cassettes/invoices/multi_param_find_by_hash.yml +29 -25
  166. data/spec/vcr_cassettes/invoices/row_description_limit.yml +65 -0
  167. data/spec/vcr_cassettes/invoices/save_new.yml +31 -27
  168. data/spec/vcr_cassettes/invoices/save_new_with_comments.yml +31 -27
  169. data/spec/vcr_cassettes/invoices/save_new_with_country.yml +31 -26
  170. data/spec/vcr_cassettes/invoices/save_new_with_country_GB.yml +32 -27
  171. data/spec/vcr_cassettes/invoices/save_new_with_country_Norge.yml +31 -26
  172. data/spec/vcr_cassettes/invoices/save_new_with_country_Norway.yml +31 -26
  173. data/spec/vcr_cassettes/invoices/save_new_with_country_Sverige.yml +31 -26
  174. data/spec/vcr_cassettes/invoices/save_new_with_country_VA.yml +32 -27
  175. data/spec/vcr_cassettes/invoices/save_new_with_country_VI.yml +32 -27
  176. data/spec/vcr_cassettes/invoices/save_new_with_country_empty_string.yml +31 -26
  177. data/spec/vcr_cassettes/invoices/save_new_with_country_nil.yml +31 -26
  178. data/spec/vcr_cassettes/invoices/save_new_with_unsaved_parent.yml +65 -0
  179. data/spec/vcr_cassettes/invoices/save_old.yml +32 -28
  180. data/spec/vcr_cassettes/invoices/save_old_with_empty_comments.yml +32 -28
  181. data/spec/vcr_cassettes/invoices/save_old_with_empty_country.yml +32 -27
  182. data/spec/vcr_cassettes/invoices/save_old_with_nil_comments.yml +32 -28
  183. data/spec/vcr_cassettes/invoices/save_old_with_nil_country.yml +32 -27
  184. data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +32 -27
  185. data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +31 -26
  186. data/spec/vcr_cassettes/invoices/search_by_name.yml +29 -31
  187. data/spec/vcr_cassettes/invoices/search_miss.yml +27 -23
  188. data/spec/vcr_cassettes/invoices/search_with_special_char.yml +27 -23
  189. data/spec/vcr_cassettes/invoices/single_param_find_by_hash.yml +30 -26
  190. data/spec/vcr_cassettes/orders/all.yml +35 -123
  191. data/spec/vcr_cassettes/orders/filter_hit.yml +30 -30
  192. data/spec/vcr_cassettes/orders/filter_invalid.yml +27 -23
  193. data/spec/vcr_cassettes/orders/find_by_hash_failure.yml +27 -23
  194. data/spec/vcr_cassettes/orders/find_failure.yml +27 -23
  195. data/spec/vcr_cassettes/orders/find_id_1.yml +33 -27
  196. data/spec/vcr_cassettes/orders/find_new.yml +32 -28
  197. data/spec/vcr_cassettes/orders/housework_invalid_tax_reduction_type.yml +28 -24
  198. data/spec/vcr_cassettes/orders/housework_othercoses_invalid.yml +28 -24
  199. data/spec/vcr_cassettes/orders/housework_type_babysitting.yml +32 -27
  200. data/spec/vcr_cassettes/orders/housework_type_cleaning.yml +32 -27
  201. data/spec/vcr_cassettes/orders/housework_type_construction.yml +32 -27
  202. data/spec/vcr_cassettes/orders/housework_type_cooking.yml +28 -24
  203. data/spec/vcr_cassettes/orders/housework_type_electricity.yml +32 -27
  204. data/spec/vcr_cassettes/orders/housework_type_gardening.yml +32 -27
  205. data/spec/vcr_cassettes/orders/housework_type_glassmetalwork.yml +32 -27
  206. data/spec/vcr_cassettes/orders/housework_type_grounddrainagework.yml +32 -27
  207. data/spec/vcr_cassettes/orders/housework_type_hvac.yml +32 -27
  208. data/spec/vcr_cassettes/orders/housework_type_itservices.yml +32 -27
  209. data/spec/vcr_cassettes/orders/housework_type_majorappliancerepair.yml +32 -27
  210. data/spec/vcr_cassettes/orders/housework_type_masonry.yml +32 -27
  211. data/spec/vcr_cassettes/orders/housework_type_movingservices.yml +32 -27
  212. data/spec/vcr_cassettes/orders/housework_type_othercare.yml +32 -27
  213. data/spec/vcr_cassettes/orders/housework_type_othercosts.yml +32 -27
  214. data/spec/vcr_cassettes/orders/housework_type_paintingwallpapering.yml +32 -27
  215. data/spec/vcr_cassettes/orders/housework_type_snowplowing.yml +32 -27
  216. data/spec/vcr_cassettes/orders/housework_type_textileclothing.yml +32 -27
  217. data/spec/vcr_cassettes/orders/housework_type_tutoring.yml +28 -24
  218. data/spec/vcr_cassettes/orders/multi_param_find_by_hash.yml +29 -25
  219. data/spec/vcr_cassettes/orders/save_new.yml +32 -28
  220. data/spec/vcr_cassettes/orders/save_old.yml +32 -28
  221. data/spec/vcr_cassettes/orders/save_with_nested_model.yml +32 -27
  222. data/spec/vcr_cassettes/orders/search_by_name.yml +29 -27
  223. data/spec/vcr_cassettes/orders/search_miss.yml +27 -23
  224. data/spec/vcr_cassettes/orders/search_with_special_char.yml +27 -23
  225. data/spec/vcr_cassettes/orders/single_param_find_by_hash.yml +30 -26
  226. data/spec/vcr_cassettes/projects/all.yml +30 -43
  227. data/spec/vcr_cassettes/projects/find_by_hash_failure.yml +27 -23
  228. data/spec/vcr_cassettes/projects/find_failure.yml +27 -23
  229. data/spec/vcr_cassettes/projects/find_id_1.yml +29 -25
  230. data/spec/vcr_cassettes/projects/find_new.yml +30 -26
  231. data/spec/vcr_cassettes/projects/multi_param_find_by_hash.yml +31 -26
  232. data/spec/vcr_cassettes/projects/save_new.yml +29 -25
  233. data/spec/vcr_cassettes/projects/save_old.yml +30 -26
  234. data/spec/vcr_cassettes/projects/single_param_find_by_hash.yml +29 -25
  235. data/spec/vcr_cassettes/termsofpayments/all.yml +32 -32
  236. data/spec/vcr_cassettes/termsofpayments/find_failure.yml +27 -23
  237. data/spec/vcr_cassettes/termsofpayments/find_id_1.yml +29 -26
  238. data/spec/vcr_cassettes/termsofpayments/find_new.yml +29 -25
  239. data/spec/vcr_cassettes/termsofpayments/save_new.yml +29 -25
  240. data/spec/vcr_cassettes/termsofpayments/save_old.yml +29 -25
  241. data/spec/vcr_cassettes/units/all.yml +29 -32
  242. data/spec/vcr_cassettes/units/find_failure.yml +27 -23
  243. data/spec/vcr_cassettes/units/find_id_1.yml +29 -25
  244. data/spec/vcr_cassettes/units/find_new.yml +29 -25
  245. data/spec/vcr_cassettes/units/save_new.yml +29 -25
  246. data/spec/vcr_cassettes/units/save_old.yml +29 -25
  247. data/spec/vcr_cassettes/units/save_with_specially_named_attribute.yml +29 -25
  248. metadata +130 -261
  249. data/lib/fortnox/api/circular_queue.rb +0 -39
  250. data/spec/fortnox/api/circular_queue_spec.rb +0 -52
  251. data/spec/support/helpers/dummy_class_helper.rb +0 -38
  252. data/spec/support/helpers/when_performing_helper.rb +0 -7
  253. data/spec/vcr_cassettes/invoices/save_new_with_country_KR.yml +0 -61
  254. data/spec/vcr_cassettes/orders/housework_without_tax_reduction_type.yml +0 -57
  255. data/temp.txt +0 -1
@@ -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
- # TODO: Following error is risen sometimes when all specs are run:
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
- describe 'wrap_entity_json_hash' do
13
- it 'should be tested'
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
- # include_context 'with JSON conversion'
16
+ let(:mapper) { Test::ProductMapper.new }
17
17
 
18
- # before do
19
- # module Test
20
- # class BaseMapper
21
- # include Fortnox::API::Mapper::ToJSON
22
- # end
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
- # let( :mapper ){ Test::ProductMapper.new }
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
- # describe 'entity_to_hash' do
29
- # let( :category1 ){ Test::Category.new( name: 'Cars', id: '1' ) }
30
- # let( :category2 ){ Test::Category.new( name: 'Fast Cars', id: '2' ) }
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
- # it 'includes JSON entity wrapper' do
44
- # expect( returned_hash ).to have_key( 'Product' )
45
- # end
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
- # context 'with keys without mapping' do
48
- # specify 'converts correctly' do
49
- # expect( inner_hash['Name'] ).to eq( 'Ford Mustang' )
50
- # end
51
- # end
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
- # context 'with keys to filter' do
54
- # specify 'filteres out those keys' do
55
- # expect( inner_hash ).not_to have_key( '@url' )
56
- # end
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
- # context 'with nested models' do
60
- # let( :expected_nested_model_hash ) do
61
- # [{"Name" => "Cars", "ID" => "1"}, {"Name" => "Fast Cars", "ID" => "2"}]
62
- # end
55
+ specify 'are converted correctly' do
56
+ expect(inner_hash['Categories']).to eq(expected_nested_model_hash)
57
+ end
58
+ end
63
59
 
64
- # specify 'are converted correctly' do
65
- # expect( inner_hash['Categories'] ).to eq( expected_nested_model_hash )
66
- # end
67
- # end
60
+ describe 'nested model' do
61
+ let(:expected_nested_model_hash) { { 'Name' => 'John Najjar', 'ID' => '23' } }
68
62
 
69
- # context 'with nested model' do
70
- # let( :expected_nested_model_hash ){ { 'Name' => 'John Najjar', 'ID' => '23' } }
71
-
72
- # specify 'is converted correctly' do
73
- # expect( inner_hash['Designer'] ).to eq( expected_nested_model_hash )
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
- is_expected.to eq('Sverige')
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 eq(nil) }
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
- before do
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
- class Category < Fortnox::API::Model::Base
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
- class ProductDesigner < Fortnox::API::Model::Base
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
- class Product < Fortnox::API::Model::Base
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
- end
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
- register_mapper(:category, Test::CategoryMapper)
54
- register_mapper(:productdesigner, Test::ProductDesignerMapper)
55
- register_mapper(:product, Test::ProductMapper)
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 { is_expected.to eq(key_map) }
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 { Unit.new.entity_to_hash(model, {}) }
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 { Unit.new.wrapped_json_hash_to_entity_hash(serialised_model_hash) }
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 { Unit.new.wrapped_json_collection_to_entities_hash(serialised_collection_hash) }
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
- using_test_classes do
9
- class Entity < Fortnox::API::Model::Base
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 { Entity.new(string: 'Test') }
19
+ subject { entity_class.new(string: 'Test') }
20
20
 
21
- it { is_expected.to be_a Entity }
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
- subject { -> { Entity.new({}) } }
28
-
29
- it { is_expected.to raise_error Fortnox::API::Exception }
30
- it { is_expected.to raise_error Fortnox::API::MissingAttributeError }
31
- it { is_expected.to raise_error Fortnox::API::MissingAttributeError, /Missing attribute :string/ }
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
- subject { -> { Entity.new(string: 'Test', account: 13_337) } }
36
-
37
- it { is_expected.to raise_error Fortnox::API::Exception }
38
- it { is_expected.to raise_error Fortnox::API::AttributeError }
39
- it { is_expected.to raise_error Fortnox::API::AttributeError, /invalid type for :account/ }
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) { Entity.new(string: 'Test') }
44
+ let(:original) { entity_class.new(string: 'Test') }
45
45
 
46
46
  context 'with new, simple value' do
47
- subject { updated_model }
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
- is_expected.not_to eql(original)
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
- is_expected.to eql(original)
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 = Entity.new(string: 'Saved', new: false, unsaved: false)
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
- subject { -> { described_class.new } }
13
-
14
- it { is_expected.to raise_error(Fortnox::API::MissingAttributeError, /Missing attribute.*:code/) }
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, order: :defined, integration: true do
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
- # When recording new VCR cassettes, expected matches must be increased
30
- include_examples '.all', 29
32
+ # VCR: expected matches must be increased
33
+ include_examples '.all', 6
31
34
 
32
- # When recording new VCR cassettes, expected matches must be increased
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: 1 }, matches: 13 } }
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: 1, description: 'Cykelpump' }, matches: 1 }
42
+ { find_hash: { articlenumber: 101, description: 'Hammer' }, matches: 1 }
39
43
  end
40
44
  end
41
45
 
42
- include_examples '.search', :description, 'Testartikel', 2
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