fortnox-api 1.0.0.rc7 → 1.0.0.rc10

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: 1572886bdede9cde4d2de4970160e66e53b83f2dbd19f7cd5ab6165fe28a3c6b
4
- data.tar.gz: f76deefb58d635d1fc1a0583fa96a398d47131fbdb9eb5b9e5454281eeac4686
3
+ metadata.gz: d90c382b3359e0c55cda22e41eee63112f77c721bdabfd490d903cd1d0dbc34f
4
+ data.tar.gz: 9198f60533f070aa7ccbb12e0e4950aaf0d69476541ad6b13b2d23c1cec86781
5
5
  SHA512:
6
- metadata.gz: a99b87e8f1d3ef0370b3258000c4a6fe65561305338a9c1d52590faacd0ecd851e6423973c8043857a3b9aadeb750c703e51cdda3362303dda628e953ecfd521
7
- data.tar.gz: baa027a8995db227621be745ca00856c84d60f93f6772e21ca0f3c5666c94a96d0b85c992a3682b6688054eab68c4aca383936fc866e3d71057851a338617990
6
+ metadata.gz: d1847fe3c20ce526ee13328f78d2114e5abb82ac3b5de5e4e08da49989f66a91dc6bbec9eaffed96f52b1af6588689a93834ebe6e095484a780f306ebb213013
7
+ data.tar.gz: c01f1d2cbf228d825dcfd1092efe7e53ad20fd653a5dc856e03084cce174ccfb1220317afd37b52c93aae30fc6b34ad2c6f3a20e1c8f06444229983b1a094d65
data/CHANGELOG.md CHANGED
@@ -8,6 +8,46 @@ and this project adheres to
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.0.0.rc10] - 2026-05-27
12
+
13
+ ### Changed
14
+
15
+ - Upgraded `rest-easy` dependency to `~> 1.3.1`.
16
+
17
+ ### Fixed
18
+
19
+ - `Types::AccountNumber` no longer raises `Fortnox::ConstraintError` when
20
+ Fortnox returns `""` for an unset attribute using that type. Observed in production on
21
+ `Customer#sales_account`. Blank strings now coerce to `nil`.
22
+ This bug was introduced in 1.0.0.rc1 and did not exist in 0.x.
23
+
24
+ ## [1.0.0.rc9] - 2026-05-20
25
+
26
+ ### Added
27
+
28
+ - `Fortnox::ALLOWED_CHARACTERS_REGEXP` constant, exposing the character
29
+ set Fortnox accepts in text fields. Sourced from the official Fortnox
30
+ docs. Useful for pre-validating strings before sending them to the API.
31
+
32
+ ### Changed
33
+
34
+ - `Customer#default_delivery_types.invoice` now accepts `'ELECTRONICINVOICE'`
35
+ when returned by Fortnox. The value is read-only — attempting to set it from
36
+ consumer code raises `Fortnox::ConstraintError` at save time,
37
+ rather than letting Fortnox reject the request.
38
+ Unchanged values round-trip through `save` as before.
39
+
40
+ ## [1.0.0.rc8] - 2026-05-19
41
+
42
+ ### Changed
43
+
44
+ - `fortnox-setup` now prints the authorization URL and asks before
45
+ opening a browser when a non-localhost redirect URI is used, defaulting
46
+ to not opening it. Previously it always opened the URL locally, so the
47
+ browser immediately followed the redirect and the URL was lost — making
48
+ it impossible to hand off to whoever should log in (e.g. a customer).
49
+ The local-server flow is unchanged.
50
+
11
51
  ## [1.0.0.rc7] - 2026-05-19
12
52
 
13
53
  ### Changed
@@ -217,7 +257,10 @@ for the full list of breaking changes.
217
257
  For changes prior to the 1.0 rewrite, see the
218
258
  [0.x changelog](https://github.com/accodeing/fortnox-api/blob/v0.9.2/CHANGELOG.md).
219
259
 
220
- [Unreleased]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc7...HEAD
260
+ [Unreleased]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc10...HEAD
261
+ [1.0.0.rc10]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc9...v1.0.0.rc10
262
+ [1.0.0.rc9]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc8...v1.0.0.rc9
263
+ [1.0.0.rc8]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc7...v1.0.0.rc8
221
264
  [1.0.0.rc7]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc6...v1.0.0.rc7
222
265
  [1.0.0.rc6]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc5...v1.0.0.rc6
223
266
  [1.0.0.rc5]: https://github.com/accodeing/fortnox-api/compare/v1.0.0.rc4...v1.0.0.rc5
data/README.md CHANGED
@@ -18,7 +18,7 @@ Adding more resources is quick and easy — see the
18
18
  ## Status
19
19
 
20
20
  Version 1.0 is a complete rewrite, currently in release candidate
21
- (`1.0.0.rc7`). It is built on
21
+ (`1.0.0.rc8`). It is built on
22
22
  [rest-easy](https://github.com/accodeing/rest-easy), replacing the old
23
23
  HTTParty + Data Mapper architecture with a single resource class per entity.
24
24
  Authorization uses the Fortnox client credentials flow.
@@ -64,6 +64,16 @@ sending it to the API, which saves you API calls and time debugging. You can
64
64
  still get errors from the server; our implementation is not perfect. Also,
65
65
  Fortnox sometimes requires a specific combination of attributes.
66
66
 
67
+ #### Allowed characters
68
+
69
+ `Fortnox::ALLOWED_CHARACTERS_REGEXP` exposes the character set Fortnox
70
+ accepts in text fields, sourced from the [official Fortnox docs][formats].
71
+ The gem itself does not apply this regex to attribute values — it is
72
+ provided so consumers can pre-validate or sanitize strings before
73
+ sending them to the API.
74
+
75
+ [formats]: https://www.fortnox.se/developer/guides-and-good-to-know/formats-and-encoding
76
+
67
77
  #### Exceptions
68
78
 
69
79
  The gem raises the following exceptions:
data/bin/fortnox-setup CHANGED
@@ -154,15 +154,21 @@ auth_params = URI.encode_www_form(
154
154
  authorize_url = "#{OAUTH_ENDPOINT}/auth?#{auth_params}"
155
155
 
156
156
  puts
157
- puts 'Opening browser for Fortnox authorization...'
158
-
159
- open_browser(authorize_url)
160
157
 
161
158
  if use_local_server
159
+ puts 'Opening browser for Fortnox authorization...'
160
+ open_browser(authorize_url)
162
161
  puts
163
162
  puts 'Waiting for Fortnox to redirect back...'
164
163
  authorization_code = get_auth_code_from_server(LOCAL_PORT, nonce)
165
164
  else
165
+ puts 'Authorization URL. Open it to log in, or send it to whoever should'
166
+ puts 'log in to the Fortnox account being connected:'
167
+ puts
168
+ puts " #{authorize_url}"
169
+ puts
170
+ open_here = prompt('Open it in your browser now?', default: 'n')
171
+ open_browser(authorize_url) if open_here.downcase.start_with?('y')
166
172
  authorization_code = auth_code_manually
167
173
  end
168
174
 
data/fortnox.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'base64'
25
25
  spec.add_dependency 'countries', '~> 7.1'
26
26
  spec.add_dependency 'dry-struct', '~> 1.5'
27
- spec.add_dependency 'rest-easy', '~> 1.3.0'
27
+ spec.add_dependency 'rest-easy', '~> 1.3.1'
28
28
 
29
29
  spec.metadata['rubygems_mfa_required'] = 'true'
30
30
  end
@@ -11,6 +11,10 @@ module Fortnox
11
11
  scope 'customer'
12
12
  end
13
13
 
14
+ before_serialise do |_attrs|
15
+ validate_electronic_invoice_delivery_type!(default_delivery_types&.invoice)
16
+ end
17
+
14
18
  # Direct URL to the record.
15
19
  attr :url <=> '@url', Coercible::String.optional, :read_only
16
20
 
@@ -205,5 +209,24 @@ module Fortnox
205
209
 
206
210
  # WWW Website URL
207
211
  attr :www <=> 'WWW', Sized::String[128]
212
+
213
+ private
214
+
215
+ # ELECTRONICINVOICE is only possible to set in the Fortnox UI.
216
+ # Raise if a consumer tries to set it from this gem.
217
+ def validate_electronic_invoice_delivery_type!(type)
218
+ return unless type == DefaultInvoiceDeliveryTypeValues['ELECTRONICINVOICE']
219
+
220
+ set_by_consumer = meta.new? || __changes__.key?(:default_delivery_types)
221
+
222
+ return unless set_by_consumer
223
+
224
+ raise Fortnox::ConstraintError.new(
225
+ :default_delivery_types,
226
+ 'ELECTRONICINVOICE',
227
+ "Customer#default_delivery_types.invoice cannot be changed to 'ELECTRONICINVOICE' " \
228
+ 'via the API, you can only do that change from within Fortnox.'
229
+ )
230
+ end
208
231
  end
209
232
  end
@@ -3,13 +3,13 @@
3
3
  module Fortnox
4
4
  module Structs
5
5
  class DefaultDeliveryTypes < Fortnox::Struct
6
- # Default delivery type for invoices. Can be PRINT EMAIL or PRINTSERVICE.
7
- attribute? :invoice, Types::DefaultDeliveryTypeValues
6
+ # Default delivery type for invoices.
7
+ attribute? :invoice, Types::DefaultInvoiceDeliveryTypeValues
8
8
 
9
- # Default delivery type for orders. Can be PRINT EMAIL or PRINTSERVICE.
9
+ # Default delivery type for orders.
10
10
  attribute? :order, Types::DefaultDeliveryTypeValues
11
11
 
12
- # Default delivery type for offers. Can be PRINT EMAIL or PRINTSERVICE.
12
+ # Default delivery type for offers.
13
13
  attribute? :offer, Types::DefaultDeliveryTypeValues
14
14
  end
15
15
  end
data/lib/fortnox/types.rb CHANGED
@@ -66,6 +66,10 @@ module Fortnox
66
66
  'PRINT', 'EMAIL', 'PRINTSERVICE'
67
67
  )
68
68
 
69
+ DefaultInvoiceDeliveryTypeValues = Types::Strict::String.enum(
70
+ 'PRINT', 'EMAIL', 'PRINTSERVICE', 'ELECTRONICINVOICE'
71
+ )
72
+
69
73
  AccountingMethods = Types::Strict::String.enum(
70
74
  '', 'ACCRUAL', 'CASH'
71
75
  )
@@ -90,9 +94,13 @@ module Fortnox
90
94
  '', 'none', 'rot', 'rut', 'green'
91
95
  )
92
96
 
97
+ # Fortnox sometimes returns "" for unset attributes using AccountNumber as type.
98
+ # Without this constructor, "" falls through to Coercible::Integer and
99
+ # `Integer("")` raises, surfacing as Fortnox::ConstraintError.
93
100
  AccountNumber = Coercible::Integer
94
101
  .constrained(gteq: 0, lteq: 9999)
95
102
  .optional
103
+ .constructor { |v| v == '' ? nil : v }
96
104
 
97
105
  Email = Strict::String
98
106
  .constrained(max_size: 1024, format: /\A\z|\A[[[:alnum:]]+-_.]+@[[[:alnum:]]+-_.]+\.[a-z]+\z/i)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fortnox
4
- VERSION = '1.0.0.rc7'
4
+ VERSION = '1.0.0.rc10'
5
5
  end
data/lib/fortnox.rb CHANGED
@@ -93,6 +93,14 @@ module Fortnox
93
93
 
94
94
  OAUTH_TOKEN_URL = 'https://apps.fortnox.se/oauth-v1/token'
95
95
 
96
+ # Character set allowed in Fortnox text fields, per the official Fortnox docs.
97
+ # Useful for pre-validating strings before sending them to the API.
98
+ # See: https://www.fortnox.se/developer/guides-and-good-to-know/formats-and-encoding
99
+ # (The docs spell Unicode codepoints as \x{NNNN}; Ruby's regex parser uses
100
+ # \u{NNNN} for the same thing, so the three codepoints below are translated.)
101
+ ALLOWED_CHARACTERS_REGEXP =
102
+ %r{\A[\p{L}’\\\u{0308}\u{030a}a-zåäöéáœæøüA-ZÅÄÖÉÁÜŒÆØ0-9 –:.`´,;\^¤#%§£$€¢¥©™°&/()=+\-*_!?²³®½@\u{00a0}\n\r]*\z}
103
+
96
104
  class << self
97
105
  def access_token=(token)
98
106
  Thread.current[Auth::ThreadLocal::THREAD_LOCAL_KEY] = token
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.rc7
4
+ version: 1.0.0.rc10
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-19 00:00:00.000000000 Z
14
+ date: 2026-05-27 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: base64
@@ -61,14 +61,14 @@ dependencies:
61
61
  requirements:
62
62
  - - "~>"
63
63
  - !ruby/object:Gem::Version
64
- version: 1.3.0
64
+ version: 1.3.1
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - "~>"
70
70
  - !ruby/object:Gem::Version
71
- version: 1.3.0
71
+ version: 1.3.1
72
72
  description: Fortnox F3 REST API library, based on rest-easy.
73
73
  email:
74
74
  - info@accodeing.com