fortnox-api 0.6.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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