tax_conformance_kit 0.1.1 → 0.2.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: 6f7af37d7149859cbb18692e8040e9a710027fbef9f0716eacca6ed9c491c301
4
- data.tar.gz: 2dc3af404778b6b2e4c8939aa3e5b49b8fb2040ec0cba3ffd07987dea906e294
3
+ metadata.gz: 394f54f5a6769c980a67b7d62cd9b09490fb72fac00fbf4c04aa0db44f35944b
4
+ data.tar.gz: 25adc315b5b05ec4abbcb2ea30e07f7a369b776f824d4d9ca116dcf7e0167fc9
5
5
  SHA512:
6
- metadata.gz: 9fb939964451a20c444da3f8ecab844203cca7472a11eb331229c8bb1623cc5ad5fa7c18bcec40abe0e1040f3ac5c03354eb4f17e186e6331dc34f08688d9a76
7
- data.tar.gz: 5fbc537124e7698d4276b0b5b13d4ffe0197d437f90160283640a37c1274e5cfb7e0e996e9ef82483fdde2c0ec8fc12516de7d33573d815569f4ecfc021f6f93
6
+ metadata.gz: 609c972a8a9bc0b207b00158d8eb85fc6595eeffe8af94f05cd2a4343d999544c16aa89792e4d5107bbf4136c2a33b09d679c488fc69d491b7cc40c49b1c0aed
7
+ data.tar.gz: 1b6130ddf184af4af8ed53234a555d5f12f275811481f85d998488506f0867616797fa6f3e49c07b18a02638bcdfd0b8f4cd767d121772f06d923ea78ef62808
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Odeva
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -7,7 +7,7 @@ Thin Ruby client for the `tax-conformance-kit` Go runtime.
7
7
  Bundler (RubyGems):
8
8
 
9
9
  ```ruby
10
- gem "tax_conformance_kit", "~> 0.2.0"
10
+ gem "tax_conformance_kit", "~> 0.2.1"
11
11
  ```
12
12
 
13
13
  Path dependency (for local development):
@@ -31,6 +31,8 @@ require "tax_conformance_kit"
31
31
 
32
32
  client = TaxConformanceKit::TaxctlClient.new
33
33
  response = client.evaluate(ruleset: ruleset_hash, booking_input: booking_input_hash)
