fortnox-api 0.1.0 → 0.2.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 (212) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +3 -2
  3. data/.env.test +3 -0
  4. data/.rubocop.yml +32 -23
  5. data/.travis.yml +3 -2
  6. data/Guardfile +2 -2
  7. data/LICENSE.txt +165 -22
  8. data/README.md +56 -37
  9. data/fortnox-api.gemspec +9 -6
  10. data/lib/fortnox/api.rb +18 -2
  11. data/lib/fortnox/api/base.rb +5 -3
  12. data/lib/fortnox/api/environment_validation.rb +51 -6
  13. data/lib/fortnox/api/mappers.rb +49 -0
  14. data/lib/fortnox/api/mappers/base.rb +47 -0
  15. data/lib/fortnox/api/mappers/base/from_json.rb +78 -0
  16. data/lib/fortnox/api/mappers/base/to_json.rb +65 -0
  17. data/lib/fortnox/api/mappers/customer.rb +27 -0
  18. data/lib/fortnox/api/mappers/default_delivery_types.rb +13 -0
  19. data/lib/fortnox/api/mappers/default_templates.rb +15 -0
  20. data/lib/fortnox/api/mappers/edi_information.rb +22 -0
  21. data/lib/fortnox/api/mappers/email_information.rb +18 -0
  22. data/lib/fortnox/api/mappers/invoice.rb +27 -0
  23. data/lib/fortnox/api/mappers/invoice_row.rb +20 -0
  24. data/lib/fortnox/api/mappers/order.rb +23 -0
  25. data/lib/fortnox/api/mappers/order_row.rb +16 -0
  26. data/lib/fortnox/api/models.rb +2 -0
  27. data/lib/fortnox/api/models/base.rb +56 -13
  28. data/lib/fortnox/api/models/customer.rb +112 -101
  29. data/lib/fortnox/api/models/document_base.rb +189 -0
  30. data/lib/fortnox/api/models/invoice.rb +29 -195
  31. data/lib/fortnox/api/models/label.rb +17 -0
  32. data/lib/fortnox/api/models/order.rb +27 -0
  33. data/lib/fortnox/api/repositories.rb +2 -0
  34. data/lib/fortnox/api/repositories/base.rb +4 -5
  35. data/lib/fortnox/api/repositories/base/loaders.rb +22 -14
  36. data/lib/fortnox/api/repositories/base/savers.rb +30 -16
  37. data/lib/fortnox/api/repositories/customer.rb +3 -25
  38. data/lib/fortnox/api/repositories/invoice.rb +3 -22
  39. data/lib/fortnox/api/repositories/order.rb +16 -0
  40. data/lib/fortnox/api/request_handling.rb +3 -3
  41. data/lib/fortnox/api/types.rb +44 -0
  42. data/lib/fortnox/api/types/default_delivery_types.rb +20 -0
  43. data/lib/fortnox/api/types/default_templates.rb +23 -0
  44. data/lib/fortnox/api/types/defaulted.rb +11 -0
  45. data/lib/fortnox/api/types/document_row.rb +65 -0
  46. data/lib/fortnox/api/types/edi_information.rb +29 -0
  47. data/lib/fortnox/api/types/email_information.rb +26 -0
  48. data/lib/fortnox/api/types/enums.rb +75 -0
  49. data/lib/fortnox/api/types/invoice_row.rb +19 -0
  50. data/lib/fortnox/api/types/model.rb +40 -0
  51. data/lib/fortnox/api/types/nullable.rb +21 -0
  52. data/lib/fortnox/api/types/order_row.rb +16 -0
  53. data/lib/fortnox/api/types/required.rb +13 -0
  54. data/lib/fortnox/api/types/sized.rb +25 -0
  55. data/lib/fortnox/api/version.rb +1 -1
  56. data/spec/fortnox/api/base_spec.rb +85 -14
  57. data/spec/fortnox/api/mappers/base/from_json_spec.rb +70 -0
  58. data/spec/fortnox/api/mappers/base/to_json_spec.rb +76 -0
  59. data/spec/fortnox/api/mappers/base_spec.rb +156 -0
  60. data/spec/fortnox/api/mappers/contexts/json_conversion.rb +56 -0
  61. data/spec/fortnox/api/mappers/customer_spec.rb +25 -0
  62. data/spec/fortnox/api/mappers/default_delivery_types_spec.rb +12 -0
  63. data/spec/fortnox/api/mappers/edi_information_spec.rb +21 -0
  64. data/spec/fortnox/api/mappers/email_information_spec.rb +17 -0
  65. data/spec/fortnox/api/mappers/examples/mapper.rb +26 -0
  66. data/spec/fortnox/api/mappers/invoice_row_spec.rb +19 -0
  67. data/spec/fortnox/api/mappers/invoice_spec.rb +24 -0
  68. data/spec/fortnox/api/mappers/order_row_spec.rb +14 -0
  69. data/spec/fortnox/api/mappers/order_spec.rb +20 -0
  70. data/spec/fortnox/api/models/base_spec.rb +44 -22
  71. data/spec/fortnox/api/models/customer_spec.rb +9 -0
  72. data/spec/fortnox/api/models/examples/document_base.rb +13 -0
  73. data/spec/fortnox/api/models/examples/model.rb +13 -0
  74. data/spec/fortnox/api/models/invoice_spec.rb +7 -31
  75. data/spec/fortnox/api/models/order_spec.rb +13 -0
  76. data/spec/fortnox/api/repositories/customer_spec.rb +20 -76
  77. data/spec/fortnox/api/repositories/examples/all.rb +17 -0
  78. data/spec/fortnox/api/repositories/examples/find.rb +25 -0
  79. data/spec/fortnox/api/repositories/examples/only.rb +42 -0
  80. data/spec/fortnox/api/repositories/examples/save.rb +69 -0
  81. data/spec/fortnox/api/repositories/examples/save_with_nested_model.rb +32 -0
  82. data/spec/fortnox/api/repositories/examples/save_with_specially_named_attribute.rb +27 -0
  83. data/spec/fortnox/api/repositories/examples/search.rb +31 -0
  84. data/spec/fortnox/api/repositories/invoice_spec.rb +36 -5
  85. data/spec/fortnox/api/repositories/order_spec.rb +35 -0
  86. data/spec/fortnox/api/types/account_number_spec.rb +28 -0
  87. data/spec/fortnox/api/types/default_delivery_types_spec.rb +10 -0
  88. data/spec/fortnox/api/types/edi_information_spec.rb +13 -0
  89. data/spec/fortnox/api/types/email_information_spec.rb +13 -0
  90. data/spec/fortnox/api/types/email_spec.rb +29 -0
  91. data/spec/fortnox/api/types/enums_spec.rb +13 -0
  92. data/spec/fortnox/api/types/examples/document_row.rb +15 -0
  93. data/spec/fortnox/api/types/examples/enum.rb +48 -0
  94. data/spec/fortnox/api/types/examples/types.rb +9 -0
  95. data/spec/fortnox/api/types/house_work_types_spec.rb +60 -0
  96. data/spec/fortnox/api/types/invoice_row_spec.rb +9 -0
  97. data/spec/fortnox/api/types/model_spec.rb +56 -0
  98. data/spec/fortnox/api/types/nullable_spec.rb +57 -0
  99. data/spec/fortnox/api/types/order_row_spec.rb +13 -0
  100. data/spec/fortnox/api/types/required_spec.rb +42 -0
  101. data/spec/fortnox/api/types/sized_spec.rb +74 -0
  102. data/spec/fortnox/api_spec.rb +16 -15
  103. data/spec/spec_helper.rb +19 -9
  104. data/spec/support/helpers/dummy_class_helper.rb +19 -0
  105. data/spec/support/helpers/environment_helper.rb +7 -0
  106. data/spec/support/helpers/repository_helper.rb +8 -0
  107. data/spec/support/helpers/when_performing_helper.rb +5 -0
  108. data/spec/support/matchers.rb +1 -1
  109. data/spec/support/matchers/type.rb +17 -0
  110. data/spec/support/matchers/type/attribute_matcher.rb +39 -0
  111. data/spec/support/matchers/type/enum_matcher.rb +21 -0
  112. data/spec/support/matchers/type/have_account_number_matcher.rb +21 -0
  113. data/spec/support/matchers/type/have_country_code_matcher.rb +13 -0
  114. data/spec/support/matchers/type/have_currency_matcher.rb +7 -0
  115. data/spec/support/matchers/type/have_customer_type_matcher.rb +13 -0
  116. data/spec/support/matchers/type/have_default_delivery_type_matcher.rb +7 -0
  117. data/spec/support/matchers/type/have_discount_type_matcher.rb +7 -0
  118. data/spec/support/matchers/type/have_email_matcher.rb +22 -0
  119. data/spec/support/matchers/type/have_house_work_type_matcher.rb +7 -0
  120. data/spec/support/matchers/type/have_nullable_date_matcher.rb +58 -0
  121. data/spec/support/matchers/type/have_nullable_matcher.rb +52 -0
  122. data/spec/support/matchers/type/have_nullable_string_matcher.rb +49 -0
  123. data/spec/support/matchers/type/have_sized_float_matcher.rb +8 -0
  124. data/spec/support/matchers/type/have_sized_integer_matcher.rb +8 -0
  125. data/spec/support/matchers/type/have_sized_string_matcher.rb +35 -0
  126. data/spec/support/matchers/type/have_vat_type_matcher.rb +7 -0
  127. data/spec/support/matchers/type/numeric_matcher.rb +50 -0
  128. data/spec/support/matchers/type/require_attribute_matcher.rb +69 -0
  129. data/spec/support/matchers/type/type_matcher.rb +38 -0
  130. data/spec/vcr_cassettes/customers/all.yml +119 -9
  131. data/spec/vcr_cassettes/customers/find_id_1.yml +8 -9
  132. data/spec/vcr_cassettes/customers/find_new.yml +46 -0
  133. data/spec/vcr_cassettes/customers/save_new.yml +9 -11
  134. data/spec/vcr_cassettes/customers/save_old.yml +9 -12
  135. data/spec/vcr_cassettes/customers/save_with_specially_named_attribute.yml +45 -0
  136. data/spec/vcr_cassettes/customers/search_by_name.yml +66 -0
  137. data/spec/vcr_cassettes/customers/search_miss.yml +45 -0
  138. data/spec/vcr_cassettes/invoices/all.yml +104 -0
  139. data/spec/vcr_cassettes/invoices/filter_hit.yml +46 -0
  140. data/spec/vcr_cassettes/invoices/filter_invalid.yml +42 -0
  141. data/spec/vcr_cassettes/invoices/find_id_1.yml +47 -0
  142. data/spec/vcr_cassettes/invoices/find_new.yml +49 -0
  143. data/spec/vcr_cassettes/invoices/save_new.yml +48 -0
  144. data/spec/vcr_cassettes/invoices/save_old.yml +49 -0
  145. data/spec/vcr_cassettes/invoices/save_with_nested_model.yml +47 -0
  146. data/spec/vcr_cassettes/invoices/save_with_specially_named_attribute.yml +47 -0
  147. data/spec/vcr_cassettes/invoices/search_by_name.yml +48 -0
  148. data/spec/vcr_cassettes/invoices/search_miss.yml +45 -0
  149. data/spec/vcr_cassettes/orders/all.yml +144 -0
  150. data/spec/vcr_cassettes/orders/filter_hit.yml +48 -0
  151. data/spec/vcr_cassettes/orders/filter_invalid.yml +42 -0
  152. data/spec/vcr_cassettes/orders/find_id_1.yml +48 -0
  153. data/spec/vcr_cassettes/orders/find_new.yml +49 -0
  154. data/spec/vcr_cassettes/orders/house_work_type_babysitting.yml +47 -0
  155. data/spec/vcr_cassettes/orders/house_work_type_cleaning.yml +47 -0
  156. data/spec/vcr_cassettes/orders/house_work_type_construction.yml +47 -0
  157. data/spec/vcr_cassettes/orders/house_work_type_cooking.yml +43 -0
  158. data/spec/vcr_cassettes/orders/house_work_type_electricity.yml +47 -0
  159. data/spec/vcr_cassettes/orders/house_work_type_gardening.yml +47 -0
  160. data/spec/vcr_cassettes/orders/house_work_type_glassmetalwork.yml +47 -0
  161. data/spec/vcr_cassettes/orders/house_work_type_grounddrainagework.yml +47 -0
  162. data/spec/vcr_cassettes/orders/house_work_type_hvac.yml +47 -0
  163. data/spec/vcr_cassettes/orders/house_work_type_masonry.yml +47 -0
  164. data/spec/vcr_cassettes/orders/house_work_type_othercare.yml +47 -0
  165. data/spec/vcr_cassettes/orders/house_work_type_othercosts.yml +47 -0
  166. data/spec/vcr_cassettes/orders/house_work_type_paintingwallpapering.yml +47 -0
  167. data/spec/vcr_cassettes/orders/house_work_type_snowplowing.yml +47 -0
  168. data/spec/vcr_cassettes/orders/house_work_type_textileclothing.yml +47 -0
  169. data/spec/vcr_cassettes/orders/house_work_type_tutoring.yml +43 -0
  170. data/spec/vcr_cassettes/orders/save_new.yml +48 -0
  171. data/spec/vcr_cassettes/orders/save_old.yml +49 -0
  172. data/spec/vcr_cassettes/orders/save_with_nested_model.yml +47 -0
  173. data/spec/vcr_cassettes/orders/search_by_name.yml +47 -0
  174. data/spec/vcr_cassettes/orders/search_miss.yml +45 -0
  175. metadata +301 -71
  176. data/lib/fortnox/api/models/attributes/country_code.rb +0 -17
  177. data/lib/fortnox/api/models/attributes/currency.rb +0 -17
  178. data/lib/fortnox/api/models/edi_information.rb +0 -28
  179. data/lib/fortnox/api/models/email_information.rb +0 -25
  180. data/lib/fortnox/api/models/row.rb +0 -82
  181. data/lib/fortnox/api/repositories/base/json_convertion.rb +0 -68
  182. data/lib/fortnox/api/repositories/base/options.rb +0 -33
  183. data/lib/fortnox/api/validators.rb +0 -1
  184. data/lib/fortnox/api/validators/attributes/country_code.rb +0 -42
  185. data/lib/fortnox/api/validators/attributes/currency.rb +0 -38
  186. data/lib/fortnox/api/validators/base.rb +0 -70
  187. data/lib/fortnox/api/validators/constant.rb +0 -21
  188. data/lib/fortnox/api/validators/customer.rb +0 -29
  189. data/lib/fortnox/api/validators/edi_information.rb +0 -11
  190. data/lib/fortnox/api/validators/email_information.rb +0 -19
  191. data/lib/fortnox/api/validators/invoice.rb +0 -33
  192. data/lib/fortnox/api/validators/row.rb +0 -22
  193. data/spec/fortnox/api/models/attributes/country_code_spec.rb +0 -23
  194. data/spec/fortnox/api/models/attributes/currency_spec.rb +0 -23
  195. data/spec/fortnox/api/models/attributes/dummy_model_context.rb +0 -9
  196. data/spec/fortnox/api/models/row_spec.rb +0 -13
  197. data/spec/fortnox/api/repositories/context.rb +0 -10
  198. data/spec/fortnox/api/repositories/examples.rb +0 -16
  199. data/spec/fortnox/api/validators/attributes/country_code_spec.rb +0 -9
  200. data/spec/fortnox/api/validators/attributes/currency_spec.rb +0 -9
  201. data/spec/fortnox/api/validators/attributes/examples_for_validate.rb +0 -29
  202. data/spec/fortnox/api/validators/base_spec.rb +0 -61
  203. data/spec/fortnox/api/validators/constant_spec.rb +0 -12
  204. data/spec/fortnox/api/validators/context.rb +0 -102
  205. data/spec/fortnox/api/validators/customer_spec.rb +0 -31
  206. data/spec/fortnox/api/validators/edi_information_spec.rb +0 -18
  207. data/spec/fortnox/api/validators/email_information_spec.rb +0 -26
  208. data/spec/fortnox/api/validators/invoice_spec.rb +0 -36
  209. data/spec/fortnox/api/validators/row_spec.rb +0 -27
  210. data/spec/fortnox/api/validators/validator_examples.rb +0 -20
  211. data/spec/support/matchers/models.rb +0 -27
  212. data/spec/support/matchers/validators.rb +0 -36
@@ -0,0 +1,32 @@
1
+ # TODO: This will not work until we solve issue #62.
2
+ # Until then, these tests are pending.
3
+ # rubocop:disable RSpec/DescribeClass
4
+ shared_examples_for '.save with nested model' do |required_hash, nested_model_key, nested_model_hash, nested_entity|
5
+ describe '.save with nested model' do
6
+ let( :repository ){ described_class.new }
7
+ let( :new_hash ) do
8
+ required_hash.merge( nested_model_key => nested_entity )
9
+ end
10
+ let( :response ) do
11
+ VCR.use_cassette( "#{ vcr_dir }/save_with_nested_model" ) do
12
+ model = described_class::MODEL.new( new_hash )
13
+ repository.save( model )
14
+ end
15
+ end
16
+
17
+ it 'does not raise any errors' do
18
+ expect{ response }.not_to raise_error
19
+ end
20
+
21
+ describe 'returned entity\'s nested model' do
22
+ subject(:returned_nested_model){ response.send(nested_model_key).first }
23
+
24
+ it 'has the wanted attributes' do
25
+ nested_model_hash.each do |attribute, value|
26
+ expect(returned_nested_model.send(attribute)).to eq(value)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ # rubocop:enable RSpec/DescribeClass
@@ -0,0 +1,27 @@
1
+ # rubocop:disable RSpec/DescribeClass
2
+ # Test saving model with attributes that has specially names that needs to be mapped.
3
+ #
4
+ # NOTE: VCR cassette must be discarded when repositories are updated to reflect
5
+ # the changes!
6
+ shared_examples_for '.save with specially named attribute' do |required_hash, attribute, value|
7
+ describe '.save' do
8
+ context 'with specially named attribute' do
9
+ subject{ ->{ save_model } }
10
+
11
+ let( :new_model ){ described_class::MODEL.new( required_hash.merge(attribute => value) ) }
12
+ let( :save_model )do
13
+ VCR.use_cassette( "#{ vcr_dir }/save_with_specially_named_attribute" ) do
14
+ repository.save( new_model )
15
+ end
16
+ end
17
+
18
+ it{ is_expected.not_to raise_error }
19
+
20
+ describe 'response' do
21
+ subject{ save_model.send(attribute) }
22
+ it{ is_expected.to eq(value) }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ # rubocop:enable RSpec/DescribeClass
@@ -0,0 +1,31 @@
1
+ # rubocop:disable RSpec/DescribeClass
2
+ shared_examples_for '.search' do |attribute_hash_key_name, value, matches|
3
+ describe '.search' do
4
+
5
+ describe 'search' do
6
+ context "with no matches" do
7
+ subject do
8
+ VCR.use_cassette( "#{ vcr_dir }/search_miss" ) do
9
+ repository.search( attribute_hash_key_name => 'nothing' )
10
+ end
11
+ end
12
+
13
+ it{ is_expected.to be_instance_of( Array ) }
14
+ it{ is_expected.to have(0).entries }
15
+ end
16
+
17
+ context "with #{ matches } match(es)" do
18
+ subject do
19
+ VCR.use_cassette( "#{ vcr_dir }/search_by_name" ) do
20
+ repository.search( attribute_hash_key_name => value )
21
+ end
22
+ end
23
+
24
+ it{ is_expected.to be_instance_of( Array) }
25
+ it{ is_expected.to have(matches).entries }
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ # rubocop:enable RSpec/DescribeClass
@@ -1,10 +1,41 @@
1
1
  require 'spec_helper'
