fortnox-api 1.0.0.rc2 → 1.0.0.rc4

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: 355563e337538c18df2917f19aee3e0d91a1f7763fbb3a01bad441bd3956f496
4
- data.tar.gz: 4898bf90e631edd152c4c44b1fda68c2284cc2f24e38cd712a8a0057e27a6c40
3
+ metadata.gz: f19a2c9fcfb25d0e1007a1e2d26be4c9b6a591d46c89e8944929b2db0413e839
4
+ data.tar.gz: 6453a4955e007f770edf4ab28b2ea0fb8777e06e40e3a86a06295522481d634f
5
5
  SHA512:
6
- metadata.gz: 5acaea5d925b3c8f60f817ff39d167f0e078e5ec32f7f86568cf853935ac4955431dd037c81b561ec2be081e09d46b1dbae9b3c3d204bbfbcfd2615bc4d19d50
7
- data.tar.gz: 14ddc8dbdc2da42f8c09d6bb5ee11c47ceb6fa8faba6cd51da7c97d1fc4bbf4c3adcba67e2bbc831c2783a2841d4f292b3f358d608e31d84cae8e25222fa711b
6
+ metadata.gz: 9d3853810ea665b1af6f6a1d993a19209b048146f6b8b745f8eb275778c4ac77f1a35df8c6ce0916ef92aa27e10cf1cfbe280d79d8e326d01352b1919b81644c
7
+ data.tar.gz: 4f2b91936ba25eaf2606d4751bc590f855c3a73fbc59d7a9dd80aeeaabe1e1cd8289e28c1520aeba142b2f3cf2edb564c4ac70f97013caa86b2598452baa103d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to
7
7
  [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [1.0.0.rc4] - 2026-05-15
10
+
11
+ ### Changed
12
+
13
+ - Upgraded `rest-easy` dependency to `~> 1.1.1`. This drops the runtime
14
+ dependency on `dry-inflector`, which was never used.
15
+
16
+ ## [1.0.0.rc3] - 2026-05-08
17
+
18
+ ### Changed
19
+
20
+ - `Fortnox::RequestError#message` now includes the API's
21
+ `ErrorInformation.Message` and code from the response body when present,
22
+ normalising Fortnox's inconsistent key casing (PascalCase vs lowercase)
23
+ across endpoints. Previously the message was only `"Request failed: <status>"`,
24
+ hiding the cause from logs and uncaught backtraces.
25
+ - `Article#commodity_code`, `Customer#phone`, `Invoice#accounting_method`,
26
+ `Invoice#invoice_period_reference`, `Invoice#invoice_reference`,
27
+ `Document#time_basis_reference`, `Document#total_to_pay`, and
28
+ `Document#warehouse_ready` are now flagged read-only to match the Fortnox
29
+ API. Values set on these attributes are silently excluded from save
30
+ requests; previously they were sent and rejected by the API.
31
+
32
+ ### Fixed
33
+
34
+ - `Order` and `Invoice` rows now serialise the VAT field as `VAT` instead of
35
+ `Vat`. Saving rows with a `vat` value previously failed with Fortnox
36
+ rejecting the request as `"Felaktigt fältnamn"`. This bug was introduced in the 1.0.0.rc1,
37
+ it did not exist in 0.x.
38
+
9
39
  ## [1.0.0.rc2] - 2026-05-05
10
40
 
11
41
  ### Added
@@ -22,16 +52,22 @@ and this project adheres to
22
52
  prescriptive default that didn't reflect the actual resource set. Other
23
53
  Fortnox scopes (`salary`, `bookkeeping`, etc.) can still be entered
24
54
  manually.
25
- - `TermsOfPayment.code` is now `Sized::String[25]` and required, matching
26
- Fortnox API documentation. The rest-easy rewrite for rc1 briefly lost
27
- the required flag.
28
- - `Unit.code` is now `Sized::String[20]` and required, matching Fortnox
29
- API documentation. The rest-easy rewrite for rc1 briefly lost the
30
- required flag.
55
+ - `TermsOfPayment.code` now has a 25-character limit, matching Fortnox
56
+ API documentation.
57
+ - `Unit.code` now has a 20-character limit, matching Fortnox API
58
+ documentation.
31
59
  - `Unit.description` is now `Sized::String[100]` and required, matching
32
60
  Fortnox API documentation. In 0.x and rc1 this was nullable client-side,
33
61
  but the Fortnox API rejected unset descriptions anyway.
34
62
 
63
+ ### Fixed
64
+
65
+ - `TermsOfPayment.code` is required again, matching Fortnox API
66
+ documentation. The rest-easy rewrite for rc1 briefly lost the required
67
+ flag.
68
+ - `Unit.code` is required again, matching Fortnox API documentation. The
69
+ rest-easy rewrite for rc1 briefly lost the required flag.
70
+
35
71
  ## [1.0.0.rc1] - 2026-05-04
36
72
 
37
73
  Version 1.0 is a complete rewrite of the gem and is **not** a drop-in
@@ -139,5 +175,7 @@ for the full list of breaking changes.
139
175
  For changes prior to the 1.0 rewrite, see the
140
176
  [0.x changelog](https://github.com/accodeing/fortnox-api/blob/v0.9.2/CHANGELOG.md).
141
177
 
178
+ [1.0.0.rc4]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc3...v1.0.0.rc4
179
+ [1.0.0.rc3]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc2...v1.0.0.rc3
142
180
  [1.0.0.rc2]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc1...v1.0.0.rc2
143
181
  [1.0.0.rc1]: https://github.com/accodeing/fortnox-api/releases/tag/v1.0.0.rc1
data/README.md CHANGED
@@ -16,7 +16,7 @@ Adding more resources is quick and easy, see the
16
16
  ## Status
17
17
 
18
18
  Version 1.0 is a complete rewrite, currently in release candidate
19
- (`1.0.0.rc2`). It is built on
19
+ (`1.0.0.rc4`). It is built on
20
20
  [rest-easy](https://github.com/accodeing/rest-easy), replacing the old
21
21
  HTTParty + Data Mapper architecture with a single resource class per entity.
22
22
  Authorization uses the Fortnox client credentials flow.
@@ -68,8 +68,10 @@ The gem raises the following exceptions:
68
68
 
69
69
  - `Fortnox::Error` — base class for everything below. Rescue this to catch
70
70
  any error raised by the gem.
71
- - `Fortnox::RequestError` — 4xx/5xx responses from the Fortnox API. Carries
72
- the response object as `.response`.
71
+ - `Fortnox::RequestError` — 4xx/5xx responses from the Fortnox API. The
72
+ exception message includes the API's `ErrorInformation.Message` and code
73
+ when present (Fortnox is inconsistent about the key casing — the gem
74
+ normalises both). The full response is on `.response`.
73
75
  - `Fortnox::AttributeError` — base for attribute validation failures.
74
76
  - `Fortnox::ConstraintError` — an attribute value violates a type
75
77
  constraint (max size, format, etc.). Carries `.attribute_name` and
data/fortnox.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_dependency 'countries', '~> 7.1'
25
25
  spec.add_dependency 'dry-struct', '~> 1.5'
26
- spec.add_dependency 'rest-easy', '~> 1.0.0'
26
+ spec.add_dependency 'rest-easy', '~> 1.1.1'
27
27
 
28
28
  spec.metadata['rubygems_mfa_required'] = 'true'
29
29
  end
@@ -6,7 +6,8 @@ module Fortnox
6
6
  struct Structs::DocumentRow
7
7
  overrides housework: 'HouseWork',
8
8
  housework_hours_to_report: 'HouseWorkHoursToReport',
9
- housework_type: 'HouseWorkType'
9
+ housework_type: 'HouseWorkType',
10
+ vat: 'VAT'
10
11
  end
11
12
  end
12
13
  end
@@ -155,6 +155,6 @@ module Fortnox
155
155
  attr :default_stock_location, Coercible::String.optional
156
156
 
157
157
  # CommodityCode Commodity code of the article.
158
- attr :commodity_code, Coercible::String.optional
158
+ attr :commodity_code, Coercible::String.optional, :read_only
159
159
  end
160
160
  end
@@ -131,6 +131,9 @@ module Fortnox
131
131
  # Our reference
132
132
  attr :our_reference, Sized::String[50]
133
133
 
134
+ # Phone number of the customer. Only present in collection responses.
135
+ attr :phone, Coercible::String.optional, :read_only
136
+
134
137
  # First phone number of the customer
135
138
  attr :phone1, Sized::String[1024]
136
139
 
@@ -191,9 +194,6 @@ module Fortnox
191
194
  # Active If the customer is active.
192
195
  attr :active, Bool.optional, Boolean
193
196
 
194
- # Phone number of the customer. Only present in collection responses.
195
- attr :phone, Coercible::String.optional
196
-
197
197
  # External reference
198
198
  attr :external_reference, Sized::String[1024]
199
199
 
@@ -191,12 +191,12 @@ module Fortnox
191
191
  attr :outbound_date, Date.optional, Mappers::Date
192
192
 
193
193
  # TimeBasisReference Reference to time basis.
194
- attr :time_basis_reference, Coercible::Integer.optional
194
+ attr :time_basis_reference, Coercible::Integer.optional, :read_only
195
195
 
196
196
  # TotalToPay Total amount to pay.
197
- attr :total_to_pay, Coercible::Float.optional
197
+ attr :total_to_pay, Coercible::Float.optional, :read_only
198
198
 
199
199
  # WarehouseReady If the document is warehouse ready.
200
- attr :warehouse_ready, Bool.optional, Boolean
200
+ attr :warehouse_ready, Bool.optional, :read_only, Boolean
201
201
  end
202
202
  end
@@ -12,7 +12,7 @@ module Fortnox
12
12
  end
13
13
 
14
14
  # AccountingMethod Accounting Method.
15
- attr :accounting_method, AccountingMethods
15
+ attr :accounting_method, AccountingMethods, :read_only
16
16
 
17
17
  # Balance Balance of the invoice.
18
18
  attr :balance, Coercible::Float.optional, :read_only
@@ -51,10 +51,10 @@ module Fortnox
51
51
  attr :invoice_period_end, Date.optional, :read_only, Mappers::Date
52
52
 
53
53
  # InvoicePeriodReference Reference to the invoice period.
54
- attr :invoice_period_reference, Coercible::String.optional
54
+ attr :invoice_period_reference, Coercible::String.optional, :read_only
55
55
 
56
56
  # InvoiceReference Reference to another invoice.
57
- attr :invoice_reference, Coercible::String.optional
57
+ attr :invoice_reference, Coercible::String.optional, :read_only
58
58
 
59
59
  # InvoiceRows Separate object
60
60
  attr :invoice_rows, Strict::Array.of(Structs::InvoiceRow), Mappers::StructArray.for(Mappers::InvoiceRow)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fortnox
4
- VERSION = '1.0.0.rc2'
4
+ VERSION = '1.0.0.rc4'
5
5
  end
data/lib/fortnox.rb CHANGED
@@ -23,11 +23,49 @@ module Fortnox
23
23
  def initialize(arg = nil)
24
24
  if arg.respond_to?(:status)
25
25
  @response = arg
26
- super("Request failed: #{arg.status}")
26
+ super("Request failed: #{arg.status}#{format_body(arg.body)}")
27
27
  else
28
28
  super
29
29
  end
30
30
  end
31
+
32
+ BODY_FALLBACK_LIMIT = 500
33
+ private_constant :BODY_FALLBACK_LIMIT
34
+
35
+ private
36
+
37
+ def format_body(body)
38
+ return '' if body.nil? || body.empty?
39
+
40
+ " - #{error_details(body) || truncate(body.to_s)}"
41
+ end
42
+
43
+ # Fortnox have at least in the past sometimes returned HTML responses on error,
44
+ # for instance 503 Service Temporarily Unavailable.
45
+ # In that case, the body might be long and useful for debugging,
46
+ # so let's truncate it to a reasonable length if we end up here.
47
+ def truncate(string)
48
+ string.length > BODY_FALLBACK_LIMIT ? "#{string[0, BODY_FALLBACK_LIMIT]}…" : string
49
+ end
50
+
51
+ def error_details(body)
52
+ info = error_information(body)
53
+ message = info && info['message']
54
+ return nil unless message
55
+
56
+ code = info['code']
57
+ code ? "#{message} (#{code})" : message
58
+ end
59
+
60
+ def error_information(body)
61
+ parsed = body.is_a?(String) ? JSON.parse(body) : body
62
+ info = parsed['ErrorInformation'] if parsed.is_a?(Hash)
63
+ # Fortnox responds with inconsistently-cased error keys (see tests),
64
+ # so let's normalise to lowercase before reading.
65
+ info.is_a?(Hash) ? info.transform_keys(&:downcase) : nil
66
+ rescue JSON::ParserError
67
+ nil
68
+ end
31
69
  end
32
70
 
33
71
  class AttributeError < Error; end
@@ -105,7 +143,6 @@ module Fortnox
105
143
  configure do
106
144
  base_url 'https://api.fortnox.se/3'
107
145
  max_retries 3
108
- attribute_convention :PascalCase
109
146
  authentication Auth::ThreadLocal.new
110
147
  end
111
148
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fortnox-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc2
4
+ version: 1.0.0.rc4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Schubert Erlandsson
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2026-05-05 00:00:00.000000000 Z
14
+ date: 2026-05-15 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: countries
@@ -47,14 +47,14 @@ dependencies:
47
47
  requirements:
48
48
  - - "~>"
49
49
  - !ruby/object:Gem::Version
50
- version: 1.0.0
50
+ version: 1.1.1
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - "~>"
56
56
  - !ruby/object:Gem::Version
57
- version: 1.0.0
57
+ version: 1.1.1
58
58
  description: Fortnox F3 REST API library, based on rest-easy.
59
59
  email:
60
60
  - info@accodeing.com