verifiabl-issuer 0.4.0 → 0.6.0

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: d049c2b4efee0761f9172022bee306456bc6e77d8223081196c027d289f88c48
4
- data.tar.gz: b43694a8fa98216ddb558f3f63fc9c47f7a6c5740e6f47fd9c187a78f60fe437
3
+ metadata.gz: 38a29453b60641c65dce6fa59db036553e682fba8522515ff219292fd050a840
4
+ data.tar.gz: 0fefd2221e50f281d566c4e9288431f57e1f6516c9b3dbd1e0cf8907725a2121
5
5
  SHA512:
6
- metadata.gz: 961b1387f5420386fa996309dfdf8c3b237879a6c350d31072a34a42d6a54bcc289f205fd81cae3a12da225a1f060b7fdebee1aa43ccc36ed1662b58c2a24682
7
- data.tar.gz: 9f72f1055910e0725e340510d888fe8e271613c762cf72d39061fb9703b93d7b647af63d2558f45cbadf1832214736c0a2574d31caa338901d0cdb588f58a2a3
6
+ metadata.gz: b55577426409f44798777c70be3e21bff6f4280d072b9502bee0662f53dd0b43c98650d920f68ea1b120dc1450b43c8f5acfca4f7dbc076cf55e140a5798e16b
7
+ data.tar.gz: de6f5b281c1c0dbbb603e57d35e3896105a39d5758bf1c9effd6d4c79f28b82980f9ce757200403b095a78c96d79b243817fac8ff4c70056749977a3b9488fd9
data/CHANGELOG.md CHANGED
@@ -4,6 +4,52 @@ All notable changes to the Verifiabl Ruby SDK will be documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.6.0] - 2026-10-13
8
+
9
+ ### Changed
10
+
11
+ - **Breaking:** AU2 and NZ2 payloads replace `hourly` and `annual_rate` with
12
+ `base_rate`, the base rate the payslip prints apart from the earnings lines:
13
+ `{amount: "450.00", per: "day"}`. `per` is one of
14
+ `PayslipCodes::Australian::BASE_RATE_PERIODS` or
15
+ `PayslipCodes::NewZealand::BASE_RATE_PERIODS`. AU takes `hour`, `day` or
16
+ `year`; NZ also takes `week`. To migrate, send the printed annual rate as
17
+ `base_rate` with `per: "year"`, and a printed hourly rate as `base_rate`
18
+ with `per: "hour"`. Send hours and amounts only on `ordinary` earnings
19
+ lines. The API still accepts the old fields from earlier SDK versions.
20
+
21
+ ## [0.5.0] - 2026-10-09
22
+
23
+ ### Added
24
+
25
+ - AU2 `lump_sum` earnings lines accept `lump_sum_type`
26
+ (`PayslipCodes::Australian::LUMP_SUM_TYPES`: `a_redundancy` for STP lump sum
27
+ A type R, `a_other` for A type T, `b`, `d` or `e`), and a new `etp` line takes
28
+ `etp_type` (`PayslipCodes::Australian::ETP_TYPES`: `redundancy` for ETP code
29
+ R, `other` for O, `redundancy_split` for S, `other_split` for P,
30
+ `death_dependant` for D, `death_non_dependant` for N,
31
+ `death_non_dependant_split` for B or `death_trustee` for T) and
32
+ `etp_component` (`PayslipCodes::Australian::ETP_COMPONENTS`: `taxable` or
33
+ `tax_free`). Send the taxable and tax-free components as separate `etp`
34
+ lines; tax withheld from an ETP is part of `paygw`. Lump sum W stays
35
+ `return_to_work`, and lump sum U stays `paid_leave` with
36
+ `unused_on_termination`. The gem sends a `lump_sum` line without a type, and
37
+ the API accepts that for now. It will require `lump_sum_type` before
38
+ production, once every issuer is on an SDK release with the lump sum codes.
39
+
40
+ ### Removed
41
+
42
+ - **Breaking:** removed `au.payslip.v1` and `nz.payslip.v1` registration
43
+ validation. The gem no longer requires `period_start` for those schemas; it
44
+ sends them like any other schema without a field tree, and the issuer API
45
+ rejects them. Send `au.payslip.v2` instead, for example with
46
+ `Verifiabl::Issuer.prepare_australian_v2_payslip`.
47
+ - **Breaking:** removed the P2 PII writer `Verifiabl::Issuer.format_pii`.
48
+ Verifiabl now accepts only the AU2 and NZ2 PII formats from issuers. Use
49
+ `prepare_australian_v2_payslip` or `prepare_new_zealand_v2_payslip`, or for
50
+ low-level use `format_australian_pii` or `format_new_zealand_pii` with
51
+ `encrypt_pii`. Payslips already issued with P1 or P2 still verify.
52
+
7
53
  ## [0.4.0] - 2026-10-07