34
+ resolved = client.evaluate_resolved(booking_input: booking_input_hash)
35
+ grouped = client.evaluate_resolved_assessment(assessment_input: assessment_input_hash)
34
36
  ```
35
37
 
36
38
  ### Advanced: override `command:`
data/bin/taxctl CHANGED
Binary file
@@ -50,13 +50,31 @@
50
50
  }
51
51
  },
52
52
  "generic.per_person_per_night": {
53
- "description": "Flat amount per guest per night. Guests = adults + children unless a predicate narrows the set.",
53
+ "description": "Flat amount per taxable guest per night. Guests = adults + children unless taxable_guest_age_gte narrows the count. max_nights caps the taxable stay units.",
54
54
  "since": "v1",
55
55
  "params_schema": {
56
56
  "type": "object",
57
57
  "required": ["amount"],
58
58
  "properties": {
59
- "amount": { "type": "number", "minimum": 0 }
59
+ "amount": { "type": "number", "minimum": 0 },
60
+ "max_nights": { "type": "integer", "minimum": 0 },
61
+ "taxable_guest_age_gte": { "type": "integer", "minimum": 0 }
62
+ },
63
+ "additionalProperties": false
64
+ }
65
+ },
66
+ "generic.per_person_per_night_discount_after_nights": {
67
+ "description": "Flat amount per taxable guest per night, with a discounted tail from a configurable night onward. Useful for regimes such as the Balearic Islands where nights 9+ are charged at 50%.",
68
+ "since": "v1",
69
+ "params_schema": {
70
+ "type": "object",
71
+ "required": ["amount", "discount_start_night", "discount_multiplier"],
72
+ "properties": {
73
+ "amount": { "type": "number", "minimum": 0 },
74
+ "discount_start_night": { "type": "integer", "minimum": 1 },
75
+ "discount_multiplier": { "type": "number", "minimum": 0 },
76
+ "max_nights": { "type": "integer", "minimum": 0 },
77
+ "taxable_guest_age_gte": { "type": "integer", "minimum": 0 }
60
78
  },
61
79
  "additionalProperties": false
62
80
  }
@@ -311,6 +329,22 @@
311
329
  },
312
330
  "additionalProperties": false
313
331
  }
332
+ },
333
+ "location.property_locality_code_not_in": {
334
+ "description": "True when the property's locality code is not in the configured list. Useful for region-wide rules that exclude one municipality, such as Catalonia tariffs outside Barcelona city.",
335
+ "since": "v1",
336
+ "params_schema": {
337
+ "type": "object",
338
+ "required": ["values"],
339
+ "properties": {
340
+ "values": {
341
+ "type": "array",
342
+ "items": { "type": "string" },
343
+ "minItems": 1
344
+ }
345
+ },
346
+ "additionalProperties": false
347
+ }
314
348
  }
315
349
  }
316
350
  }
@@ -0,0 +1,168 @@
1
+ {
2
+ "id": "es-catalonia-barcelona-city-2026-04-01",
3
+ "domain": "tourist_tax",
4
+ "lifecycle": "reviewed",
5
+ "jurisdiction": {
6
+ "country_code": "ES",
7
+ "country_name": "Spain",
8
+ "region_code": "ES-CT",
9
+ "region_name": "Catalonia"
10
+ },
11
+ "assessment_policy": {
12
+ "period": "calendar_half_year",
13
+ "notes": "Catalonia files the IEET twice per year: 1-20 April for stays accrued from October through March, and 1-20 October for stays accrued from April through September."
14
+ },
15
+ "notes": "Reviewed fixture based on the Catalonia Tax Agency's official IEET quota table effective April 1, 2026. Rates below include Barcelona city's municipal surcharge where applicable. Minors under 17 are exempt and the tax is capped at seven stay units per person.",
16
+ "rules": [
17
+ {
18
+ "id": "es-ct-bcn-city-2026-hotel-5-star",
19
+ "location_scope": {
20
+ "country_code": "ES",
21
+ "region_code": "ES-CT",
22
+ "locality_kind": "municipality",
23
+ "locality_code": "08019",
24
+ "locality_name": "Barcelona"
25
+ },
26
+ "valid_from": "2026-04-01",
27
+ "valid_to": null,
28
+ "applies_to": {
29
+ "accommodation_types": ["hotel_5_star", "luxury_hotel", "cruise"]
30
+ },
31
+ "calculation": {
32
+ "kind": "generic.per_person_per_night",
33
+ "params": {
34
+ "amount": 12.0,
35
+ "max_nights": 7,
36
+ "taxable_guest_age_gte": 17
37
+ },
38
+ "currency": "EUR"
39
+ },
40
+ "source": {
41
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
42
+ "reviewed_at": null
43
+ },
44
+ "confidence": "reviewed",
45
+ "notes": "Barcelona city rate from April 1, 2026: EUR 12.00 for 5-star and luxury hotels, campings de lujo, and cruises."
46
+ },
47
+ {
48
+ "id": "es-ct-bcn-city-2026-hotel-4-star",
49
+ "location_scope": {
50
+ "country_code": "ES",
51
+ "region_code": "ES-CT",
52
+ "locality_kind": "municipality",
53
+ "locality_code": "08019",
54
+ "locality_name": "Barcelona"
55
+ },
56
+ "valid_from": "2026-04-01",
57
+ "valid_to": null,
58
+ "applies_to": {
59
+ "accommodation_types": ["hotel_4_star", "superior_hotel"]
60
+ },
61
+ "calculation": {
62
+ "kind": "generic.per_person_per_night",
63
+ "params": {
64
+ "amount": 8.0,
65
+ "max_nights": 7,
66
+ "taxable_guest_age_gte": 17
67
+ },
68
+ "currency": "EUR"
69
+ },
70
+ "source": {
71
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
72
+ "reviewed_at": null
73
+ },
74
+ "confidence": "reviewed",
75
+ "notes": "Barcelona city rate from April 1, 2026: EUR 8.00 for 4-star and 4-star superior hotels."
76
+ },
77
+ {
78
+ "id": "es-ct-bcn-city-2026-tourist-home",
79
+ "location_scope": {
80
+ "country_code": "ES",
81
+ "region_code": "ES-CT",
82
+ "locality_kind": "municipality",
83
+ "locality_code": "08019",
84
+ "locality_name": "Barcelona"
85
+ },
86
+ "valid_from": "2026-04-01",
87
+ "valid_to": null,
88
+ "applies_to": {
89
+ "accommodation_types": ["tourist_apartment", "tourist_home", "private_room"]
90
+ },
91
+ "calculation": {
92
+ "kind": "generic.per_person_per_night",
93
+ "params": {
94
+ "amount": 9.5,
95
+ "max_nights": 7,
96
+ "taxable_guest_age_gte": 17
97
+ },
98
+ "currency": "EUR"
99
+ },
100
+ "source": {
101
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
102
+ "reviewed_at": null
103
+ },
104
+ "confidence": "reviewed",
105
+ "notes": "Barcelona city rate from April 1, 2026: EUR 9.50 for tourist-use homes, tourist apartments, and private-room establishments."
106
+ },
107
+ {
108
+ "id": "es-ct-bcn-city-2026-hostel",
109
+ "location_scope": {
110
+ "country_code": "ES",
111
+ "region_code": "ES-CT",
112
+ "locality_kind": "municipality",
113
+ "locality_code": "08019",
114
+ "locality_name": "Barcelona"
115
+ },
116
+ "valid_from": "2026-04-01",
117
+ "valid_to": null,
118
+ "applies_to": {
119
+ "accommodation_types": ["hostel", "guesthouse", "boarding_house", "rural_lodging"]
120
+ },
121
+ "calculation": {
122
+ "kind": "generic.per_person_per_night",
123
+ "params": {
124
+ "amount": 6.0,
125
+ "max_nights": 7,
126
+ "taxable_guest_age_gte": 17
127
+ },
128
+ "currency": "EUR"
129
+ },
130
+ "source": {
131
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
132
+ "reviewed_at": null
133
+ },
134
+ "confidence": "reviewed",
135
+ "notes": "Barcelona city rate from April 1, 2026: EUR 6.00 for hostels, pensions, guesthouses, rural tourism, and similar categories."
136
+ },
137
+ {
138
+ "id": "es-ct-bcn-city-2026-camping",
139
+ "location_scope": {
140
+ "country_code": "ES",
141
+ "region_code": "ES-CT",
142
+ "locality_kind": "municipality",
143
+ "locality_code": "08019",
144
+ "locality_name": "Barcelona"
145
+ },
146
+ "valid_from": "2026-04-01",
147
+ "valid_to": null,
148
+ "applies_to": {
149
+ "accommodation_types": ["camping", "camping_luxury"]
150
+ },
151
+ "calculation": {
152
+ "kind": "generic.per_person_per_night",
153
+ "params": {
154
+ "amount": 7.0,
155
+ "max_nights": 7,
156
+ "taxable_guest_age_gte": 17
157
+ },
158
+ "currency": "EUR"
159
+ },
160
+ "source": {
161
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
162
+ "reviewed_at": null
163
+ },
164
+ "confidence": "reviewed",
165
+ "notes": "Barcelona city rate from April 1, 2026: EUR 7.00 for campsites and campings de lujo."
166
+ }
167
+ ]
168
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "id": "es-catalonia-barcelona-city-dutch-operator-hotel-5-star",
3
+ "description": "A Dutch operator with a Barcelona 5-star hotel is charged the Barcelona city IEET rate, capped at 7 nights and excluding the 15-year-old guest.",
4
+ "rule_set_path": "../2026-04-01.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-06-15",
7
+ "nights": 10,
8
+ "adults": 2,
9
+ "children": 1,
10
+ "guests": [
11
+ { "age": 34, "role": "guest" },
12
+ { "age": 38, "role": "guest" },
13
+ { "age": 15, "role": "guest" }
14
+ ],
15
+ "property_location": {
16
+ "country_code": "ES",
17
+ "region_code": "ES-CT",
18
+ "locality_kind": "municipality",
19
+ "locality_code": "08019",
20
+ "locality_name": "Barcelona"
21
+ },
22
+ "operator": {
23
+ "legal_country_code": "NL",
24
+ "legal_name": "Canal Stays BV"
25
+ },
26
+ "accommodation_type": "hotel_5_star",
27
+ "subtotal": 4000
28
+ },
29
+ "expected": {
30
+ "total_tax": 168.0,
31
+ "matched_rule_ids": ["es-ct-bcn-city-2026-hotel-5-star"]
32
+ }
33
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "es-catalonia-barcelona-city-tourist-home-age-17-taxed",
3
+ "description": "Barcelona city tourist-home stays tax 17-year-olds because only minors under 17 are exempt.",
4
+ "rule_set_path": "../2026-04-01.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-09-10",
7
+ "nights": 3,
8
+ "adults": 1,
9
+ "children": 1,
10
+ "guests": [
11
+ { "age": 41, "role": "guest" },
12
+ { "age": 17, "role": "guest" }
13
+ ],
14
+ "property_location": {
15
+ "country_code": "ES",
16
+ "region_code": "ES-CT",
17
+ "locality_kind": "municipality",
18
+ "locality_code": "08019",
19
+ "locality_name": "Barcelona"
20
+ },
21
+ "accommodation_type": "tourist_home",
22
+ "subtotal": 900
23
+ },
24
+ "expected": {
25
+ "total_tax": 57.0,
26
+ "matched_rule_ids": ["es-ct-bcn-city-2026-tourist-home"]
27
+ }
28
+ }
@@ -0,0 +1,183 @@
1
+ {
2
+ "id": "es-catalonia-rest-of-catalonia-2026-04-01",
3
+ "domain": "tourist_tax",
4
+ "lifecycle": "reviewed",
5
+ "jurisdiction": {
6
+ "country_code": "ES",
7
+ "country_name": "Spain",
8
+ "region_code": "ES-CT",
9
+ "region_name": "Catalonia"
10
+ },
11
+ "assessment_policy": {
12
+ "period": "calendar_half_year",
13
+ "notes": "Catalonia files the IEET twice per year: 1-20 April for stays accrued from October through March, and 1-20 October for stays accrued from April through September."
14
+ },
15
+ "notes": "Reviewed fixture based on the Catalonia Tax Agency's official IEET quota table effective April 1, 2026 for the rest of Catalonia. Barcelona city is excluded explicitly through locality-code predicates. Minors under 17 are exempt and the tax is capped at seven stay units per person.",
16
+ "rules": [
17
+ {
18
+ "id": "es-ct-rest-2026-hotel-5-star",
19
+ "location_scope": {
20
+ "country_code": "ES",
21
+ "region_code": "ES-CT"
22
+ },
23
+ "valid_from": "2026-04-01",
24
+ "valid_to": null,
25
+ "applies_to": {
26
+ "accommodation_types": ["hotel_5_star", "luxury_hotel", "cruise"]
27
+ },
28
+ "predicates": [
29
+ {
30
+ "kind": "location.property_locality_code_not_in",
31
+ "params": { "values": ["08019"] }
32
+ }
33
+ ],
34
+ "calculation": {
35
+ "kind": "generic.per_person_per_night",
36
+ "params": {
37
+ "amount": 4.5,
38
+ "max_nights": 7,
39
+ "taxable_guest_age_gte": 17
40
+ },
41
+ "currency": "EUR"
42
+ },
43
+ "source": {
44
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
45
+ "reviewed_at": null
46
+ },
47
+ "confidence": "reviewed",
48
+ "notes": "Rest of Catalonia rate from April 1, 2026: EUR 4.50 for 5-star and luxury hotels, campings de lujo, and cruises."
49
+ },
50
+ {
51
+ "id": "es-ct-rest-2026-hotel-4-star",
52
+ "location_scope": {
53
+ "country_code": "ES",
54
+ "region_code": "ES-CT"
55
+ },
56
+ "valid_from": "2026-04-01",
57
+ "valid_to": null,
58
+ "applies_to": {
59
+ "accommodation_types": ["hotel_4_star", "superior_hotel"]
60
+ },
61
+ "predicates": [
62
+ {
63
+ "kind": "location.property_locality_code_not_in",
64
+ "params": { "values": ["08019"] }
65
+ }
66
+ ],
67
+ "calculation": {
68
+ "kind": "generic.per_person_per_night",
69
+ "params": {
70
+ "amount": 1.8,
71
+ "max_nights": 7,
72
+ "taxable_guest_age_gte": 17
73
+ },
74
+ "currency": "EUR"
75
+ },
76
+ "source": {
77
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
78
+ "reviewed_at": null
79
+ },
80
+ "confidence": "reviewed",
81
+ "notes": "Rest of Catalonia rate from April 1, 2026: EUR 1.80 for 4-star and 4-star superior hotels."
82
+ },
83
+ {
84
+ "id": "es-ct-rest-2026-tourist-home",
85
+ "location_scope": {
86
+ "country_code": "ES",
87
+ "region_code": "ES-CT"
88
+ },
89
+ "valid_from": "2026-04-01",
90
+ "valid_to": null,
91
+ "applies_to": {
92
+ "accommodation_types": ["tourist_apartment", "tourist_home", "private_room"]
93
+ },
94
+ "predicates": [
95
+ {
96
+ "kind": "location.property_locality_code_not_in",
97
+ "params": { "values": ["08019"] }
98
+ }
99
+ ],
100
+ "calculation": {
101
+ "kind": "generic.per_person_per_night",
102
+ "params": {
103
+ "amount": 1.75,
104
+ "max_nights": 7,
105
+ "taxable_guest_age_gte": 17
106
+ },
107
+ "currency": "EUR"
108
+ },
109
+ "source": {
110
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
111
+ "reviewed_at": null
112
+ },
113
+ "confidence": "reviewed",
114
+ "notes": "Rest of Catalonia rate from April 1, 2026: EUR 1.75 for tourist-use homes, tourist apartments, and private-room establishments."
115
+ },
116
+ {
117
+ "id": "es-ct-rest-2026-hostel",
118
+ "location_scope": {
119
+ "country_code": "ES",
120
+ "region_code": "ES-CT"
121
+ },
122
+ "valid_from": "2026-04-01",
123
+ "valid_to": null,
124
+ "applies_to": {
125
+ "accommodation_types": ["hostel", "guesthouse", "boarding_house", "rural_lodging"]
126
+ },
127
+ "predicates": [
128
+ {
129
+ "kind": "location.property_locality_code_not_in",
130
+ "params": { "values": ["08019"] }
131
+ }
132
+ ],
133
+ "calculation": {
134
+ "kind": "generic.per_person_per_night",
135
+ "params": {
136
+ "amount": 0.8,
137
+ "max_nights": 7,
138
+ "taxable_guest_age_gte": 17
139
+ },
140
+ "currency": "EUR"
141
+ },
142
+ "source": {
143
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
144
+ "reviewed_at": null
145
+ },
146
+ "confidence": "reviewed",
147
+ "notes": "Rest of Catalonia rate from April 1, 2026: EUR 0.80 for hostels, pensions, guesthouses, rural tourism, and similar categories."
148
+ },
149
+ {
150
+ "id": "es-ct-rest-2026-camping",
151
+ "location_scope": {
152
+ "country_code": "ES",
153
+ "region_code": "ES-CT"
154
+ },
155
+ "valid_from": "2026-04-01",
156
+ "valid_to": null,
157
+ "applies_to": {
158
+ "accommodation_types": ["camping", "camping_luxury"]
159
+ },
160
+ "predicates": [
161
+ {
162
+ "kind": "location.property_locality_code_not_in",
163
+ "params": { "values": ["08019"] }
164
+ }
165
+ ],
166
+ "calculation": {
167
+ "kind": "generic.per_person_per_night",
168
+ "params": {
169
+ "amount": 0.9,
170
+ "max_nights": 7,
171
+ "taxable_guest_age_gte": 17
172
+ },
173
+ "currency": "EUR"
174
+ },
175
+ "source": {
176
+ "source_url": "https://atc.gencat.cat/es/tributs/ieet/quota-tributaria",
177
+ "reviewed_at": null
178
+ },
179
+ "confidence": "reviewed",
180
+ "notes": "Rest of Catalonia rate from April 1, 2026: EUR 0.90 for campsites and campings de lujo."
181
+ }
182
+ ]
183
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "es-catalonia-rest-barcelona-city-excluded",
3
+ "description": "The rest-of-Catalonia ruleset excludes Barcelona city's locality code.",
4
+ "rule_set_path": "../2026-04-01.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-07-20",
7
+ "nights": 2,
8
+ "adults": 2,
9
+ "children": 0,
10
+ "property_location": {
11
+ "country_code": "ES",
12
+ "region_code": "ES-CT",
13
+ "locality_kind": "municipality",
14
+ "locality_code": "08019",
15
+ "locality_name": "Barcelona"
16
+ },
17
+ "accommodation_type": "hotel_4_star",
18
+ "subtotal": 500
19
+ },
20
+ "expected": {
21
+ "total_tax": 0,
22
+ "matched_rule_ids": []
23
+ }
24
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "es-catalonia-rest-girona-hotel-4-star",
3
+ "description": "A Girona 4-star hotel outside Barcelona city uses the rest-of-Catalonia IEET tariff.",
4
+ "rule_set_path": "../2026-04-01.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-07-20",
7
+ "nights": 2,
8
+ "adults": 2,
9
+ "children": 0,
10
+ "guests": [
11
+ { "age": 42, "role": "guest" },
12
+ { "age": 36, "role": "guest" }
13
+ ],
14
+ "property_location": {
15
+ "country_code": "ES",
16
+ "region_code": "ES-CT",
17
+ "locality_kind": "municipality",
18
+ "locality_code": "17079",
19
+ "locality_name": "Girona"
20
+ },
21
+ "accommodation_type": "hotel_4_star",
22
+ "subtotal": 500
23
+ },
24
+ "expected": {
25
+ "total_tax": 7.2,
26
+ "matched_rule_ids": ["es-ct-rest-2026-hotel-4-star"]
27
+ }
28
+ }
@@ -0,0 +1,166 @@
1
+ {
2
+ "id": "es-balearic-islands-2025-05-17",
3
+ "domain": "tourist_tax",
4
+ "lifecycle": "reviewed",
5
+ "jurisdiction": {
6
+ "country_code": "ES",
7
+ "country_name": "Spain",
8
+ "region_code": "ES-IB",
9
+ "region_name": "Illes Balears"
10
+ },
11
+ "assessment_policy": {
12
+ "period": "calendar_quarter",
13
+ "notes": "ATIB files the Balearic tourist-stay tax by quarter using model 700."
14
+ },
15
+ "notes": "Reviewed fixture based on the consolidated Balearic tourist-stay tax law and ATIB guidance. Guests under 16 are exempt. A 75% seasonal reduction applies from 1 November through 30 April, and from the ninth day onward the quota is reduced by 50%.",
16
+ "rules": [
17
+ {
18
+ "id": "es-ib-2025-hotel-4-star-high-season",
19
+ "location_scope": {
20
+ "country_code": "ES",
21
+ "region_code": "ES-IB"
22
+ },
23
+ "valid_from": "2025-05-17",
24
+ "valid_to": null,
25
+ "applies_to": {
26
+ "accommodation_types": ["hotel_4_star", "superior_hotel"]
27
+ },
28
+ "predicates": [
29
+ {
30
+ "kind": "stay.seasonal_window",
31
+ "params": {
32
+ "start_mmdd": "05-01",
33
+ "end_mmdd": "10-31"
34
+ }
35
+ }
36
+ ],
37
+ "calculation": {
38
+ "kind": "generic.per_person_per_night_discount_after_nights",
39
+ "params": {
40
+ "amount": 3.0,
41
+ "discount_start_night": 9,
42
+ "discount_multiplier": 0.5,
43
+ "taxable_guest_age_gte": 16
44
+ },
45
+ "currency": "EUR"
46
+ },
47
+ "source": {
48
+ "source_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2016-4175",
49
+ "reviewed_at": null
50
+ },
51
+ "confidence": "reviewed",
52
+ "notes": "Balearic Islands high-season rate: EUR 3.00 for 4-star hotels and 3-star superior hotels. The law reduces the quota by 50% from the ninth day onward."
53
+ },
54
+ {
55
+ "id": "es-ib-2025-hotel-4-star-low-season",
56
+ "location_scope": {
57
+ "country_code": "ES",
58
+ "region_code": "ES-IB"
59
+ },
60
+ "valid_from": "2025-05-17",
61
+ "valid_to": null,
62
+ "applies_to": {
63
+ "accommodation_types": ["hotel_4_star", "superior_hotel"]
64
+ },
65
+ "predicates": [
66
+ {
67
+ "kind": "stay.seasonal_window",
68
+ "params": {
69
+ "start_mmdd": "11-01",
70
+ "end_mmdd": "04-30"
71
+ }
72
+ }
73
+ ],
74
+ "calculation": {
75
+ "kind": "generic.per_person_per_night_discount_after_nights",
76
+ "params": {
77
+ "amount": 0.75,
78
+ "discount_start_night": 9,
79
+ "discount_multiplier": 0.5,
80
+ "taxable_guest_age_gte": 16
81
+ },
82
+ "currency": "EUR"
83
+ },
84
+ "source": {
85
+ "source_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2016-4175",
86
+ "reviewed_at": null
87
+ },
88
+ "confidence": "reviewed",
89
+ "notes": "Low season applies a 75% reduction to the EUR 3.00 high-season rate, yielding EUR 0.75 before the ninth-day discount."
90
+ },
91
+ {
92
+ "id": "es-ib-2025-tourist-home-high-season",
93
+ "location_scope": {
94
+ "country_code": "ES",
95
+ "region_code": "ES-IB"
96
+ },
97
+ "valid_from": "2025-05-17",
98
+ "valid_to": null,
99
+ "applies_to": {
100
+ "accommodation_types": ["tourist_home", "tourist_apartment", "vacation_rental"]
101
+ },
102
+ "predicates": [
103
+ {
104
+ "kind": "stay.seasonal_window",
105
+ "params": {
106
+ "start_mmdd": "05-01",
107
+ "end_mmdd": "10-31"
108
+ }
109
+ }
110
+ ],
111
+ "calculation": {
112
+ "kind": "generic.per_person_per_night_discount_after_nights",
113
+ "params": {
114
+ "amount": 2.0,
115
+ "discount_start_night": 9,
116
+ "discount_multiplier": 0.5,
117
+ "taxable_guest_age_gte": 16
118
+ },
119
+ "currency": "EUR"
120
+ },
121
+ "source": {
122
+ "source_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2016-4175",
123
+ "reviewed_at": null
124
+ },
125
+ "confidence": "reviewed",
126
+ "notes": "Balearic Islands high-season rate: EUR 2.00 for tourist homes, holiday rentals, and tourist apartments."
127
+ },
128
+ {
129
+ "id": "es-ib-2025-tourist-home-low-season",
130
+ "location_scope": {
131
+ "country_code": "ES",
132
+ "region_code": "ES-IB"
133
+ },
134
+ "valid_from": "2025-05-17",
135
+ "valid_to": null,
136
+ "applies_to": {
137
+ "accommodation_types": ["tourist_home", "tourist_apartment", "vacation_rental"]
138
+ },
139
+ "predicates": [
140
+ {
141
+ "kind": "stay.seasonal_window",
142
+ "params": {
143
+ "start_mmdd": "11-01",
144
+ "end_mmdd": "04-30"
145
+ }
146
+ }
147
+ ],
148
+ "calculation": {
149
+ "kind": "generic.per_person_per_night_discount_after_nights",
150
+ "params": {
151
+ "amount": 0.5,
152
+ "discount_start_night": 9,
153
+ "discount_multiplier": 0.5,
154
+ "taxable_guest_age_gte": 16
155
+ },
156
+ "currency": "EUR"
157
+ },
158
+ "source": {
159
+ "source_url": "https://www.boe.es/buscar/act.php?id=BOE-A-2016-4175",
160
+ "reviewed_at": null
161
+ },
162
+ "confidence": "reviewed",
163
+ "notes": "Low season applies a 75% reduction to the EUR 2.00 high-season rate, yielding EUR 0.50 before the ninth-day discount."
164
+ }
165
+ ]
166
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ "id": "es-balearic-palma-hotel-4-star-high-season-long-stay",
3
+ "description": "Balearic high-season stays charge the first eight nights in full and reduce nights 9+ by 50%; guests under 16 remain exempt.",
4
+ "rule_set_path": "../2025-05-17.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-07-10",
7
+ "nights": 10,
8
+ "adults": 2,
9
+ "children": 1,
10
+ "guests": [
11
+ { "age": 40, "role": "guest" },
12
+ { "age": 34, "role": "guest" },
13
+ { "age": 14, "role": "guest" }
14
+ ],
15
+ "property_location": {
16
+ "country_code": "ES",
17
+ "region_code": "ES-IB",
18
+ "locality_kind": "municipality",
19
+ "locality_name": "Palma"
20
+ },
21
+ "operator": {
22
+ "legal_country_code": "NL",
23
+ "legal_name": "Canal Stays BV"
24
+ },
25
+ "accommodation_type": "hotel_4_star",
26
+ "subtotal": 2200
27
+ },
28
+ "expected": {
29
+ "total_tax": 54.0,
30
+ "matched_rule_ids": ["es-ib-2025-hotel-4-star-high-season"]
31
+ }
32
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "es-balearic-tourist-home-low-season",
3
+ "description": "Balearic low-season tourist-home stays apply the 75% seasonal reduction to the base per-person nightly rate.",
4
+ "rule_set_path": "../2025-05-17.json",
5
+ "booking_input": {
6
+ "stay_date": "2026-11-15",
7
+ "nights": 3,
8
+ "adults": 2,
9
+ "children": 0,
10
+ "guests": [
11
+ { "age": 31, "role": "guest" },
12
+ { "age": 29, "role": "guest" }
13
+ ],
14
+ "property_location": {
15
+ "country_code": "ES",
16
+ "region_code": "ES-IB",
17
+ "locality_kind": "municipality",
18
+ "locality_name": "Sant Antoni de Portmany"
19
+ },
20
+ "accommodation_type": "tourist_home",
21
+ "subtotal": 700
22
+ },
23
+ "expected": {
24
+ "total_tax": 3.0,
25
+ "matched_rule_ids": ["es-ib-2025-tourist-home-low-season"]
26
+ }
27
+ }
@@ -10,26 +10,32 @@
10
10
  },
11
11
  "notes": "Auto-generated from CVDR publication analysis. Source-backed draft only; review required before conformance use.",
12
12
  "assessment_policy": {
13
+ "period": "calendar_year",
13
14
  "minimum_assessment_amount": {
14
15
  "amount": 5,
15
16
  "currency": "EUR"
16
17
  },
17
- "notes": "Assessment period inferred from the belastingtijdvak article. Minimum assessment amount inferred from the aanslaggrens article.",
18
- "period": "calendar_year"
18
+ "notes": "Assessment period inferred from the belastingtijdvak article. Minimum assessment amount inferred from the aanslaggrens article."
19
19
  },
20
20
  "rules": [
21
21
  {
22
+ "id": "2026-03-19-rate-1",
23
+ "municipality_code": "0758",
24
+ "municipality_name": "Breda",
25
+ "region_code": "",
26
+ "valid_from": "2026-03-19",
27
+ "valid_to": null,
22
28
  "applies_to": {
23
29
  "accommodation_types": []
24
30
  },
25
31
  "calculation": {
26
- "currency": "EUR",
27
32
  "kind": "generic.per_person_per_night",
28
33
  "params": {
29
34
  "amount": 3.95
30
- }
35
+ },
36
+ "currency": "EUR"
31
37
  },
32
- "confidence": "scraped",
38
+ "predicates": [],
33
39
  "exemptions": [
34
40
  {
35
41
  "kind": "guest.resident_of_same_municipality",
@@ -50,36 +56,36 @@
50
56
  }
51
57
  }
52
58
  ],
53
- "id": "2026-03-19-rate-1",
54
- "municipality_code": "0758",
55
- "municipality_name": "Breda",
56
- "notes": "Likely default tariff from the opening paragraph; reviewer must exclude specific reduced categories mentioned later in the same article. Evidence articles: 6",
57
- "predicates": [],
58
- "region_code": "",
59
59
  "source": {
60
+ "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2",
60
61
  "cvdr_id": "CVDR749624",
62
+ "scraped_at": "2026-04-29T12:04:56Z",
61
63
  "reviewed_at": null,
62
- "reviewer": "",
63
- "scraped_at": "2026-04-17T12:09:56Z",
64
- "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2"
64
+ "reviewer": ""
65
65
  },
66
- "valid_from": "2026-03-19",
67
- "valid_to": null
66
+ "confidence": "scraped",
67
+ "notes": "Likely default tariff from the opening paragraph; reviewer must exclude specific reduced categories mentioned later in the same article. Evidence articles: 6 Generated from CVDR analysis."
68
68
  },
69
69
  {
70
+ "id": "2026-03-19-rate-2",
71
+ "municipality_code": "0758",
72
+ "municipality_name": "Breda",
73
+ "region_code": "",
74
+ "valid_from": "2026-03-19",
75
+ "valid_to": null,
70
76
  "applies_to": {
71
77
  "accommodation_types": [
72
78
  "camping"
73
79
  ]
74
80
  },
75
81
  "calculation": {
76
- "currency": "EUR",
77
82
  "kind": "generic.per_person_per_night",
78
83
  "params": {
79
84
  "amount": 1.5
80
- }
85
+ },
86
+ "currency": "EUR"
81
87
  },
82
- "confidence": "scraped",
88
+ "predicates": [],
83
89
  "exemptions": [
84
90
  {
85
91
  "kind": "guest.resident_of_same_municipality",
@@ -100,36 +106,36 @@
100
106
  }
101
107
  }
102
108
  ],
103
- "id": "2026-03-19-rate-2",
104
- "municipality_code": "0758",
105
- "municipality_name": "Breda",
106
- "notes": "Generated from tariff article. Reviewer must confirm category boundaries and exclusions. Evidence articles: 6",
107
- "predicates": [],
108
- "region_code": "",
109
109
  "source": {
110
+ "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2",
110
111
  "cvdr_id": "CVDR749624",
112
+ "scraped_at": "2026-04-29T12:04:56Z",
111
113
  "reviewed_at": null,
112
- "reviewer": "",
113
- "scraped_at": "2026-04-17T12:09:56Z",
114
- "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2"
114
+ "reviewer": ""
115
115
  },
116
- "valid_from": "2026-03-19",
117
- "valid_to": null
116
+ "confidence": "scraped",
117
+ "notes": "Generated from tariff article. Reviewer must confirm category boundaries and exclusions. Evidence articles: 6 Generated from CVDR analysis."
118
118
  },
119
119
  {
120
+ "id": "2026-03-19-rate-3",
121
+ "municipality_code": "0758",
122
+ "municipality_name": "Breda",
123
+ "region_code": "",
124
+ "valid_from": "2026-03-19",
125
+ "valid_to": null,
120
126
  "applies_to": {
121
127
  "accommodation_types": [
122
128
  "camping"
123
129
  ]
124
130
  },
125
131
  "calculation": {
126
- "currency": "EUR",
127
132
  "kind": "generic.per_person_per_night",
128
133
  "params": {
129
134
  "amount": 0.5
130
- }
135
+ },
136
+ "currency": "EUR"
131
137
  },
132
- "confidence": "scraped",
138
+ "predicates": [],
133
139
  "exemptions": [
134
140
  {
135
141
  "kind": "guest.resident_of_same_municipality",
@@ -150,21 +156,15 @@
150
156
  }
151
157
  }
152
158
  ],
153
- "id": "2026-03-19-rate-3",
154
- "municipality_code": "0758",
155
- "municipality_name": "Breda",
156
- "notes": "Generated from tariff article. Reviewer must confirm category boundaries and exclusions. Evidence articles: 6",
157
- "predicates": [],
158
- "region_code": "",
159
159
  "source": {
160
+ "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2",
160
161
  "cvdr_id": "CVDR749624",
162
+ "scraped_at": "2026-04-29T12:04:56Z",
161
163
  "reviewed_at": null,
162
- "reviewer": "",
163
- "scraped_at": "2026-04-17T12:09:56Z",
164
- "source_url": "https://lokaleregelgeving.overheid.nl/CVDR749624/2"
164
+ "reviewer": ""
165
165
  },
166
- "valid_from": "2026-03-19",
167
- "valid_to": null
166
+ "confidence": "scraped",
167
+ "notes": "Generated from tariff article. Reviewer must confirm category boundaries and exclusions. Evidence articles: 6 Generated from CVDR analysis."
168
168
  }
169
169
  ]
170
170
  }
@@ -27,6 +27,15 @@ module TaxConformanceKit
27
27
  })
28
28
  end
29
29
 
30
+ def evaluate_resolved(booking_input:, fixture_root: nil, domain: nil, kind_registry: nil)
31
+ run_json("runtime-resolve-evaluate", {
32
+ fixture_root: fixture_root,
33
+ domain: domain,
34
+ booking_input: booking_input,
35
+ kind_registry: kind_registry
36
+ })
37
+ end
38
+
30
39
  def evaluate_assessment(ruleset:, assessment_input:, kind_registry: nil)
31
40
  run_json("runtime-evaluate-assessment", {
32
41
  ruleset: ruleset,
@@ -35,6 +44,15 @@ module TaxConformanceKit
35
44
  })
36
45
  end
37
46
 
47
+ def evaluate_resolved_assessment(assessment_input:, fixture_root: nil, domain: nil, kind_registry: nil)
48
+ run_json("runtime-resolve-evaluate-assessment", {
49
+ fixture_root: fixture_root,
50
+ domain: domain,
51
+ assessment_input: assessment_input,
52
+ kind_registry: kind_registry
53
+ })
54
+ end
55
+
38
56
  private
39
57
 
40
58
  def normalize_command(command)
@@ -1,3 +1,3 @@
1
1
  module TaxConformanceKit
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,24 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tax_conformance_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
- - Urban Heroes
7
+ - ramones
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Ruby adapter for runtime-validate, runtime-evaluate, and runtime-evaluate-assessment.
13
13
  email:
14
- - dev@urbanheroes.dev
14
+ - ramonvansprundel@gmail.com
15
15
  executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - LICENSE
19
20
  - README.md
20
21
  - bin/taxctl
21
22
  - data/kind-registry.v1.json
23
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/barcelona_city/2026-04-01.json
24
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/barcelona_city/conformance/dutch_operator_barcelona_hotel_5_star.json
25
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/barcelona_city/conformance/tourist_home_age_17_taxed.json
26
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/rest_of_catalonia/2026-04-01.json
27
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/rest_of_catalonia/conformance/barcelona_city_excluded.json
28
+ - data/regulation/es/impuesto_estancias_turisticas/catalonia/rest_of_catalonia/conformance/girona_hotel_4_star.json
29
+ - data/regulation/es/impuesto_turismo_sostenible/balearic_islands/2025-05-17.json
30
+ - data/regulation/es/impuesto_turismo_sostenible/balearic_islands/conformance/palma_hotel_4_star_high_season_long_stay.json
31
+ - data/regulation/es/impuesto_turismo_sostenible/balearic_islands/conformance/tourist_home_low_season.json
22
32
  - data/regulation/nl/gemeentelijke_verordening/aa_en_hunze/2024-11-29.json
23
33
  - data/regulation/nl/gemeentelijke_verordening/aa_en_hunze/2025-11-28.json
24
34
  - data/regulation/nl/gemeentelijke_verordening/aalten/2024-12-23.json
@@ -457,7 +467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
457
467
  - !ruby/object:Gem::Version
458
468
  version: '0'
459
469
  requirements: []
460
- rubygems_version: 3.6.9
470
+ rubygems_version: 4.0.6
461
471
  specification_version: 4
462
472
  summary: Thin Ruby client for the tax-conformance-kit Go runtime
463
473
  test_files: []