verifiabl-issuer 0.6.0 → 1.0.1

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: 38a29453b60641c65dce6fa59db036553e682fba8522515ff219292fd050a840
4
- data.tar.gz: 0fefd2221e50f281d566c4e9288431f57e1f6516c9b3dbd1e0cf8907725a2121
3
+ metadata.gz: b7c622f96124e2196fcc336d8295d30fef83a2efc296890d841aec4ef8376e50
4
+ data.tar.gz: c0e18b541a27073c6026703acd7e8eeae0b1ce6867f55f8d4847451b9eaef812
5
5
  SHA512:
6
- metadata.gz: b55577426409f44798777c70be3e21bff6f4280d072b9502bee0662f53dd0b43c98650d920f68ea1b120dc1450b43c8f5acfca4f7dbc076cf55e140a5798e16b
7
- data.tar.gz: de6f5b281c1c0dbbb603e57d35e3896105a39d5758bf1c9effd6d4c79f28b82980f9ce757200403b095a78c96d79b243817fac8ff4c70056749977a3b9488fd9
6
+ metadata.gz: d36cfeaf56c836a4cd99d5786697668664b9003bf15c3689a50034bb1e9285aa93675ace858eff1cab65b6033ee64bffb3656290a61bd9c11e643881aa83918e
7
+ data.tar.gz: dd8bd433cd88d3ab01373608eab57476afbb2770d922a4c0f22ea238dd8d0d2bd62a154a8aa30699785c68b3e8efb7a24dd0aaf93a9d2ae3b159cfeb9408bc64
data/CHANGELOG.md CHANGED
@@ -4,6 +4,43 @@ All notable changes to the Verifiabl Ruby SDK will be documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [1.0.1] - 2026-10-20
8
+
9
+ ### Changed
10
+
11
+ - AU2 and NZ2 codes may be Symbols, such as `currency: :AUD` or
12
+ `type: :lump_sum`. The gem converts them to Strings before its checks, so
13
+ every check treats both forms alike. Amounts must still be Strings.
14
+
15
+ ### Fixed
16
+
17
+ - An AU2 earnings line with `type: :lump_sum` (a Symbol) and no
18
+ `lump_sum_type` now raises `ArgumentError`, as the String form already did.
19
+ 1.0.0 sent it without the code.
20
+
21
+ ## [1.0.0] - 2026-10-19
22
+
23
+ First stable release. The public API now follows Semantic Versioning.
24
+
25
+ ### Changed
26
+
27
+ - **Breaking:** an AU2 `lump_sum` earnings line without a `lump_sum_type` now
28
+ raises `ArgumentError` before sending. The API still accepts the line from
29
+ older SDK versions. To migrate, send a `lump_sum_type` from
30
+ `PayslipCodes::Australian::LUMP_SUM_TYPES` on each lump sum.
31
+
32
+ - `PayslipCodes::Australian::BASE_RATE_PERIODS` and
33
+ `PayslipCodes::NewZealand::BASE_RATE_PERIODS` both list every period a
34
+ payslip prints a rate in: `hour`, `day`, `week`, `fortnight`, `month` and
35
+ `year`.
36
+
37
+ ### Added
38
+
39
+ - AU2 `superannuation` lines accept `contribution_type: "other"`, for an
40
+ employer contribution that is not SG, RESC or salary sacrifice, such as an
41
+ award or agreement rate above SG. `resc` excludes salary sacrifice, which has
42
+ its own `salary_sacrifice` line.
43
+
7
44
  ## [0.6.0] - 2026-10-13
8
45
 
9
46
  ### Changed
data/README.md CHANGED
@@ -9,7 +9,7 @@ client, RBS signatures, and packed-gem consumer qualification.
9
9
  Add the stable release to your bundle:
10
10
 
11
11
  ```ruby
12
- gem "verifiabl-issuer", "0.6.0"
12
+ gem "verifiabl-issuer", "1.0.1"
13
13
  ```
14
14
 
15
15
  Then run `bundle install`.
@@ -151,14 +151,14 @@ provider_encryption_key = Base64.strict_decode64(
151
151
  )