2
- require 'fortnox/api/repositories/context'
2
+ require 'fortnox/api'
3
+ require 'fortnox/api/mappers'
3
4
  require 'fortnox/api/repositories/invoice'
4
- require 'fortnox/api/models/invoice'
5
+ require 'fortnox/api/repositories/examples/all'
6
+ require 'fortnox/api/repositories/examples/find'
7
+ require 'fortnox/api/repositories/examples/search'
8
+ require 'fortnox/api/repositories/examples/save'
9
+ require 'fortnox/api/repositories/examples/save_with_nested_model'
10
+ require 'fortnox/api/repositories/examples/save_with_specially_named_attribute'
11
+ require 'fortnox/api/repositories/examples/only'
5
12
 
6
- describe Fortnox::API::Repository::Invoice do
7
- include_context 'repository context'
13
+ describe Fortnox::API::Repository::Invoice, order: :defined, integration: true do
14
+ subject(:repository){ described_class.new }
8
15
 
9
- it_behaves_like 'repositories', Fortnox::API::Model::Invoice
16
+ required_hash = { customer_number: '1' }
17
+
18
+ include_examples '.save', :comments, required_hash
19
+
20
+ nested_model_hash = { price: 10, article_number: '0000' }
21
+ include_examples '.save with nested model',
22
+ required_hash,
23
+ :invoice_rows,
24
+ nested_model_hash,
25
+ [ Fortnox::API::Types::InvoiceRow.new( nested_model_hash ) ]
26
+
27
+ include_examples '.save with specially named attribute',
28
+ required_hash,
29
+ :ocr,
30
+ '426523791'
31
+
32
+ # It is not possible to delete Invoces. Therefore, expected nr of Orders
33
+ # when running .all will continue to increase (until 100, which is max by default).
34
+ include_examples '.all', 60
35
+
36
+ include_examples '.find', 1
37
+
38
+ include_examples '.search', :customername, 'Test', 3
39
+
40
+ include_examples '.only', :fullypaid, 1
10
41
  end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api'