8
54
 
9
55
  - Add `layout: :horizontal` to local SVG and PNG rendering, with the QR on the
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.4.0"
12
+ gem "verifiabl-issuer", "0.6.0"
13
13
  ```
14
14
 
15
15
  Then run `bundle install`.
@@ -220,10 +220,12 @@ nz::LEAVE_BALANCE_UNITS # => ["hours", "days", "weeks"]
220
220
  ```
221
221
 
222
222
  `EARNINGS_TYPES`, `PAID_LEAVE_TYPES` and `ALLOWANCE_TYPES` are available for
223
- both jurisdictions. Use their strings in your normal payslip hash; the lists
224
- do not restrict input or add local enum/variant validation. The API may
225
- accept a new code before this gem is updated. Printed-text fields such as
226
- `tax_code` and `pay_cycle` are not code sets.
223
+ both jurisdictions. An AU2 `lump_sum` line takes a `lump_sum_type` from
224
+ `LUMP_SUM_TYPES`, and an `etp` line takes an `etp_type` from `ETP_TYPES` and
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.
228
+ Printed-text fields such as `tax_code` and `pay_cycle` are not code sets.
227
229
 
228
230
  ### Self-managed barcode flow
229
231
 
@@ -425,13 +427,16 @@ failures raise `TransportError`. Request and error messages never include the su
425
427
 
426
428
  ## Offline protocol primitives
427
429
 
428
- Format and encrypt PII locally. The plaintext must never be logged or sent to Verifiabl:
430
+ Most integrations should use the v2 preparation helpers. To select the schema and formatter
431
+ yourself, format and encrypt PII locally with `format_australian_pii` (AU2, for `au.payslip.v2`) or
432
+ `format_new_zealand_pii` (NZ2, for `nz.payslip.v2`). The plaintext must never be logged or sent to
433
+ Verifiabl:
429
434
 