152
152
  prepared = Verifiabl::Issuer.prepare_australian_v2_payslip(
153
153
  pii: {
154
- employee_name: "Jane A. Doe",
155
- employer_name: "Example Payroll Pty Ltd",
154
+ employee_name: "Ana Leota",
155
+ employer_name: "Example Software Pty Ltd",
156
156
  employer_abn: "12 345 678 901",
157
- address: {lines: ["A204/11-17 Eve Street"], suburb: "Erskineville", state_or_territory: "NSW", postcode: "2043"}
157
+ address: {lines: ["12 Example St"], suburb: "Sydney", state_or_territory: "NSW", postcode: "2000"}
158
158
  },
159
159
  payslip_non_pii: {
160
160
  period_end: "2026-05-31", payment_date: "2026-06-04", currency: "AUD",
161
- gross: "8125.00", paygw: "2030.00", net: "6095.00"
161
+ gross: "9000.00", paygw: "2250.00", net: "6750.00"
162
162
  },
163
163
  issued_at: Time.now.utc,
164
164
  key: provider_encryption_key
@@ -223,8 +223,10 @@ nz::LEAVE_BALANCE_UNITS # => ["hours", "days", "weeks"]
223
223
  both jurisdictions. An AU2 `lump_sum` line takes a `lump_sum_type` from
224
224
  `LUMP_SUM_TYPES`, and an `etp` line takes an `etp_type` from `ETP_TYPES` and
225
225
  an `etp_component` from `ETP_COMPONENTS`. Use their strings in your normal
226
- payslip hash; the lists do not restrict input or add local enum/variant
227
- validation. The API may accept a new code before this gem is updated.
226
+ payslip hash; the lists do not restrict input or add local enum validation,
227
+ and the API may accept a new code before this gem is updated. The gem raises
228
+ before sending an AU2 `lump_sum` line without a `lump_sum_type`. A code may
229
+ also be a Symbol, such as `type: :lump_sum`; the gem sends it as a String.
228
230
  Printed-text fields such as `tax_code` and `pay_cycle` are not code sets.
229
231
 
230
232
  ### Self-managed barcode flow
@@ -244,14 +246,14 @@ require "verifiabl/issuer"
244
246
  PAYSLIP = {
245
247
  external_id: "PAY-1001",
246
248
  pii: {
247
- employee_name: "Jane A. Doe",
249
+ employee_name: "Ana Leota",
248
250
  position: "Senior Developer",
249
251
  department: "Engineering",
250
- employer_name: "Example Payroll Pty Ltd",
252
+ employer_name: "Example Software Pty Ltd",
251
253
  employer_abn: "12 345 678 901",
252
254
  bsb: "062-000",
253
255
  account_number: "****5678",
254
- account_name: "Jane A Doe",
256
+ account_name: "A Leota",
255
257
  address: {lines: ["12 Example St"], suburb: "Sydney", state_or_territory: "NSW", postcode: "2000"}
256
258
  },
257
259
  non_pii: {
@@ -320,22 +322,22 @@ require "verifiabl/issuer"
320
322
  PAYSLIP = {
321
323
  external_id: "PAY-1002",
322
324
  pii: {
323
- employee_name: "Zoë Nguyễn",
325
+ employee_name: "Ana Leota",
324
326
  ird_number: "***-***-***",
325
- position: "Product Designer",
326
- department: "Product",
327
- employer_name: "Example Payroll NZ Ltd",
327
+ position: "Senior Developer",
328
+ department: "Engineering",
329
+ employer_name: "Example Software Limited",
328
330
  account_number: "**-****-*******-**",
329
- account_name: "Zoë Nguyễn",
330
- address: {lines: ["44 Harbour Rd"], suburb: "Parnell", city: "Auckland", postcode: "1052"}
331
+ account_name: "A Leota",
332
+ address: {lines: ["12 Example Street"], suburb: "Te Aro", city: "Wellington", postcode: "6011"}
331
333
  },
332
334
  non_pii: {
333
335
  period_end: "2026-08-31",
334
336
  payment_date: "2026-09-04",
335
337
  currency: "NZD",
336
- gross: "7600.00",
337
- paye: "1710.00",
338
- net: "5890.00"
338
+ gross: "9000.00",
339
+ paye: "2283.96",
340
+ net: "6716.04"
339
341
  }
340
342
  }.freeze
341
343
 
@@ -434,7 +436,7 @@ Verifiabl:
434
436
 
435
437
  ```ruby
436
438
  plaintext = Verifiabl::Issuer.format_australian_pii(
437
- employee_name: "Jane Doe",
439
+ employee_name: "Ana Leota",
438
440
  employer_abn: "53004085616",
439
441
  address: {lines: ["12 Example St"], suburb: "Sydney", state_or_territory: "NSW", postcode: "2000"}
440
442
  )
@@ -42,7 +42,7 @@ module Verifiabl
42
42
  ].map!(&:freeze).freeze
43
43
 
44
44
  BASE_RATE_PERIODS = %w[
45
- hour day year
45
+ hour day week fortnight month year
46
46
  ].map!(&:freeze).freeze
47
47
  end
48
48
 
@@ -68,7 +68,7 @@ module Verifiabl
68
68
  ].map!(&:freeze).freeze
69
69
 
70
70
  BASE_RATE_PERIODS = %w[
71
- hour day week year
71
+ hour day week fortnight month year
72
72
  ].map!(&:freeze).freeze
73
73
  end
74
74
  end
@@ -4,56 +4,74 @@ require "json"
4
4
 
5
5
  module Verifiabl
6
6
  module Issuer
7
- # A pre-transport guard for unknown fields and the decimal grammar, not a second implementation of the API contract.
7
+ # A pre-transport guard for unknown fields, the decimal grammar and AU2 lump sum codes, not a second
8
+ # implementation of the API contract.
8
9
  module NonPiiV2
9
10
  FIELDS = JSON.parse(File.read(File.join(__dir__, "generated/non-pii-v2-fields.json"))).freeze
10
11
  DECIMAL_PATTERN = /\A-?[0-9]+(?:\.[0-9]+)?\z/
11
12
 
12
13
  module_function
13
14
 
14
- def validate!(schema, payload)
15
- check!(FIELDS.fetch(schema), payload, "payslip_non_pii")
15
+ # Returns the payload with Symbol codes as Strings, so later checks see what JSON encoding sends.
16
+ def to_wire!(schema, payload)
17
+ wire = convert!(FIELDS.fetch(schema), payload, "payslip_non_pii")
18
+ check_lump_sum_types!(wire) if schema == AUSTRALIAN_PAYSLIP_V2_SCHEMA
19
+ wire
16
20
  end
17
21
 
18
- def check!(allowed, value, path)
22
+ # The API still accepts a bare lump sum from older SDKs, but a lump sum without its STP2 code
23
+ # cannot be categorised, so this SDK requires the code before sending.
24
+ def check_lump_sum_types!(payload)
25
+ Array(payload["earnings"]).each_with_index do |line, index|
26
+ next unless line["type"] == "lump_sum" && line["lump_sum_type"].nil?
27
+
28
+ raise ArgumentError, "payslip_non_pii.earnings[#{index}].lump_sum_type is required on a lump_sum line"
29
+ end
30
+ end
31
+ private_class_method :check_lump_sum_types!
32
+
33
+ def convert!(allowed, value, path)
19
34
  case allowed
20
- when Hash then check_object!(allowed, value, path)
21
- when Array then check_array!(allowed.first, value, path)
22
- when "decimal" then check_decimal!(value, path)
23
- else check_scalar!(value, path)
35
+ when Hash then convert_object!(allowed, value, path)
36
+ when Array then convert_array!(allowed.first, value, path)
37
+ when "decimal" then decimal!(value, path)
38
+ else scalar!(value, path)
24
39
  end
25
40
  end
26
- private_class_method :check!
41
+ private_class_method :convert!
27
42
 
28
- def check_object!(allowed, value, path)
43
+ def convert_object!(allowed, value, path)
29
44
  raise ArgumentError, "#{path} must be an object" unless value.is_a?(Hash)
30
45
 
31
- value.each do |key, child|
46
+ value.to_h do |key, child|
32
47
  raise ArgumentError, "#{path}.#{key} is not permitted" unless allowed.key?(key)
33
48
 
34
- check!(allowed.fetch(key), child, "#{path}.#{key}")
49
+ [key, convert!(allowed.fetch(key), child, "#{path}.#{key}")]
35
50
  end
36
51
  end
37
- private_class_method :check_object!
52
+ private_class_method :convert_object!
38
53
 
39
- def check_array!(allowed, value, path)
54
+ def convert_array!(allowed, value, path)
40
55
  raise ArgumentError, "#{path} must be an array" unless value.is_a?(Array)
41
56
 
42
- value.each_with_index { |child, index| check!(allowed, child, "#{path}[#{index}]") }
57
+ value.each_with_index.map { |child, index| convert!(allowed, child, "#{path}[#{index}]") }
43
58
  end
44
- private_class_method :check_array!
59
+ private_class_method :convert_array!
45
60
 
46
- def check_decimal!(value, path)
47
- return if value.is_a?(String) && DECIMAL_PATTERN.match?(value)
61
+ # Amounts stay Strings only, so the SDK never guesses at a number's text.
62
+ def decimal!(value, path)
63
+ return value if value.is_a?(String) && DECIMAL_PATTERN.match?(value)
48
64
 
49
65
  raise ArgumentError, "#{path} must be a plain decimal String, for example \"1234.56\""
50
66
  end
51
- private_class_method :check_decimal!
67
+ private_class_method :decimal!
52
68
 
53
- def check_scalar!(value, path)
69
+ def scalar!(value, path)
54
70
  raise ArgumentError, "#{path} must be a scalar" if value.is_a?(Hash) || value.is_a?(Array)
71
+
72
+ value.is_a?(Symbol) ? value.to_s : value
55
73
  end
56
- private_class_method :check_scalar!
74
+ private_class_method :scalar!
57
75
  end
58
76
  end
59
77
  end
@@ -12,7 +12,10 @@ module Verifiabl
12
12
  def registration_to_wire(schema:, issued_at:, payslip_non_pii:, encryption_metadata:)
13
13
  Validation.registration!(schema: schema, issued_at: issued_at, payslip_non_pii: payslip_non_pii, encryption_metadata: encryption_metadata)
14
14
  wire_payslip = stringify_keys(payslip_non_pii)
15
- NonPiiV2.validate!(schema, wire_payslip) if [AUSTRALIAN_PAYSLIP_V2_SCHEMA, NEW_ZEALAND_PAYSLIP_V2_SCHEMA].include?(schema)
15
+ if [AUSTRALIAN_PAYSLIP_V2_SCHEMA, NEW_ZEALAND_PAYSLIP_V2_SCHEMA].include?(schema)
16
+ wire_payslip = NonPiiV2.to_wire!(schema, wire_payslip)
17
+ Validation.v2_currency!(wire_payslip)
18
+ end
16
19
  {
17
20
  "schema" => schema,
18
21
  "issued_at" => serialize_time(issued_at),
@@ -14,7 +14,7 @@ module Verifiabl
14
14
 
15
15
  def registration!(schema:, issued_at:, payslip_non_pii:, encryption_metadata:)
16
16
  registration_envelope!(schema:, issued_at:, encryption_metadata:)
17
- validate_payslip_non_pii!(schema, payslip_non_pii)
17
+ validate_payslip_non_pii!(payslip_non_pii)
18
18
  end
19
19
 
20
20
  def registration_envelope!(schema:, issued_at:, encryption_metadata:)
@@ -55,20 +55,19 @@ module Verifiabl
55
55
  end
56
56
  private_class_method :validate_encryption_metadata!
57
57
 
58
- def validate_payslip_non_pii!(schema, payslip_non_pii)
58
+ def validate_payslip_non_pii!(payslip_non_pii)
59
59
  raise ArgumentError, "payslip_non_pii must be a Hash" unless payslip_non_pii.is_a?(Hash)
60
60
  validate_iso_date!(value(payslip_non_pii, :period_start), "period_start") if key?(payslip_non_pii, :period_start)
61
61
  validate_iso_date!(value(payslip_non_pii, :period_end), "period_end") if key?(payslip_non_pii, :period_end)
62
- validate_v2_currency!(payslip_non_pii) if [AUSTRALIAN_PAYSLIP_V2_SCHEMA, NEW_ZEALAND_PAYSLIP_V2_SCHEMA].include?(schema)
63
62
  end
64
63
  private_class_method :validate_payslip_non_pii!
65
64
 
66
- def validate_v2_currency!(payslip_non_pii)
67
- return if SUPPORTED_V2_CURRENCIES.include?(value(payslip_non_pii, :currency))
65
+ # Takes the wire payslip, so a Symbol code has already become a String.
66
+ def v2_currency!(wire_payslip)
67
+ return if SUPPORTED_V2_CURRENCIES.include?(wire_payslip["currency"])
68
68
 
69
69
  raise ArgumentError, "currency is required and must be a supported ISO 4217 currency code, for example AUD"
70
70
  end
71
- private_class_method :validate_v2_currency!
72
71
 
73
72
  def validate_issued_at!(issued_at)
74
73
  return if issued_at.is_a?(Time)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Verifiabl
4
4
  module Issuer
5
- VERSION = "0.6.0"
5
+ VERSION = "1.0.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verifiabl-issuer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Verifiabl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-13 00:00:00.000000000 Z
11
+ date: 2026-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -206,7 +206,7 @@ licenses:
206
206
  metadata:
207
207
  bug_tracker_uri: https://github.com/Verifiabl/verifiabl-ruby/issues
208
208
  changelog_uri: https://github.com/Verifiabl/verifiabl-ruby/blob/main/gems/verifiabl-issuer/CHANGELOG.md
209
- documentation_uri: https://docs.verifiabl.io/payroll-providers
209
+ documentation_uri: https://docs.verifiabl.io/issuers
210
210
  homepage_uri: https://verifiabl.io
211
211
  source_code_uri: https://github.com/Verifiabl/verifiabl-ruby
212
212
  post_install_message: