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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fortnox
4
+ module API
5
+ module Mapper
6
+ Identity = ->(value) { value }
7
+
8
+ Registry.register(:integer, Fortnox::API::Mapper::Identity)
9
+ Registry.register(:int, Fortnox::API::Mapper::Identity)
10
+ Registry.register(:float, Fortnox::API::Mapper::Identity)
11
+ Registry.register(:string, Fortnox::API::Mapper::Identity)
12
+ Registry.register(:boolean, Fortnox::API::Mapper::Identity)
13
+ Registry.register(:falseclass, Fortnox::API::Mapper::Identity)
14
+ Registry.register(:trueclass, Fortnox::API::Mapper::Identity)
15
+ Registry.register(:nilclass, Fortnox::API::Mapper::Identity)
16
+ end
17
+ end
18
+ end
@@ -44,7 +44,7 @@ module Fortnox
44
44
  attribute :contribution_value, Types::Nullable::Float.is(:read_only)
45
45
 
46
46
  # Country Country for the document address.
47
- attribute :country, Types::CountryCode
47
+ attribute :country, Types::Country
48
48
 
49
49
  # CostCenter Code of the cost center.
50
50
  attribute :cost_center, Types::Nullable::String
@@ -74,7 +74,7 @@ module Fortnox
74
74
  attribute :delivery_city, Types::Sized::String[1024]
75
75
 
76
76
  # DeliveryCountry Country for the document delivery address.
77
- attribute :delivery_country, Types::CountryCode
77
+ attribute :delivery_country, Types::Country
78
78
 
79
79
  # DeliveryDate Date of delivery.
80
80
  attribute :delivery_date, Types::Nullable::Date
@@ -109,7 +109,7 @@ module Fortnox
109
109
  # HouseWork If there is any row of the document marked "housework".
110
110
  attribute :housework, Types::Nullable::Boolean.is(:read_only)
111
111
 
112
- attribute :labels, Types::Strict::Array.member(Label)
112
+ attribute :labels, Types::Strict::Array.of(Label)
113
113
 
114
114
  # Net Net amount
115
115
  attribute :net, Types::Nullable::Float.is(:read_only)
@@ -154,6 +154,9 @@ module Fortnox
154
154
  # TaxReduction The amount of tax reduction.
155
155
  attribute :tax_reduction, Types::Nullable::Integer.is(:read_only)
156
156
 
157
+ # TaxReductionType Tax Reduction Type
158
+ attribute :tax_reduction_type, Types::TaxReductionType
159
+
157
160
  # TermsOfDelivery Code of the terms of delivery.
158
161
  attribute :terms_of_delivery, Types::Nullable::String
159
162
 
@@ -50,7 +50,7 @@ module Fortnox
50
50
  attribute :invoice_period_end, Types::Nullable::Date.is(:read_only)
51
51
 
52
52
  # InvoiceRows Separate object
53
- attribute :invoice_rows, Types::Strict::Array.member(Types::InvoiceRow)
53
+ attribute :invoice_rows, Types::Strict::Array.of(Types::InvoiceRow)
54
54
 
55
55
  # InvoiceType The type of invoice.
56
56
  attribute :invoice_type, Types::Nullable::String
@@ -20,7 +20,7 @@ module Fortnox
20
20
  attribute :order_date, Types::Nullable::Date
21
21
 
22
22
  # OrderRows Separate object
23
- attribute :order_rows, Types::Strict::Array.member(Types::OrderRow)
23
+ attribute :order_rows, Types::Strict::Array.of(Types::OrderRow)
24
24
  end
25
25
  end
26
26
  end
@@ -16,10 +16,10 @@ module Fortnox
16
16
 
17
17
  HTTParty::Parser::SupportedFormats['text/html'] = :json
18
18
 
19
- DEFAULT_HEADERS = {
19
+ headers(
20
20
  'Content-Type' => 'application/json',
21
21
  'Accept' => 'application/json'
22
- }.freeze
22
+ )
23
23
 
24
24
  HTTP_METHODS = %i[get put post delete].freeze
25
25
 