3
+ require 'fortnox/api/mappers'
4
+ require 'fortnox/api/repositories/order'
5
+ require 'fortnox/api/repositories/examples/all'
6
+ require 'fortnox/api/repositories/examples/find'
7
+ require 'fortnox/api/repositories/examples/only'
8
+ require 'fortnox/api/repositories/examples/save'
9
+ require 'fortnox/api/repositories/examples/save_with_nested_model'
10
+ require 'fortnox/api/repositories/examples/search'
11
+
12
+ describe Fortnox::API::Repository::Order, order: :defined, integration: true do
13
+ subject(:repository){ described_class.new }
14
+
15
+ required_hash = { customer_number: '1' }
16
+
17
+ include_examples '.save', :comments, required_hash
18
+
19
+ nested_model_hash = { price: 10, article_number: '0000', ordered_quantity: 1 }
20
+ include_examples '.save with nested model',
21
+ required_hash,
22
+ :order_rows,
23
+ nested_model_hash,
24
+ [ Fortnox::API::Types::OrderRow.new( nested_model_hash ) ]
25
+
26
+ # It is not possible to delete Orders. Therefore, expected nr of Orders
27
+ # when running .all will continue to increase (until 100, which is max by default).
28
+ include_examples '.all', 100
29
+
30
+ include_examples '.find', 1
31
+
32
+ include_examples '.search', :customername, 'A customer', 2
33
+
34
+ include_examples '.only', :cancelled, 3
35
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types'
3
+ require 'fortnox/api/types/examples/types'
4
+
5
+ describe Fortnox::API::Types do
6
+ let( :klass ){ Fortnox::API::Types::AccountNumber }
7
+
8
+ context 'AccountNumber created with nil' do
9
+ subject{ klass[ nil ] }
10
+ it{ is_expected.to be_nil }
11
+ end
12
+
13
+ context 'AccountNumber created with empty string' do
14
+ include_examples 'raises ConstraintError', ''
15
+ end
16
+
17
+ context 'AccountNumber created with valid number' do
18
+ include_examples 'equals input', 1234
19
+ end
20
+
21
+ context 'AccountNumber created with a too large number' do
22
+ include_examples 'raises ConstraintError', 10000
23
+ end
24
+
25
+ context 'AccountNumber created with a negative number' do
26
+ include_examples 'raises ConstraintError', -1
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types/default_delivery_types'
3
+
4
+ RSpec.describe Fortnox::API::Types::DefaultDeliveryTypes, type: :type do
5
+ subject{ described_class }
6
+
7
+ it{ is_expected.to have_default_delivery_type( :invoice ) }
8
+ it{ is_expected.to have_default_delivery_type( :order ) }
9
+ it{ is_expected.to have_default_delivery_type( :offer ) }
10
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types/edi_information'
3
+
4
+ RSpec.describe Fortnox::API::Types::EDIInformation, type: :type do
5
+ subject{ described_class }
6
+
7
+ it{ is_expected.to have_nullable_string( :edi_global_location_number ) }
8
+ it{ is_expected.to have_nullable_string( :edi_global_location_number_delivery ) }
9
+ it{ is_expected.to have_nullable_string( :edi_invoice_extra1 ) }
10
+ it{ is_expected.to have_nullable_string( :edi_invoice_extra2 ) }
11
+ it{ is_expected.to have_nullable_string( :edi_our_electronic_reference ) }
12
+ it{ is_expected.to have_nullable_string( :edi_your_electronic_reference ) }
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types/email_information'
3
+
4
+ RSpec.describe Fortnox::API::Types::EmailInformation, type: :type do
5
+ subject{ described_class }
6
+
7
+ it{ is_expected.to have_email( :email_address_to ) }
8
+ it{ is_expected.to have_email( :email_address_cc ) }
9
+ it{ is_expected.to have_email( :email_address_bcc ) }
10
+
11
+ it{ is_expected.to have_sized_string( :email_subject, 100 ) }
12
+ it{ is_expected.to have_sized_string( :email_body, 20000 ) }
13
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types'
3
+ require 'fortnox/api/types/examples/types'
4
+
5
+ describe Fortnox::API::Types do
6
+ let( :klass ){ Fortnox::API::Types::Email }
7
+
8
+ context 'Email created with nil' do
9
+ subject{ klass[ nil ] }
10
+ it{ is_expected.to be_nil }
11
+ end
12
+
13
+ context 'Email created with empty string' do
14
+ subject{ klass[ '' ] }
15
+ it{ is_expected.to eq('') }
16
+ end
17
+
18
+ context 'Email created with valid email' do
19
+ subject{ klass[ input ] }
20
+ let( :input ){ 'test@example.com' }
21
+ it{ is_expected.to eq input }
22
+ end
23
+
24
+ context 'Email created with more than 1024 characters' do
25
+ legal_characters = 'abcdefghijklmnopqrstuvwxyz-_+'.split('')
26
+ too_long_email = (legal_characters * 35).shuffle.join + '@example.com'
27
+ include_examples 'raises ConstraintError', too_long_email
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types'
3
+ require 'fortnox/api/types/examples/enum'
4
+
5
+ describe Fortnox::API::Types do
6
+ it_behaves_like 'enum', 'CountryCode', 'CountryCodes', auto_crop: true
7
+ it_behaves_like 'enum', 'Currency', 'Currencies', auto_crop: true
8
+ it_behaves_like 'enum', 'CustomerType', 'CustomerTypes'
9
+ it_behaves_like 'enum', 'DiscountType', 'DiscountTypes'
10
+ it_behaves_like 'enum', 'HouseWorkType', 'HouseWorkTypes'
11
+ it_behaves_like 'enum', 'VATType', 'VATTypes'
12
+ it_behaves_like 'enum', 'DefaultDeliveryType', 'DefaultDeliveryTypeValues'
13
+ end
@@ -0,0 +1,15 @@
1
+ shared_examples_for 'DocumentRow' do |valid_hash|
2
+ it{ is_expected.to have_account_number( :account_number, valid_hash ) }
3
+
4
+ it{ is_expected.to have_sized_string( :article_number, 50, valid_hash ) }
5
+ it{ is_expected.to have_sized_string( :description, 50, valid_hash ) }
6
+
7
+ it{ is_expected.to have_sized_float( :delivered_quantity, 0.0, 9_999_999_999_999.0, valid_hash ) }
8
+ it{ is_expected.to have_sized_float( :price, 0.0, 99_999_999_999.0, valid_hash ) }
9
+
10
+ it{ is_expected.to have_discount_type( :discount_type, valid_hash ) }
11
+
12
+ it{ is_expected.to have_sized_integer( :house_work_hours_to_report, 0, 99_999, valid_hash ) }
13
+
14
+ it{ is_expected.to have_house_work_type( :house_work_type, valid_hash ) }
15
+ end
@@ -0,0 +1,48 @@
1
+ require 'fortnox/api/types/examples/types'
2
+
3
+ shared_examples_for 'enum' do |name, values, auto_crop: false|
4
+ describe name do
5
+ let( :klass ){ Fortnox::API::Types.const_get(name) }
6
+
7
+ context 'created with nil' do
8
+ subject{ klass[ nil ] }
9
+ it{ is_expected.to be_nil }
10
+ end
11
+
12
+ context 'created with' do
13
+ subject{ klass[ input ] }
14
+
15
+ let( :enum_value ){ Fortnox::API::Types.const_get(values).values.sample }
16
+
17
+ context 'a random member from then enum' do
18
+ let(:input){ enum_value }
19
+ it{ is_expected.to eq enum_value }
20
+ end
21
+
22
+ context 'a symoblised, random member from the enum' do
23
+ let( :input ){ enum_value.to_sym }
24
+ it{ is_expected.to eq enum_value }
25
+ end
26
+
27
+ context 'a lower case, random member from the enum' do
28
+ let( :input ){ enum_value.downcase }
29
+ it{ is_expected.to eq enum_value }
30
+ end
31
+
32
+ context 'a string that starts like a random member from the enum' do
33
+ let( :input ){ enum_value.downcase + 'more string' }
34
+
35
+ if auto_crop
36
+ it{ is_expected.to eq enum_value }
37
+ else
38
+ subject{ ->{ klass[ input ] } }
39
+ it{ is_expected.to raise_error(Dry::Types::ConstraintError) }
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'created with invalid input' do
45
+ include_examples 'raises ConstraintError', 'r4nd0m'
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ shared_examples_for 'equals input' do |input|
2
+ subject{ klass[ input ] }
3
+ it{ is_expected.to eq input }
4
+ end
5
+
6
+ shared_examples_for 'raises ConstraintError' do |input|
7
+ subject{ ->{ klass[ input ] } }
8
+ it{ is_expected.to raise_error(Dry::Types::ConstraintError) }
9
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api'
3
+ require 'fortnox/api/types'
4
+ require 'fortnox/api/repositories/order'
5
+ require 'fortnox/api/models/order'
6
+ require 'fortnox/api/types/order_row'
7
+
8
+ # rubocop:disable RSpec/DescribeClass
9
+ describe 'HouseWorkTypes', integration: true do
10
+ let(:repository){ Fortnox::API::Repository::Order.new }
11
+ let(:valid_model) do
12
+ Fortnox::API::Model::Order.new(customer_number: '1', order_rows: [order_row])
13
+ end
14
+ let(:order_row){ Fortnox::API::Types::OrderRow.new(ordered_quantity: 1,
15
+ article_number: '0000',
16
+ house_work_type: house_work_type)}
17
+
18
+ shared_examples_for 'house work type' do |type, legacy: false|
19
+ subject do
20
+ -> do
21
+ VCR.use_cassette( "orders/house_work_type_#{ type.downcase }" ) do
22
+ repository.save(valid_model)
23
+ end
24
+ end
25
+ end
26
+
27
+ let(:error_message){ 'Skattereduktion för en av de valda husarbetestyperna har upphört.' }
28
+ let(:house_work_type){ Fortnox::API::Types::HouseWorkTypes[type] }
29
+
30
+ context "when creating an OrderRow with house_work_type set to #{ type }" do
31
+ if legacy
32
+ it 'raises an error' do
33
+ is_expected.to raise_error(Fortnox::API::RemoteServerError, error_message)
34
+ end
35
+ else
36
+ it{ is_expected.not_to raise_error }
37
+ end
38
+ end
39
+ end
40
+
41
+ it_behaves_like 'house work type', 'CONSTRUCTION'
42
+ it_behaves_like 'house work type', 'ELECTRICITY'
43
+ it_behaves_like 'house work type', 'GLASSMETALWORK'
44
+ it_behaves_like 'house work type', 'GROUNDDRAINAGEWORK'
45
+ it_behaves_like 'house work type', 'MASONRY'
46
+ it_behaves_like 'house work type', 'PAINTINGWALLPAPERING'
47
+ it_behaves_like 'house work type', 'HVAC'
48
+ it_behaves_like 'house work type', 'CLEANING'
49
+ it_behaves_like 'house work type', 'TEXTILECLOTHING'
50
+ it_behaves_like 'house work type', 'CLEANING'
51
+ it_behaves_like 'house work type', 'SNOWPLOWING'
52
+ it_behaves_like 'house work type', 'GARDENING'
53
+ it_behaves_like 'house work type', 'BABYSITTING'
54
+ it_behaves_like 'house work type', 'OTHERCARE'
55
+ it_behaves_like 'house work type', 'OTHERCOSTS'
56
+
57
+ it_behaves_like 'house work type', 'COOKING', legacy: true
58
+ it_behaves_like 'house work type', 'TUTORING', legacy: true
59
+ end
60
+ # rubocop:enable RSpec/DescribeClass
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require 'fortnox/api/types/invoice_row'
3
+ require 'fortnox/api/types/examples/document_row'
4
+
5
+ RSpec.describe Fortnox::API::Types::InvoiceRow, type: :type do
6
+ subject{ described_class }
7
+
8
+ it_behaves_like 'DocumentRow', {}
9
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+ require 'dry-struct'
3
+ require 'fortnox/api/types/model'
4
+
5
+ RSpec.describe Fortnox::API::Types::Model do
6
+ shared_examples_for 'raises error' do |error|
7
+ using_test_classes do
8
+ module Types
9
+ include Dry::Types.module
10
+
11
+ Age = Int.constrained(gt: 18).with(required: true)
12
+ end
13
+
14
+ class TypesModelUser < Fortnox::API::Types::Model
15
+ attribute :age, Types::Age
16
+ end
17
+ end
18
+
19
+ describe "User inheriting from #{ described_class }" do
20
+ subject{ ->{ TypesModelUser.new(args) } }
21
+
22
+ it{ is_expected.to raise_error(error) }
23
+ end
24
+ end
25
+
26
+ context 'without required keys' do
27
+ include_examples 'raises error', Fortnox::API::MissingAttributeError do
28
+ let(:args){ {} }
29
+ end
30
+ end
31
+
32
+ context 'when omitting optional keys' do
33
+ using_test_class do
34
+ module Types
35
+ include Dry::Types.module
36
+
37
+ module Nullable
38
+ String = Types::Strict::String.optional
39
+ end
40
+ end
41
+
42
+ class User < Fortnox::API::Types::Model
43
+ attribute :optional_string, Types::Nullable::String
44
+ end
45
+ end
46
+
47
+ subject{ ->{ User.new() } }
48
+
49
+ it{ is_expected.not_to raise_error }
50
+
51
+ describe 'optional attribute' do
52
+ subject{ User.new().optional_string }
53
+ it{ is_expected.to be nil }
54
+ end
55
+ end
56
+ end