fortnox-api 1.0.0.rc12 → 1.0.0.rc14

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a383d4f26222585f14be0a06145f63bb4584f8033e2eae2f91dc22cc513c085
4
- data.tar.gz: 71fe26b84df2f8bb30ddcd990b39742606827b507164d42f8b05594b069f8ad6
3
+ metadata.gz: 1c59313b416138bb0a0544e45c6b2e4166937a184cf95112247a5d45f5a44418
4
+ data.tar.gz: 25d19b69aed753b8099edafcab818c0b6b64ec989c1b2deb57d819b4aae3f69d
5
5
  SHA512:
6
- metadata.gz: c22875f971a82ee3b75168da1395ef21c75bb04ef4e521d550264435c840b5ea786abcde67d8234eded0a06d9ad4028e1926403daf62a3ed8355ae9adfd9634f
7
- data.tar.gz: '08b942421e226597317d74e1189b3a4aca90fcc5158d8b4f6d27d934a791f2af57f80c9226f406015372286187fd286e43d271fcdb8b2e501380001f55ce43f7'
6
+ metadata.gz: 8f8d49aac36c3a995c580b3776b09ef7ac88047ae01a8dc3435c4287dd12bd68681e79668815853a38d5318e3edbea156381b4298dbf398181fba52907bfdde4
7
+ data.tar.gz: 8066b72c5242c29bef520f44cce65b30e0a12b7d19318972daa887c0da181253fe95bbb9aee86fb532fb5d036148cf0c9f14424fa3a888357d43f102b5b311ed
data/CHANGELOG.md CHANGED
@@ -8,6 +8,123 @@ and this project adheres to
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.0.0.rc14] - 2026-08-11
12
+
13
+ ### Changed
14
+
15
+ - The `base64` runtime dependency is now bounded to `~> 0.2`, matching what
16
+ `rest-easy` already requires. It was declared open-ended when it was added
17
+ in 1.0.0.rc7, so a future `base64` 1.0 with a breaking change would have
18
+ been resolved into consumers' bundles unannounced.
19
+
20
+ ### Added
21
+
22
+ - **Breaking** `Fortnox::UnknownAttributeError`, raised when `new`, `stub` or
23
+ `update` is passed an attribute the resource or struct doesn't declare.
24
+ Previously the attribute was silently discarded: the request went out
25
+ without it and Fortnox accepted the result, so a typo cost a field with no
26
+ indication anything was wrong. Worst on nested rows, where
27
+ `stub(order_rows: [{ artcile_number: '1' }])` sent `"OrderRows":[{}]` and
28
+ created an order with empty rows. Subclasses `Fortnox::AttributeError` and
29
+ carries `.attribute_names` (all of them) and `.attribute_name` (the first).
30
+ Consumers passing a wider hash than the resource declares must slice it
31
+ first. Parsing an API response is unaffected and stays tolerant of fields
32
+ the gem doesn't declare — Fortnox adds them over time, and a response must
33
+ not fail to parse because of one.
34
+ - Attribute hashes now accept string keys as well as symbols, on `new`,
35
+ `stub`, `update` and struct constructors. Previously a string key matched
36
+ nothing and was dropped, which is how a Rails controller passing `params`
37
+ through produced records missing every field.
38
+ - Optional Rails integration, `require 'fortnox/rails'`. Defines `as_json` on
39
+ resources, collections and nested structs so `render json:` works when they
40
+ are nested inside another structure — ActiveSupport walks nested objects
41
+ with `as_json`, and without a definition falls through to `Object#as_json`,
42
+ which serialises instance variables and leaks `api_data`,
43
+ `model_attributes`, `changes` and `meta` into response bodies. The file is
44
+ not loaded with the rest of the gem and ActiveSupport is not a runtime
45
+ dependency; requiring it is opt-in for apps that already have Rails.
46
+
47
+ ### Fixed
48
+
49
+ - `to_json` on a resource holding nested structs no longer renders them
50
+ through `to_s`. An invoice or order with rows serialised them as
51
+ `"#<Fortnox::Structs::InvoiceRow:0x…>"`. `Fortnox::Struct#to_json` and
52
+ `Fortnox::Collection#to_json` are defined for the same reason — both
53
+ previously fell back to the default `Object#to_json`, producing an
54
+ inspect string rather than JSON. All three render the model representation
55
+ (snake_case attribute names); `to_api` still produces the Fortnox wire
56
+ format. This affects all consumers, not only Rails apps.
57
+ - Nested structs (`Fortnox::Structs::*`) now coerce boolean attributes from
58
+ the string spellings params arrive as (`'true'`, `'false'`, `'yes'`,
59
+ `'no'`, `'1'`, `'0'`, `'on'`, `'off'`), matching what resource attributes
60
+ have always accepted. Previously the struct-level type was strict and
61
+ rejected every string, so `Order.stub(order_rows: [{ housework: 'true' }])`
62
+ failed while the equivalent value on a resource attribute coerced cleanly
63
+ — callers passing Rails controller params had to cast booleans by hand
64
+ before building rows. Affects `DocumentRow#housework` and the `InvoiceRow`
65
+ and `OrderRow` subclasses. This asymmetry was introduced in 1.0.0.rc1 and
66
+ did not exist in 0.x.
67
+ - Struct construction now raises Fortnox-namespaced errors. A bad value in a
68
+ nested struct — reached directly via `Fortnox::Structs::OrderRow.new` or
69
+ indirectly via `stub`/`update` with a nested hash — previously raised
70
+ `Dry::Struct::Error`, which is a `TypeError` outside the `Fortnox::Error`
71
+ hierarchy, so `rescue Fortnox::AttributeError` blocks didn't catch it. It
72
+ now raises `Fortnox::ConstraintError` carrying `.attribute_name` and
73
+ `.value`, with the same message format as the resource-level error. This
74
+ extends the error translation added in 1.0.0.rc13, which covered resources
75
+ but not structs.
76
+
77
+ ## [1.0.0.rc13] - 2026-08-04
78
+
79
+ ### Changed
80
+
81
+ - **Breaking** String attributes now normalise `''` to `nil` at the type level. This
82
+ is the mechanism behind the reset fix below: Fortnox silently ignores
83
+ empty strings in update payloads — updating an attribute to `''` kept
84
+ the original value — and a field can only be cleared with an explicit
85
+ `null`. Normalising in the type also changes the read side: unset
86
+ string attributes read as `nil` in the model, never `''`. Fortnox
87
+ spells "unset" as `""` or `null` depending on endpoint and record
88
+ history, so the model value was previously unpredictable. Consumers
89
+ comparing against `''` must switch to `nil` checks (or call `.to_s`
90
+ if they prefer empty strings). On create, an attribute set to `''`
91
+ is now omitted from the POST body entirely (new records strip
92
+ `nil`s), leaving the field to Fortnox's default — previously `""`
93
+ was sent, which Fortnox ignores, with the same end result.
94
+ Enum-typed attributes whose value set
95
+ includes `''` (`payment_way`, `accounting_method`, `invoice_type`,
96
+ `tax_reduction_type`, `delivery_state`) are exempt: there `''` is a
97
+ real Fortnox value, not an unset spelling. For required string attributes
98
+ (`Customer#name`, `Article#description`, `Unit#code`/`#description`,
99
+ `TermsOfPayment#code`) this means updating to `''` now raises
100
+ `Fortnox::MissingAttributeError` before any request is made —
101
+ previously the empty string was sent and silently ignored by Fortnox
102
+ (clearing a required field is invalid: Fortnox rejects `null` for
103
+ them with a 400 and ignores `""`).
104
+
105
+ ### Fixed
106
+
107
+ - Resetting a string attribute to `''` on update now clears the value in
108
+ Fortnox. Previously the empty string was silently ignored by Fortnox
109
+ and the old value was left intact (reported for `Customer#comments`).
110
+ Since `''` now coerces to `nil` (see above), both `update(attr: '')`
111
+ and `update(attr: nil)` reach Fortnox as `null`, which clears. This
112
+ includes the country attributes on documents (`country_code`,
113
+ `delivery_country`), whose mapper previously turned `nil` back into
114
+ `""` on the wire, so countries could never be cleared at all.
115
+ - Numeric attributes no longer raise `Fortnox::ConstraintError` when
116
+ Fortnox returns `""` for an unset value — blank coerces to `nil`,
117
+ extending the 1.0.0.rc10 `Types::AccountNumber` fix to all integer
118
+ and float attributes (e.g. `Customer#invoice_discount`,
119
+ `Invoice#balance`). Like that bug, this was introduced in 1.0.0.rc1
120
+ and did not exist in 0.x, which coerced `""` to `0`/`0.0`.
121
+ - `#update`, `#serialise` (and `#to_api`, which goes through it) and
122
+ `.new` now raise Fortnox-namespaced errors. A coercion failure like
123
+ `customer.update(email: 'not-an-email')` previously leaked
124
+ `RestEasy::ConstraintError`, which `rescue Fortnox::ConstraintError`
125
+ blocks don't catch — error translation only covered `save`, `parse`,
126
+ `find`, `stub` and the other class-level paths.
127
+
11
128
  ## [1.0.0.rc12] - 2026-06-26