@@ -31,21 +31,19 @@ module Fortnox
31
31
  end
32
32
 
33
33
  HTTP_METHODS.each do |method|
34
- define_method method do |*args|
35
- headers['Access-Token'] = next_access_token
34
+ define_method method do |path, options = {}, &block|
35
+ provided_headers = options[:headers] || {}
36
+ provided_headers['Client-Secret'] = client_secret
37
+ provided_headers['Access-Token'] = next_access_token
38
+ options[:headers] = provided_headers
39
+ options[:base_uri] ||= base_url
36
40
  execute do |remote|
37
- remote.send(method, *args)
41
+ remote.send(method, path, options, &block)
38
42
  end
39
43
  end
40
44
  end
41
45
 
42
46
  def initialize(keys_filtered_on_save: [:url], token_store: :default)
43
- self.class.base_uri(base_url)
44
-
45
- self.headers = DEFAULT_HEADERS.merge(
46
- 'Client-Secret' => client_secret
47
- )
48
-
49
47
  @keys_filtered_on_save = keys_filtered_on_save
50
48
  @token_store = token_store
51
49
  @mapper = Registry[Mapper::Base.canonical_name_sym(self.class::MODEL)].new
@@ -26,7 +26,6 @@ module Fortnox
26
26
  end
27
27
 
28
28
  def execute
29
- self.class.set_headers(@headers)
30
29
  response = yield(self.class)
31
30
  validate_and_parse response
32
31
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'dry-struct'
4
4
  require 'dry-types'
5
+ require 'countries'
6
+ require 'fortnox/api/types/shim/country_string'
5
7
 
6
8
  module Dry
7
9
  module Types
@@ -24,6 +26,7 @@ module Fortnox
24
26
  module API
25
27
  module Types
26
28
  include Dry::Types.module
29
+ ISO3166.configure { |config| config.locales = %i[en sv] }
27
30
 
28
31
  THE_TRUTH = { true => true, 'true' => true, false => false, 'false' => false }.freeze
29
32
 
@@ -38,16 +41,45 @@ module Fortnox
38
41
  AccountNumber = Strict::Int
39
42
  .constrained(gteq: 0, lteq: 9999)
40
43
  .optional
44
+ .constructor do |value|
45
+ next nil if value.nil? || value == ''
46
+ value
47
+ end
41
48
 
42
49
  ArticleType = Strict::String
43
50
  .constrained(included_in: ArticleTypes.values)
44
51
  .optional
45
52
  .constructor(EnumConstructors.default)
46
53
 
54
+ Country = Strict::String
55
+ .optional
56
+ .constructor do |value|
57
+ next value if value.nil? || value == ''
58
+
59
+ # Fortnox only supports Swedish translation of Sweden
60
+ next CountryString.new('SE') if value.match?(/^s(e$|we|ve)/i)
61
+
62
+ country = ::ISO3166::Country[value] ||
63
+ ::ISO3166::Country.find_country_by_name(value) ||
64
+ ::ISO3166::Country.find_country_by_translated_names(value)
65
+
66
+ raise Dry::Types::ConstraintError.new('value violates constraints', value) if country.nil?
67
+
68
+ CountryString.new(country.alpha2)
69
+ end
70
+
47
71
  CountryCode = Strict::String
48
- .constrained(included_in: CountryCodes.values)
49
72
  .optional
50
- .constructor(EnumConstructors.sized(2))
73
+ .constructor do |value|
74
+ next value if value.nil? || value == ''
75
+
76
+ country = ::ISO3166::Country[value]
77
+
78
+ raise Dry::Types::ConstraintError.new('value violates constraints', value) if country.nil?
79
+
80
+ country.alpha2
81
+ end
82
+
51
83
  Currency = Strict::String
52
84
  .constrained(included_in: Currencies.values)
53
85
  .optional
@@ -63,7 +95,7 @@ module Fortnox
63
95
  .constructor(EnumConstructors.default)
64
96
 
65
97
  Email = Strict::String
66
- .constrained(max_size: 1024, format: /^$|\A[\w+-_.]+@[\w+-_.]+\.[a-z]+\z/i)
98
+ .constrained(max_size: 1024, format: /^$|\A[[[:alnum:]]+-_.]+@[\w+-_.]+\.[a-z]+\z/i)
67
99
  .optional
68
100
  .constructor { |v| v.to_s.downcase unless v.nil? }
69
101
 
@@ -87,6 +119,11 @@ module Fortnox
87
119
  .optional
88
120
  .constructor(EnumConstructors.default)
89
121
 
122
+ TaxReductionType = Strict::String
123
+ .constrained(included_in: TaxReductionTypes.values)
124
+ .optional
125
+ .constructor(EnumConstructors.lower_case)
126
+
90
127
  require 'fortnox/api/types/model'
91
128
  require 'fortnox/api/types/default_delivery_types'
92
129
  require 'fortnox/api/types/default_templates'
@@ -17,6 +17,13 @@ module Fortnox
17
17
  value.to_s.upcase unless value.nil?
18
18
  end
19
19
  end
20
+
21
+ def self.lower_case
22
+ lambda do |value|
23
+ return nil if value == ''
24
+ value.to_s.downcase unless value.nil?
25
+ end
26
+ end
20
27
  end
21
28
 