430
435
  ```ruby
431
- plaintext = Verifiabl::Issuer.format_pii(
436
+ plaintext = Verifiabl::Issuer.format_australian_pii(
432
437
  employee_name: "Jane Doe",
433
438
  employer_abn: "53004085616",
434
- address: "12 Example St, Sydney NSW 2000"
439
+ address: {lines: ["12 Example St"], suburb: "Sydney", state_or_territory: "NSW", postcode: "2000"}
435
440
  )
436
441
 
437
442
  encrypted = Verifiabl::Issuer.encrypt_pii(plaintext, provider_encryption_key)
@@ -13,12 +13,10 @@
13
13
  "employment_basis": null,
14
14
  "engagement_type": null,
15
15
  "award": null,
16
- "hourly": {
17
- "ordinary_rate": "decimal",
18
- "hours": "decimal",
19
- "amount": "decimal"
16
+ "base_rate": {
17
+ "amount": "decimal",
18
+ "per": null
20
19
  },
21
- "annual_rate": "decimal",
22
20
  "taxable_gross": "decimal",
23
21
  "stsl_withholding": "decimal",
24
22
  "earnings": [
@@ -30,7 +28,10 @@
30
28
  "rate": "decimal",
31
29
  "ytd_amount": "decimal",
32
30
  "allowance_type": null,
33
- "other_category": null
31
+ "other_category": null,
32
+ "lump_sum_type": null,
33
+ "etp_type": null,
34
+ "etp_component": null
34
35
  }
35
36
  ],
36
37
  "salary_sacrifice": [
@@ -79,12 +80,10 @@
79
80
  "tax_code": null,
80
81
  "employment_type": null,
81
82
  "hours_paid": "decimal",
82
- "hourly": {
83
- "ordinary_rate": "decimal",
84
- "hours": "decimal",
85
- "amount": "decimal"
83
+ "base_rate": {
84
+ "amount": "decimal",
85
+ "per": null
86
86
  },
87
- "annual_rate": "decimal",
88
87
  "earnings_not_liable_for_acc": "decimal",
89
88
  "earnings": [
90
89
  {
@@ -7,8 +7,8 @@ module Verifiabl
7
7
  module PayslipCodes
8
8
  module Australian
9
9
  EARNINGS_TYPES = %w[
10
- paid_leave allowance ordinary overtime bonus_commission directors_fees
11
- lump_sum return_to_work other
10
+ paid_leave allowance lump_sum etp ordinary overtime
11
+ bonus_commission directors_fees return_to_work other
12
12
  ].map!(&:freeze).freeze
13
13
 
14
14
  PAID_LEAVE_TYPES = %w[
@@ -24,9 +24,26 @@ module Verifiabl
24
24
  home_office non_deductible transport_fares uniform private_vehicle general
25
25
  ].map!(&:freeze).freeze
26
26
 
27
+ LUMP_SUM_TYPES = %w[
28
+ a_redundancy a_other b d e
29
+ ].map!(&:freeze).freeze
30
+
31
+ ETP_TYPES = %w[
32
+ redundancy other redundancy_split other_split death_dependant death_non_dependant
33
+ death_non_dependant_split death_trustee
34
+ ].map!(&:freeze).freeze
35
+
36
+ ETP_COMPONENTS = %w[
37
+ taxable tax_free
38
+ ].map!(&:freeze).freeze
39
+
27
40
  PAY_FREQUENCIES = %w[
28
41
  weekly fortnightly monthly quarterly four_weekly semi_monthly
29
42
  ].map!(&:freeze).freeze
43
+
44
+ BASE_RATE_PERIODS = %w[
45
+ hour day year
46
+ ].map!(&:freeze).freeze
30
47
  end
31
48
 
32
49
  module NewZealand
@@ -49,6 +66,10 @@ module Verifiabl
49
66
  LEAVE_BALANCE_UNITS = %w[
50
67
  hours days weeks
51
68
  ].map!(&:freeze).freeze
69
+
70
+ BASE_RATE_PERIODS = %w[
71
+ hour day week year
72
+ ].map!(&:freeze).freeze
52
73
  end
53
74
  end
54
75
  end
@@ -6,16 +6,12 @@ require_relative "generated/jurisdiction_pii_profiles"
6
6
  module Verifiabl
7
7
  module Issuer
8
8
  module Pii
9
- FIELD_ORDER = %i[
10
- employee_name position department employer_abn bsb account_number account_name address
11
- ].freeze
12
9
  AUSTRALIAN_FIELD_ORDER = JurisdictionPiiProfiles::AUSTRALIAN_FIELD_ORDER
13
10
  NEW_ZEALAND_FIELD_ORDER = JurisdictionPiiProfiles::NEW_ZEALAND_FIELD_ORDER
14
- PROFILE_ID = PiiTextProfile::PROFILE_ID
15
11
  AUSTRALIAN_PROFILE_ID = JurisdictionPiiProfiles::AUSTRALIAN_PROFILE_ID
16
12
  NEW_ZEALAND_PROFILE_ID = JurisdictionPiiProfiles::NEW_ZEALAND_PROFILE_ID
17
13
  PROFILE_UNICODE_VERSION = PiiTextProfile::UNICODE_VERSION
18
- PAYLOAD_MAX_BYTES = PiiTextProfile::PAYLOAD_MAX_BYTES
14
+ PAYLOAD_MAX_BYTES = JurisdictionPiiProfiles::PAYLOAD_MAX_BYTES
19
15
  FORMAT_CHARACTER_RANGES = PiiTextProfile::FORMAT_CHARACTER_RANGES
20
16
 
21
17
  Violation = Data.define(:field, :reason)
@@ -43,16 +39,8 @@ module Verifiabl
43
39
 
44
40
  module_function
45
41
 
46
- # Formats employee PII into the current P2 plaintext wire format. The
47
- # returned value must be encrypted before it is persisted or embedded.
48
- def format(fields)
49
- validate_fields!(fields)
50
- values, violations = normalize_values(fields)
51
- raise ValidationError, violations unless violations.empty?
52
-
53
- format_profile("P2", FIELD_ORDER.map { |field| values.fetch(field) })
54
- end
55
-
42
+ # Formats Australian employee PII as AU2 plaintext. The returned value
43
+ # must be encrypted before it is persisted or embedded.
56
44
  def format_australian(fields)
57
45
  allowed = %i[
58
46
  employee_name position department employer_name employer_abn bsb account_number account_name address
@@ -69,6 +57,8 @@ module Verifiabl
69
57
  format_profile(JurisdictionPiiProfiles::AUSTRALIAN_MARKER, AUSTRALIAN_FIELD_ORDER.map { |field| wire_values.fetch(field) })
70
58
  end
71
59
 
60
+ # Formats New Zealand employee PII as NZ2 plaintext. The returned value
61
+ # must be encrypted before it is persisted or embedded.
72
62
  def format_new_zealand(fields)
73
63
  allowed = %i[
74
64
  employee_name ird_number position department employer_name account_number account_name address
@@ -83,7 +73,7 @@ module Verifiabl
83
73
  format_profile(JurisdictionPiiProfiles::NEW_ZEALAND_MARKER, NEW_ZEALAND_FIELD_ORDER.map { |field| wire_values.fetch(field) })
84
74
  end
85
75
 
86
- def validate_fields!(fields, allowed = FIELD_ORDER)
76
+ def validate_fields!(fields, allowed)
87
77
  raise ArgumentError, "fields must be a Hash" unless fields.is_a?(Hash)
88
78
 
89
79
  normalized_keys = fields.keys.map do |key|
@@ -95,11 +85,6 @@ module Verifiabl
95
85
  end
96
86
  private_class_method :validate_fields!
97
87
 
98
- def normalize_values(fields)
99
- normalize_named_values(fields, FIELD_ORDER)
100
- end
101
- private_class_method :normalize_values
102
-
103
88
  def normalize_named_values(fields, names)
104
89
  names.each_with_object([{}, []]) do |field, (values, violations)|
105
90
  value, violation = normalize_value(field, field_value(fields, field))
@@ -155,8 +140,9 @@ module Verifiabl
155
140
 
156
141
  def format_profile(version, segments)
157
142
  plaintext = "#{version}|#{segments.join("|")}"
158
- limit = (version == "P2") ? PAYLOAD_MAX_BYTES : JurisdictionPiiProfiles::PAYLOAD_MAX_BYTES
159
- raise RangeError, "#{version} plaintext exceeds #{limit} UTF-8 bytes" if plaintext.bytesize > limit
143
+ if plaintext.bytesize > PAYLOAD_MAX_BYTES
144
+ raise RangeError, "#{version} plaintext exceeds #{PAYLOAD_MAX_BYTES} UTF-8 bytes"
145
+ end
160
146
 
161
147
  plaintext
162
148
  end
@@ -57,9 +57,6 @@ module Verifiabl
57
57
 
58
58
  def validate_payslip_non_pii!(schema, payslip_non_pii)
59
59
  raise ArgumentError, "payslip_non_pii must be a Hash" unless payslip_non_pii.is_a?(Hash)
60
- if %w[au.payslip.v1 nz.payslip.v1].include?(schema) && !key?(payslip_non_pii, :period_start)
61
- raise ArgumentError, "period_start is required for #{schema}"
62
- end
63
60
  validate_iso_date!(value(payslip_non_pii, :period_start), "period_start") if key?(payslip_non_pii, :period_start)
64
61
  validate_iso_date!(value(payslip_non_pii, :period_end), "period_end") if key?(payslip_non_pii, :period_end)
65
62
  validate_v2_currency!(payslip_non_pii) if [AUSTRALIAN_PAYSLIP_V2_SCHEMA, NEW_ZEALAND_PAYSLIP_V2_SCHEMA].include?(schema)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Verifiabl
4
4
  module Issuer
5
- VERSION = "0.4.0"
5
+ VERSION = "0.6.0"
6
6
  end
7
7
  end
@@ -21,10 +21,6 @@ require_relative "issuer/version"
21
21
  module Verifiabl
22
22
  module Issuer
23
23
  class << self
24
- def format_pii(fields)
25
- Pii.format(fields)
26
- end
27
-
28
24
  def format_australian_pii(fields)
29
25
  Pii.format_australian(fields)
30
26
  end
@@ -11,6 +11,9 @@ module Verifiabl
11
11
  PAID_LEAVE_TYPES: Array[String]
12
12
  ALLOWANCE_TYPES: Array[String]
13
13
  OTHER_ALLOWANCE_CATEGORIES: Array[String]
14
+ LUMP_SUM_TYPES: Array[String]
15
+ ETP_TYPES: Array[String]
16
+ ETP_COMPONENTS: Array[String]
14
17
  PAY_FREQUENCIES: Array[String]
15
18
  end
16
19
 
@@ -57,7 +60,6 @@ module Verifiabl
57
60
  ?address: new_zealand_address?
58
61
  }
59
62
 
60
- def self.format_pii: (Hash[Symbol | String, String?]) -> String
61
63
  def self.format_australian_pii: (australian_pii_fields) -> String
62
64
  def self.format_new_zealand_pii: (new_zealand_pii_fields) -> String
63
65
  def self.prepare_australian_v2_payslip: (pii: australian_pii_fields, payslip_non_pii: Hash[Symbol | String, untyped], issued_at: String | Time, key: binary, ?verifiabl_reference: String) -> PreparedV2Payslip
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.4.0
4
+ version: 0.6.0
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-06 00:00:00.000000000 Z
11
+ date: 2026-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64