12
129
 
13
130
  ### Fixed
@@ -281,7 +398,9 @@ for the full list of breaking changes.
281
398
  For changes prior to the 1.0 rewrite, see the
282
399
  [0.x changelog](https://github.com/accodeing/fortnox-api/blob/v0.9.2/CHANGELOG.md).
283
400
 
284
- [Unreleased]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc12...HEAD
401
+ [Unreleased]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc14...HEAD
402
+ [1.0.0.rc14]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc13...v1.0.0.rc14
403
+ [1.0.0.rc13]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc12...v1.0.0.rc13
285
404
  [1.0.0.rc12]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc11...v1.0.0.rc12
286
405
  [1.0.0.rc11]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc10...v1.0.0.rc11
287
406
  [1.0.0.rc10]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc9...v1.0.0.rc10
data/README.md CHANGED
@@ -397,6 +397,58 @@ hitting some other schema-drift issue — please open an issue. There's a
397
397
  maintainer-only knob to surface those warnings; see the
398
398
  [Developer readme](DEVELOPER_README.md) for details.
399
399
 
400
+ ### Rails
401
+
402
+ Two things are worth setting up before you render or receive Fortnox data in
403
+ a Rails app.
404
+
405
+ **Rendering.** Require the Rails integration once, in an initializer:
406
+
407
+ ```ruby
408
+ # config/initializers/fortnox.rb
409
+ require 'fortnox/rails'
410
+ ```
411
+
412
+ Without it, `render json:` only works for a resource passed on its own.
413
+ Rendering one *inside* another structure walks it with `as_json`, which the
414
+ gem's types don't define outside this file, so ActiveSupport falls back to
415
+ serialising instance variables and your response body gets the gem's
416
+ internals:
417
+
418
+ ```ruby
419
+ # Without fortnox/rails
420
+ render json: { invoices: [Fortnox::Invoice.find(1)] }
421
+ # => {"invoices":[{"api_data":{…},"model_attributes":{…},"changes":[…],"meta":{…}}]}
422
+
423
+ # With it
424
+ # => {"invoices":[{"document_number":1,"invoice_rows":[{"article_number":"101"}],…}]}
425
+ ```
426
+
427
+ It covers resources, collections, and nested structs, and produces the same
428
+ representation as `to_json` — model attribute names, not the Fortnox wire
429
+ names. Rendering a collection yields its records, as an array would;
430
+ pagination stays on the object (`.total`, `.pages`, `.current_page`) for you
431
+ to render alongside if you want it.
432
+
433
+ The file is not loaded with the rest of the gem and ActiveSupport is not a
434
+ dependency of this gem — requiring it is opt-in, for apps that already have
435
+ Rails.
436
+
437
+ **Receiving params.** Controller params can be passed through as they arrive.
438
+ String keys are accepted, and string values coerce — booleans from
439
+ `'true'`/`'false'`/`'1'`/`'0'`/`'yes'`/`'no'`/`'on'`/`'off'`, numbers from
440
+ their string forms:
441
+
442
+ ```ruby
443
+ Fortnox::Order.stub('customer_number' => '1', 'order_rows' => [{ 'article_number' => '101' }])
444
+ ```
445
+
446
+ An attribute the resource or struct doesn't declare raises
447
+ `Fortnox::UnknownAttributeError` rather than being dropped, so a typo or a
448
+ stray param surfaces at the call site instead of producing a record that is
449
+ quietly missing a field. Filter params to the attributes you mean to accept,
450
+ as you would for a model.
451
+
400
452
  ### Gotchas
401
453
 
402
454
  See [docs/gotchas.md](docs/gotchas.md) for known quirks and edge cases in the
data/fortnox.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.required_ruby_version = '>= 3.2.0'
23
23
 
24
- spec.add_dependency 'base64'
24
+ spec.add_dependency 'base64', '~> 0.2'
25
25
  spec.add_dependency 'countries', '~> 7.1'
26
26
  spec.add_dependency 'dry-struct', '~> 1.5'
27
27
  spec.add_dependency 'rest-easy', '~> 1.4.0'
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fortnox
4
+ # Checks the attribute names a caller passes to `new`, `stub` and `update`.
5
+ #
6
+ # Both rest-easy and Dry::Struct build from the attributes they recognise and
7
+ # ignore everything else, so a typo or a string key used to vanish without a
8
+ # word: the request went out missing that field and Fortnox accepted it. The
9
+ # bigger the payload, the easier that is to miss.
10
+ #
11
+ # This only guards data a caller supplies. Parsing an API response stays
12
+ # tolerant of fields the gem doesn't declare — Fortnox adds them over time,
13
+ # and a response must not fail to parse because of one.
14
+ module AttributeKeys
15
+ module_function
16
+
17
+ def check(data, known:, subject:)
18
+ normalised = normalise(data)
19
+ unknown = normalised.keys - known
20
+ raise Fortnox::UnknownAttributeError.new(unknown, subject) unless unknown.empty?
21
+
22
+ normalised
23
+ end
24
+
25
+ # Rails hands params through with string keys. Accept them rather than
26
+ # reporting every attribute in the hash as unknown.
27
+ def normalise(data)
28
+ data.to_h { |key, value| [symbolise(key), value] }
29
+ end
30
+
31
+ # Left alone if it can't be a symbol, so it falls through to the unknown
32
+ # check and is reported as an attribute error rather than a NoMethodError.
33
+ def symbolise(key)
34
+ key.respond_to?(:to_sym) ? key.to_sym : key
35
+ end
36
+ end
37
+ end
@@ -7,6 +7,7 @@ module Fortnox
7
7
  # the pagination metadata Fortnox returns alongside collection responses.
8
8
  class Collection
9
9
  include Enumerable
10
+ include Serialisation::CollectionJSON
10
11
  extend Forwardable
11
12
 
12
13
  def_delegators :@items, :each, :first, :last, :size, :length, :empty?, :[], :to_a
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fortnox
4
+ # Translates rest-easy errors at the gem boundary so callers only see
5
+ # Fortnox-namespaced exceptions. Mixed into Fortnox::Resource both ways —
6
+ # `include` for the instance methods, `extend` for the class-level ones.
7
+ module ErrorTranslation
8
+ private
9
+
10
+ def with_translated_errors
11
+ yield
12
+ rescue RestEasy::ConstraintError => e
13
+ raise Fortnox::ConstraintError.new(e.attribute_name, e.value, e.message)
14
+ rescue RestEasy::MissingAttributeError => e
15
+ raise Fortnox::MissingAttributeError, e.attribute_name
16
+ rescue RestEasy::AttributeError => e
17
+ raise Fortnox::AttributeError, e.message
18
+ rescue RestEasy::RequestError => e
19
+ raise Fortnox::RequestError, e.response || e.message
20
+ end
21
+ end
22
+ end
@@ -7,8 +7,11 @@ module Fortnox
7
7
  module CountryCode
8
8
  ISO3166.configure { |config| config.locales = [:en, :sv] }
9
9
 
10
+ # Blank maps to nil in both directions, mirroring the string types:
11
+ # Fortnox spells "unset" country as "" on reads, and on updates only
12
+ # an explicit null clears the field — "" is silently ignored.
10
13
  def self.parse(country)
11
- return '' if country.nil? || country == ''
14
+ return nil if country.nil? || country == ''
12
15
 
13
16
  # Fortnox only supports Swedish translation of Sweden
14
17
  return 'SE' if country =~ /^s(e$|we|ve)/i
@@ -23,7 +26,7 @@ module Fortnox
23
26
  end
24
27
 
25
28
  def self.serialise(country_code)
26
- return '' if country_code.nil? || country_code == ''
29
+ return nil if country_code.nil? || country_code == ''
27
30
 
28
31
  return 'Sverige' if country_code == 'SE'
29
32
 
@@ -33,7 +33,11 @@ module Fortnox
33
33
  attributes = data.transform_keys do |api_key|
34
34
  api_to_model_map[api_key] || CONVENTION.parse(api_key)
35
35
  end
36
- struct_class.new(attributes)
36
+ # Drop fields the struct doesn't declare. Fortnox adds them over
37
+ # time, and a response must not fail to parse because of one — the
38
+ # strictness on `new` is aimed at what a caller passes, not at what
39
+ # the API returns.
40
+ struct_class.new(attributes.slice(*struct_class.attribute_names))
37
41
  end
38
42
 
39
43
  def serialise(struct)
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fortnox'
4
+ require 'active_support/json'
5
+
6
+ # Optional Rails integration. Not loaded with the rest of the gem — require it
7
+ # explicitly, e.g. from config/initializers/fortnox.rb:
8
+ #
9
+ # require 'fortnox/rails'
10
+ #
11
+ # Rails serialises nested objects by calling `as_json` on them. Anything that
12
+ # doesn't define it falls through to `Object#as_json`, which dumps instance
13
+ # variables — so without this, `render json: { invoices: [invoice] }` puts the
14
+ # gem's internals (`api_data`, `model_attributes`, `changes`, `meta`) in the
15
+ # response body. `to_json` needs no help here; it is correct without Rails.
16
+ module Fortnox
17
+ # Deliberately not named `Rails`: inside `module Fortnox` that constant would
18
+ # shadow the framework's own for every other file in the gem.
19
+ module RailsSerialisation
20
+ # `:only` / `:except` are applied by Fortnox::Serialisation rather than by
21
+ # ActiveSupport, so they accept string and symbol names alike. The inner
22
+ # `as_json` is then called without options — it only needs to stringify
23
+ # keys and recurse into nested structs.
24
+ module ResourceMethods
25
+ # Same representation `to_json` produces: model attribute names.
26
+ def as_json(options = nil)
27
+ Serialisation.filter(model.attributes, options).as_json
28
+ end
29
+ end
30
+
31
+ module StructMethods
32
+ def as_json(options = nil)
33
+ Serialisation.filter(to_h, options).as_json
34
+ end
35
+ end
36
+
37
+ module CollectionMethods
38
+ def as_json(options = nil)
39
+ to_a.map { |item| item.as_json(options) }
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ Fortnox::Resource.include(Fortnox::RailsSerialisation::ResourceMethods)
46
+ Fortnox::Struct.include(Fortnox::RailsSerialisation::StructMethods)
47
+ Fortnox::Collection.include(Fortnox::RailsSerialisation::CollectionMethods)
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fortnox
4
+ # TODO: this class is still over the length limit even with error
5
+ # translation extracted — see todo.md.
6
+ # rubocop:disable Metrics/ClassLength
4
7
  class Resource < RestEasy::Resource
5
8
  include Fortnox::Types
9
+ include Serialisation::ResourceJSON
6
10
 
7
11
  settings do
8
12
  setting :instance_wrapper, reader: true
@@ -26,6 +30,9 @@ module Fortnox
26
30
 
27
31
  after_serialise { |data| default_after_serialise(data) }
28
32
 
33
+ include ErrorTranslation # instance-level methods
34
+ extend ErrorTranslation # class-level methods
35
+
29
36
  class << self
30
37
  attr_reader :registered_resources
31
38
 
@@ -42,8 +49,12 @@ module Fortnox
42
49
  end
43
50
  end
44
51
 
52
+ def new(model_data = {}, **kwargs)
53
+ with_translated_errors { super(checked_attributes(model_data.merge(kwargs))) }
54
+ end
55
+
45
56
  def stub(**model_data)
46
- with_translated_errors { super }
57
+ with_translated_errors { super(**checked_attributes(model_data)) }
47
58
  end
48
59
 
49
60
  def save(instance)
@@ -94,18 +105,11 @@ module Fortnox
94
105
 
95
106
  private
96
107
 
97
- # Translate rest-easy errors at the gem boundary so callers only see
98
- # Fortnox-namespaced exceptions.
99
- def with_translated_errors
100
- yield
101
- rescue RestEasy::ConstraintError => e
102
- raise Fortnox::ConstraintError.new(e.attribute_name, e.value, e.message)
103
- rescue RestEasy::MissingAttributeError => e
104
- raise Fortnox::MissingAttributeError, e.attribute_name
105
- rescue RestEasy::AttributeError => e
106
- raise Fortnox::AttributeError, e.message
107
- rescue RestEasy::RequestError => e
108
- raise Fortnox::RequestError, e.response || e.message
108
+ # Attribute names a caller may pass. Read-only attributes are included:
109
+ # rest-easy drops them from the payload later, and rejecting them here
110
+ # would break round-tripping a parsed record back through `update`.
111
+ def checked_attributes(data)
112
+ AttributeKeys.check(data, known: all_attribute_definitions.keys, subject: self)
109
113
  end
110
114
 
111
115
  def extract_pagination(data)
@@ -120,6 +124,14 @@ module Fortnox
120
124
  end
121
125
  end
122
126
 
127
+ def update(changes = {}, **kwargs)
128
+ with_translated_errors { super(self.class.send(:checked_attributes, changes.merge(kwargs))) }
129
+ end
130
+
131
+ def serialise(...)
132
+ with_translated_errors { super }
133
+ end
134
+
123
135
  private
124
136
 
125
137
  # Shared serialisation tail used by the base after_serialise hook. Exposed
@@ -140,4 +152,5 @@ module Fortnox
140
152
  { config.instance_wrapper => data }
141
153
  end
142
154
  end
155
+ # rubocop:enable Metrics/ClassLength
143
156
  end
@@ -12,7 +12,7 @@ module Fortnox
12
12
  end
13
13
 
14
14
  # @url Direct URL to the record.
15
- attr :url <=> '@url', Coercible::String.optional, :read_only
15
+ attr :url <=> '@url', UnsizedString, :read_only
16
16
 
17
17
  # True If the article is active
18
18
  attr :active, Bool.optional, Boolean
@@ -34,7 +34,7 @@ module Fortnox
34
34
  attr :description, Sized::String[200], :required
35
35
 
36
36
  # DisposableQuantity Disposable quantity of the article.
37
- attr :disposable_quantity, Coercible::Float.optional, :read_only
37
+ attr :disposable_quantity, UnsizedFloat, :read_only
38
38
 
39
39
  # EAN EAN bar code
40
40
  attr :ean <=> 'EAN', Sized::String[30]
@@ -80,14 +80,14 @@ module Fortnox
80
80
  attr :quantity_in_stock, Sized::Float[-100_000_000_000_000.0, 99_999_999_999_999.9]
81
81
 
82
82
  # ReservedQuantity Reserved quantity of the article
83
- attr :reserved_quantity, Coercible::Float.optional, :read_only
83
+ attr :reserved_quantity, UnsizedFloat, :read_only
84
84
 
85
85
  # SalesAccount Account number for the sales account in Sweden.
86
86
  # The number must be of an existing account.
87
87
  attr :sales_account, Types::AccountNumber
88
88
 
89
89
  # SalesPrice Price of article for its default price list
90
- attr :sales_price, Coercible::Float.optional, :read_only
90
+ attr :sales_price, UnsizedFloat, :read_only
91
91
 
92
92
  # StockGoods If the article is stock goods
93
93
  attr :stock_goods, Bool.optional, Boolean
@@ -96,27 +96,27 @@ module Fortnox
96
96
  attr :stock_place, Sized::String[100]
97
97
 
98
98
  # StockValue Value in stock of the article
99
- attr :stock_value, Coercible::Float.optional, :read_only
99
+ attr :stock_value, UnsizedFloat, :read_only
100
100
 
101
101
  # StockWarning When to start warning for low quantity in stock
102
102
  attr :stock_warning, Sized::Float[0.0, 99_999_999_999_999.9]
103
103
 
104
104
  # SupplierName Name of the supplier
105
- attr :supplier_name, Coercible::String.optional, :read_only
105
+ attr :supplier_name, UnsizedString, :read_only
106
106
 
107
107
  # SupplierNumber Supplier number for the article.
108
108
  # The number must be of an existing supplier.
109
- attr :supplier_number, Coercible::String.optional
109
+ attr :supplier_number, UnsizedString
110
110
 
111
111
  # Type The type of the article
112
112
  attr :type, ArticleTypes
113
113
 
114
114
  # Unit Unit code for the article.
115
115
  # The code must be of an existing unit.
116
- attr :unit, Coercible::String.optional
116
+ attr :unit, UnsizedString
117
117
 
118
118
  # VAT VAT percent, this is predefined by the VAT for the sales account
119
- attr :vat <=> 'VAT', Coercible::Float.optional
119
+ attr :vat <=> 'VAT', UnsizedFloat
120
120
 
121
121
  # WebshopArticle If the article is a webshop article
122
122
  attr :webshop_article, Bool.optional, Boolean
@@ -131,7 +131,7 @@ module Fortnox
131
131
  attr :expired, Bool.optional, Boolean
132
132
 
133
133
  # CostCalculationMethod Cost calculation method used for the article.
134
- attr :cost_calculation_method, Coercible::String.optional
134
+ attr :cost_calculation_method, UnsizedString
135
135
 
136
136
  # StockAccount Account number for stock.
137
137
  attr :stock_account, Types::AccountNumber
@@ -140,21 +140,21 @@ module Fortnox
140
140
  attr :stock_change_account, Types::AccountNumber
141
141
 
142
142
  # DirectCost Direct cost of the article.
143
- attr :direct_cost, Coercible::Float.optional
143
+ attr :direct_cost, UnsizedFloat
144
144
 
145
145
  # FreightCost Freight cost of the article.
146
- attr :freight_cost, Coercible::Float.optional
146
+ attr :freight_cost, UnsizedFloat
147
147
 
148
148
  # OtherCost Other cost of the article.
149
- attr :other_cost, Coercible::Float.optional
149
+ attr :other_cost, UnsizedFloat
150
150
 
151
151
  # DefaultStockPoint Default stock point for the article.
152
- attr :default_stock_point, Coercible::String.optional
152
+ attr :default_stock_point, UnsizedString
153
153
 
154
154
  # DefaultStockLocation Default stock location for the article.
155
- attr :default_stock_location, Coercible::String.optional
155
+ attr :default_stock_location, UnsizedString
156
156
 
157
157
  # CommodityCode Commodity code of the article.
158
- attr :commodity_code, Coercible::String.optional, :read_only
158
+ attr :commodity_code, UnsizedString, :read_only
159
159
  end
160
160
  end
@@ -25,7 +25,7 @@ module Fortnox
25
25
  end
26
26
 
27
27
  # Direct URL to the record.
28
- attr :url <=> '@url', Coercible::String.optional, :read_only
28
+ attr :url <=> '@url', UnsizedString, :read_only
29
29
 
30
30
  # First address of the customer
31
31
  attr :address1, Sized::String[1024]
@@ -37,7 +37,7 @@ module Fortnox
37
37
  attr :city, Sized::String[1024]
38
38
 
39
39
  # Country of the customer
40
- attr :country, Coercible::String.optional, :read_only
40
+ attr :country, UnsizedString, :read_only
41
41
 
42
42
  # Comments
43
43
  attr :comments, Sized::String[1024]
@@ -46,7 +46,7 @@ module Fortnox
46
46
  attr :currency, Currencies
47
47
 
48
48
  # Cost center of the customer
49
- attr :cost_center, Coercible::String.optional
49
+ attr :cost_center, UnsizedString
50
50
 
51
51
  # Country code of the customer
52
52
  attr :country_code, Sized::String[2]
@@ -70,7 +70,7 @@ module Fortnox
70
70
  attr :delivery_city, Sized::String[1024]
71
71
 
72
72
  # Delivery country of the customer
73
- attr :delivery_country, Coercible::String.optional, :read_only
73
+ attr :delivery_country, UnsizedString, :read_only
74
74
 
75
75
  # Delivery country code of the customer
76
76
  attr :delivery_country_code, Sized::String[2]
@@ -145,7 +145,7 @@ module Fortnox
145
145
  attr :our_reference, Sized::String[50]
146
146
 
147
147
  # Phone number of the customer. Only present in collection responses.
148
- attr :phone, Coercible::String.optional, :read_only
148
+ attr :phone, UnsizedString, :read_only
149
149
 
150
150
  # First phone number of the customer
151
151
  attr :phone1, Sized::String[1024]
@@ -154,10 +154,10 @@ module Fortnox
154
154
  attr :phone2, Sized::String[1024]
155
155
 
156
156
  # Price list of the customer
157
- attr :price_list, Coercible::String.optional
157
+ attr :price_list, UnsizedString
158
158
 
159
159
  # Project of the customer
160
- attr :project, Coercible::String.optional
160
+ attr :project, UnsizedString
161
161
 
162
162
  # Sales account of the customer
163
163
  attr :sales_account, Types::AccountNumber
@@ -166,16 +166,16 @@ module Fortnox
166
166
  attr :show_price_vat_included <=> 'ShowPriceVATIncluded', Bool.optional, Boolean
167
167
 
168
168
  # Terms of delivery code
169
- attr :terms_of_delivery, Coercible::String.optional
169
+ attr :terms_of_delivery, UnsizedString
170
170
 
171
171
  # Terms of payment code
172
- attr :terms_of_payment, Coercible::String.optional
172
+ attr :terms_of_payment, UnsizedString
173
173
 
174
174
  # Customer type
175
175
  attr :type, CustomerTypes
176
176
 
177
177
  # VAT number of the customer
178
- attr :vat_number <=> 'VATNumber', Coercible::String.optional
178
+ attr :vat_number <=> 'VATNumber', UnsizedString
179
179
 
180
180
  # VAT type of the customer
181
181
  attr :vat_type <=> 'VATType', VATTypes
@@ -187,7 +187,7 @@ module Fortnox
187
187
  attr :visiting_city, Sized::String[128]
188
188
 
189
189
  # Visit country of the customer
190
- attr :visiting_country, Coercible::String.optional, :read_only
190
+ attr :visiting_country, UnsizedString, :read_only
191
191
 
192
192
  # Visiting country code
193
193
  attr :visiting_country_code, Sized::String[2]
@@ -196,7 +196,7 @@ module Fortnox
196
196
  attr :visiting_zip_code, Sized::String[10]
197
197
 
198
198
  # Way of delivery code
199
- attr :way_of_delivery, Coercible::String.optional
199
+ attr :way_of_delivery, UnsizedString
200
200
 
201
201
  # Your reference
202
202
  attr :your_reference, Sized::String[50]