22
29
  ArticleTypes = Types::Strict::String.enum(
@@ -25,38 +32,31 @@ module Fortnox
25
32
  DiscountTypes = Types::Strict::String.enum(
26
33
  'AMOUNT', 'PERCENT'
27
34
  )
28
- CURRENT_HOUSEWORK_TYPES = %w[
29
- CONSTRUCTION ELECTRICITY GLASSMETALWORK GROUNDDRAINAGEWORK
30
- MASONRY PAINTINGWALLPAPERING HVAC MAJORAPPLIANCEREPAIR
31
- MOVINGSERVICES ITSERVICES CLEANING TEXTILECLOTHING
32
- SNOWPLOWING GARDENING BABYSITTING OTHERCARE OTHERCOSTS
33
- ].freeze
34
- LEGACY_HOUSEWORK_TYPES = %w[COOKING TUTORING].freeze
35
+ HOUSEWORK_TYPES = {
36
+ rot: %w[
37
+ CONSTRUCTION ELECTRICITY GLASSMETALWORK GROUNDDRAINAGEWORK
38
+ MASONRY PAINTINGWALLPAPERING HVAC OTHERCOSTS
39
+ ],
40
+ rut: %w[
41
+ MAJORAPPLIANCEREPAIR MOVINGSERVICES ITSERVICES CLEANING
42
+ TEXTILECLOTHING SNOWPLOWING GARDENING BABYSITTING OTHERCARE
43
+ OTHERCOSTS
44
+ ],
45
+ legacy_rut: %w[COOKING TUTORING]
46
+ }.freeze
47
+
48
+ # TODO: RUT to be added:
49
+ # HOMEMAINTENANCE FURNISHING TRANSPORTATIONSERVICES
50
+ # WASHINGANDCAREOFCLOTHING
51
+ #
52
+ # TODO: GREEN to be added:
53
+ # SOLARCELLS STORAGESELFPRODUCEDELECTRICTY
54
+ # CHARGINGSTATIONELECTRICVEHICLE OTHERCOSTS
55
+
35
56
  HouseworkTypes = Types::Strict::String.enum(
36
- *(CURRENT_HOUSEWORK_TYPES + LEGACY_HOUSEWORK_TYPES)
37
- )
38
- CountryCodes = Types::Strict::String.enum(
39
- 'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM',
40
- 'AW', 'AU', 'AT', 'AZ', 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ',
41
- 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', 'BV', 'BR', 'IO', 'BN', 'BG', 'BF',
42
- 'BI', 'CV', 'KH', 'CM', 'CA', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC',
43
- 'CO', 'KM', 'CG', 'CD', 'CK', 'CR', 'CI', 'HR', 'CU', 'CW', 'CY', 'CZ',
44
- 'DK', 'DJ', 'DM', 'DO', 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'ET', 'FK',
45
- 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA', 'GM', 'GE', 'DE', 'GH',
46
- 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT',
47
- 'HM', 'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM',
48
- 'IL', 'IT', 'JM', 'JP', 'JE', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW',
49
- 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI', 'LT', 'LU', 'MO', 'MK',
50
- 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX',
51
- 'FM', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP',
52
- 'NL', 'NC', 'NZ', 'NI', 'NE', 'NG', 'NU', 'NF', 'MP', 'NO', 'OM', 'PK',
53
- 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN', 'PL', 'PT', 'PR', 'QA',
54
- 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF', 'PM', 'VC', 'WS',
55
- 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL', 'SG', 'SX', 'SK', 'SI', 'SB',
56
- 'SO', 'ZA', 'GS', 'SS', 'ES', 'LK', 'SD', 'SR', 'SJ', 'SZ', 'SE', 'CH',
57
- 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK', 'TO', 'TT', 'TN', 'TR',
58
- 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU',
59
- 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW'
57
+ *(HOUSEWORK_TYPES[:rot] +
58
+ HOUSEWORK_TYPES[:rut] +
59
+ HOUSEWORK_TYPES[:legacy_rut]).uniq
60
60
  )
61
61
  Currencies = Types::Strict::String.enum(
62
62
  'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
@@ -90,6 +90,11 @@ module Fortnox
90
90
  ProjectStatusTypes = Types::Strict::String.enum(
91
91
  'NOTSTARTED', 'ONGOING', 'COMPLETED'
92
92
  )
93
+ # NOTE: Yes, these needs to be in lower case...
94
+ # I know, this is stupid... Fortnox: why?!
95
+ TaxReductionTypes = Types::Strict::String.enum(
96
+ 'rot', 'rut', 'green', 'none'
97
+ )
93
98
  end
94
99
  end
95
100
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fortnox
4
+ module API
5
+ module Types
6
+ class CountryString < String
7
+ end
8
+ end
9
+ end
10
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Fortnox
4
4
  module API
5
- VERSION = '0.6.2'
5
+ VERSION = '0.8.0'
6
6
  end
7
7
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fortnox/api/circular_queue'
5
+
6
+ describe Fortnox::API::CircularQueue do
7
+ describe 'start index' do
8
+ context 'when running several times' do
9
+ subject { Set.new(samples).size }
10
+
11
+ let(:test_array) { (0..99).to_a }
12
+ let(:samples) { Array.new(100) { described_class.new(*test_array).next } }
13
+
14
+ # NOTE: This test is not perfect. We are testing that a random generator
15
+ # with 100 items to choose from does not choose the same item 100 times in a row.
16
+ # Yes, the possibility is low, but I thought I should just mention it :)
17
+ it 'does not start with the same item each time' do
18
+ is_expected.to be > 1
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '#next' do
24
+ context 'when several items in queue' do
25
+ let(:queue) { described_class.new(1, 2, 3) }
26
+ let(:first_round) { Array.new(3) { queue.next } }
27
+ let(:second_round) { Array.new(3) { queue.next } }
28
+
29
+ it 'circulates the items' do
30
+ first_round
31
+ expect(first_round[0]).to eq(queue.next)
32
+ end
33
+
34
+ it 'circulates the items in the same order each time' do
35
+ expect(first_round).to eq(second_round)
36
+ end
37
+
38
+ it 'circulates through given input' do
39
+ expect(first_round.sort).to eq([1, 2, 3])
40
+ end
41
+ end
42
+
43
+ context 'when only one item in queue' do
44
+ let(:queue) { described_class.new(1) }
45
+
46
+ it 'circulates the item' do
47
+ first_item = queue.next
48
+ expect(first_item).to eq(queue.next)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'fortnox/api/mappers/base/canonical_name_sym'
5
+
6
+ describe Fortnox::API::Mapper::CanonicalNameSym do
7
+ describe '.canonical_name_sym' do
8
+ context 'with simple class' do
9
+ using_test_class do
10
+ class TestClass
11
+ extend Fortnox::API::Mapper::CanonicalNameSym
12
+ end
13
+ end
14
+
15
+ subject { TestClass.canonical_name_sym }
16
+
17
+ it { is_expected.to eq(:testclass) }
18
+ end
19
+
20
+ context 'when class included in module' do
21
+ using_test_class do
22
+ module Something
23
+ class Test
24
+ extend Fortnox::API::Mapper::CanonicalNameSym
25
+ end
26
+ end
27
+ end
28
+
29
+ subject { Something::Test.canonical_name_sym }
30
+
31
+ it { is_expected.to eq(:test) }
32
+ end
33
+ end
34
+ end
@@ -35,6 +35,12 @@ describe Fortnox::API::Mapper::Base do
35
35
  end
36
36
  end
37
37
 
38
+ describe 'integer' do
39
+ include_examples 'identity mapper', :integer do
40
+ let(:value) { Fortnox::API::Types::Nullable::Integer[1337] }
41
+ end
42
+ end
43
+
38
44
  describe 'float' do
39
45
  include_examples 'identity mapper', :float do
40
46
  let(:value) { Fortnox::API::Types::Nullable::Float[13.37] }
@@ -111,57 +117,41 @@ describe Fortnox::API::Mapper::Base do
111
117
  end
112
118
  end
113
119
 
114
- describe 'AccountNumber' do
115
- include_examples 'identity mapper', :account_number do
116
- let(:value) { Fortnox::API::Types::AccountNumber[1234] }
117
- end
118
- end
120
+ describe 'Country' do
121
+ subject { mapper.call('GB') }
119
122
 
120
- describe 'CountryCode' do
121
- include_examples 'identity mapper', :country_code do
122
- let(:value) { Fortnox::API::Types::CountryCode['SE'] }
123
- end
124
- end
123
+ let(:mapper) { Fortnox::API::Registry[:countrystring] }
125
124
 
126
- describe 'Currency' do
127
- include_examples 'identity mapper', :currency do
128
- let(:value) { Fortnox::API::Types::Currency['SEK'] }
129
- end
130
- end
125
+ it { is_expected.to eq('United Kingdom') }
131
126
 
132
- describe 'CustomerType' do
133
- include_examples 'identity mapper', :customer_type do
134
- let(:value) { Fortnox::API::Types::CustomerType['PRIVATE'] }
135
- end
136
- end
127
+ describe 'special cases' do
128
+ context 'with SE' do
129
+ subject { mapper.call('SE') }
137
130
 
138
- describe 'DiscountType' do
139
- include_examples 'identity mapper', :discount_type do
140
- let(:value) { Fortnox::API::Types::DiscountType['PERCENT'] }
141
- end
142
- end
131
+ it 'translates code to country name in Swedish' do
132
+ is_expected.to eq('Sverige')
133
+ end
134
+ end
143
135
 
144
- describe 'Email' do
145
- include_examples 'identity mapper', :email do
146
- let(:value) { Fortnox::API::Types::Email['email@example.com'] }
147
- end
148
- end
136
+ context 'with nil value' do
137
+ subject { mapper.call(nil) }
149
138
 
150
- describe 'HouseworkType' do
151
- include_examples 'identity mapper', :housework_type do
152
- let(:value) { Fortnox::API::Types::HouseworkType['CONSTRUCTION'] }
153
- end
154
- end
139
+ it { is_expected.to eq(nil) }
140
+ end
155
141
 
156
- describe 'VATType' do
157
- include_examples 'identity mapper', :vat_type do
158
- let(:value) { Fortnox::API::Types::VATType['SEVAT'] }
159
- end
160
- end
142
+ context 'with empty string' do
143
+ subject { mapper.call('') }
144
+
145
+ it { is_expected.to eq('') }
146
+ end
161
147
 
162
- describe '#canonical_name_sym' do
163
- subject { described_class.canonical_name_sym }
148
+ context 'with nonsense' do
149
+ subject { -> { mapper.call('nonsense') } }
164
150
 
165
- it { is_expected.to eq(described_class.name.split('::').last.downcase.to_sym) }
151
+ it 'is not supported (since input is sanitised) and therefore blows up' do
152
+ raise_error(NoMethodError)
153
+ end
154
+ end
155
+ end
166
156
  end
167
157
  end