xero-kiwi 0.10.0 → 0.11.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: 122c7e012d619aabdf473185bf0e39e1e04204940d2c6d6b96888d1b6f73b76c
4
- data.tar.gz: 2bbb94621f3e417275b1ea326a2e54e50f03083c01991863e2f91a16af5945ea
3
+ metadata.gz: e52bfcc3939a00a86a7bc26b931aa6e7553b2479fb3b2b36c3215daccad754de
4
+ data.tar.gz: 0c13e42901c11b857c0476dea1c898a46a12404de66231df0b82cb9c899d9a71
5
5
  SHA512:
6
- metadata.gz: 0266fde7e2c101e0533f9e3202ba2871f0a17c170e27ff82dd380448028f608da61f697c3ca08d2a965245125c0987f0a9ddb54ccc01e0a89f47d437fd5aa62d
7
- data.tar.gz: 93e24cd65f1ebf4f7dec4a97fe17d352fb7f6d2ed95f22e6466f403f9997859d16d51569614736c9a1ae77351f94b306dd8304b8f368f465d7c040f2eebb4514
6
+ metadata.gz: 1d9b16a8564e87c0935dfd301ec480fa856c7374f70ca939eef877d4e108f8e54a9ef38a1454451d848de1d6c697addb561f3bf81e3405414dbb0567c9ff77d2
7
+ data.tar.gz: 169f97330de612d1c940bbd0ee0d671c5d5ae7cc4284f5cc42af9b5d59cd37c2e5a68a81113d7e56a66c6e03a5a649bac779783d9b055db143f04684cd6d954c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.11.0] - 2026-10-08
4
+
5
+ ### Added
6
+
7
+ - **`include_archived:`** on `tracking_categories` / `each_tracking_category` / `each_tracking_category_page`, matching the contacts methods. Maps to Xero's `includeArchived`. Without it, Xero leaves out archived categories *and* the archived options under active ones, so a sync that mirrors the list — deleting whatever Xero didn't return — deletes every archived option, and historical invoices tagged with one stop resolving. A consumer's legacy XML client sent the flag; on 0.10.0 passing it raised `ArgumentError: unknown keyword: :include_archived`.
8
+
9
+ ### Documentation
10
+
11
+ - The tracking categories "lookup from option ID" example now passes `include_archived: true`. Without it, `options.fetch` raises `KeyError` on any line item tagged with an archived option.
12
+ - The "Ignoring archived categories" example filtered a list that could never contain one, since Xero leaves archived categories out by default. It now says so, and shows the filter on a list fetched with `include_archived: true`.
13
+
3
14
  ## [0.10.0] - 2026-09-29
4
15
 
5
16
  ### Breaking
@@ -52,8 +52,11 @@ categories.first.options.map(&:name) # => ["Eastside", "Westside"]
52
52
  the `Xero-Tenant-Id` header set, and returns a `XeroKiwi::Page` of
53
53
  `TrackingCategory` objects.
54
54
 
55
- This endpoint isn't paged — an organisation has at most two active
56
- categories. `each_tracking_category` exists so all ten list resources behave
55
+ Archived categories, and archived options under active ones, are left out
56
+ unless you pass `include_archived: true`. See [Querying](../querying.md).
57
+
58
+ This endpoint isn't paged — Xero returns every category in one response, and
59
+ an organisation has at most two active ones. `each_tracking_category` exists so all ten list resources behave
57
60
  consistently, but there's no reason to reach for it over the plain call.
58
61
 
59
62
  ## Fetching a single category
@@ -139,10 +142,12 @@ so it falls back to structural equality — every attribute must match.
139
142
  ### Building a lookup from option ID to names
140
143
 
141
144
  Line items carry only IDs and denormalised names; if you need the canonical
142
- option list, fetch the definitions once per sync and index them.
145
+ option list, fetch the definitions once per sync and index them. Include
146
+ archived ones, or a line item tagged with an archived option raises
147
+ `KeyError`.
143
148
 
144
149
  ```ruby
145
- options = client.tracking_categories(tenant_id).flat_map do |category|
150
+ options = client.tracking_categories(tenant_id, include_archived: true).flat_map do |category|
146
151
  category.options.map { |option| [option.tracking_option_id, [category.name, option.name]] }
147
152
  end.to_h
148
153
 
@@ -156,6 +161,11 @@ end
156
161
 
157
162
  ### Ignoring archived categories
158
163
 
164
+ Xero leaves archived categories out unless you ask for them, so a plain
165
+ `client.tracking_categories(tenant_id)` already returns only active ones.
166
+ Filter when you fetched archived ones too, for a lookup like the one above:
167
+
159
168
  ```ruby
160
- active = client.tracking_categories(tenant_id).select(&:active?)
169
+ categories = client.tracking_categories(tenant_id, include_archived: true)
170
+ active = categories.select(&:active?)
161
171
  ```
data/docs/querying.md CHANGED
@@ -233,14 +233,18 @@ exception, no special flag. An empty page after `modified_since:` is
233
233
  indistinguishable from a filter that matched nothing (intentional — the
234
234
  caller can treat them identically).
235
235
 
236
- ## `include_archived:` — archived contacts
236
+ ## `include_archived:` — archived contacts and tracking categories
237
237
 
238
- Contacts only. Maps to Xero's `includeArchived` query param, which returns
239
- archived contacts **alongside** active ones in the same pass.
238
+ Contacts and tracking categories only. Maps to Xero's `includeArchived`
239
+ query param, which returns archived records **alongside** active ones in
240
+ the same pass.
240
241
 
241
242
  ```ruby
242
243
  client.contacts(tenant, include_archived: true)
243
244
  client.each_contact(tenant, include_archived: true) { |contact| … }
245
+
246
+ client.tracking_categories(tenant, include_archived: true)
247
+ client.each_tracking_category(tenant, include_archived: true) { |category| … }
244
248
  ```
245
249
 
246
250
  This is not the same as filtering on `contact_status`. A
@@ -252,6 +256,11 @@ It matters beyond contacts themselves: Xero keeps serving archived
252
256
  contacts as members of contact groups, so without this you can't tell
253
257
  which group members are archived locally.
254
258
 
259
+ For tracking categories it reaches the options too. Without it, Xero leaves
260
+ out archived categories *and* the archived options under active ones. Line
261
+ items keep pointing at an archived option, so a sync that mirrors the list
262
+ without this flag deletes options its invoices still refer to.
263
+
255
264
  ## Combining everything
256
265
 
257
266
  Mix and match freely:
@@ -617,7 +617,11 @@ module XeroKiwi
617
617
  # Fetches the Tracking Categories for the given tenant. Accepts a tenant-id
618
618
  # string or a XeroKiwi::Connection (we use its tenant_id).
619
619
  # See: https://developer.xero.com/documentation/api/accounting/trackingcategories
620
- def tracking_categories(tenant_id, where: nil, order: nil, page_size: nil, page: nil, modified_since: nil)
620
+ def tracking_categories(tenant_id, where: nil, order: nil, page_size: nil, include_archived: nil, page: nil, modified_since: nil)
621
+ extra_params = {}
622
+
623
+ extra_params["includeArchived"] = include_archived unless include_archived.nil?
624
+
621
625
  list_request(
622
626
  path: "/api.xro/2.0/TrackingCategories",
623
627
  tenant_id: tenant_id,
@@ -626,27 +630,28 @@ module XeroKiwi
626
630
  order: order,
627
631
  page: page,
628
632
  page_size: page_size,
629
- modified_since: modified_since
633
+ modified_since: modified_since,
634
+ extra_params: extra_params
630
635
  )
631
636
  end
632
637
 
633
638
  # Yields every Tracking Category across all pages, driving `#tracking_categories` with
634
639
  # `page:` until an empty or short page signals the end. Returns an
635
640
  # Enumerator when no block is given.
636
- def each_tracking_category(tenant_id, where: nil, order: nil, page_size: nil, start_page: 1, modified_since: nil, &block)
637
- return to_enum(:each_tracking_category, tenant_id, where: where, order: order, page_size: page_size, start_page: start_page, modified_since: modified_since) unless block
641
+ def each_tracking_category(tenant_id, where: nil, order: nil, page_size: nil, include_archived: nil, start_page: 1, modified_since: nil, &block)
642
+ return to_enum(:each_tracking_category, tenant_id, where: where, order: order, page_size: page_size, include_archived: include_archived, start_page: start_page, modified_since: modified_since) unless block
638
643
 
639
- each_tracking_category_page(tenant_id, where: where, order: order, page_size: page_size, start_page: start_page, modified_since: modified_since) { |pg| pg.each(&block) }
644
+ each_tracking_category_page(tenant_id, where: where, order: order, page_size: page_size, include_archived: include_archived, start_page: start_page, modified_since: modified_since) { |pg| pg.each(&block) }
640
645
  end
641
646
 
642
647
  # Same walk as `#each_tracking_category`, but yields each XeroKiwi::Page rather
643
648
  # than its items. Pair `page.page` with `start_page:` to make a sync
644
649
  # resumable: record the page number in the same transaction that stores
645
650
  # the rows, and a crash can't leave a marker ahead of the data.
646
- def each_tracking_category_page(tenant_id, where: nil, order: nil, page_size: nil, start_page: 1, modified_since: nil, &block)
647
- return to_enum(:each_tracking_category_page, tenant_id, where: where, order: order, page_size: page_size, start_page: start_page, modified_since: modified_since) unless block
651
+ def each_tracking_category_page(tenant_id, where: nil, order: nil, page_size: nil, include_archived: nil, start_page: 1, modified_since: nil, &block)
652
+ return to_enum(:each_tracking_category_page, tenant_id, where: where, order: order, page_size: page_size, include_archived: include_archived, start_page: start_page, modified_since: modified_since) unless block
648
653
 
649
- walk_pages(:tracking_categories, tenant_id, where: where, order: order, page_size: page_size, start_page: start_page, modified_since: modified_since, &block)
654
+ walk_pages(:tracking_categories, tenant_id, where: where, order: order, page_size: page_size, include_archived: include_archived, start_page: start_page, modified_since: modified_since, &block)
650
655
  end
651
656
 
652
657
  # Fetches a single Tracking Category by ID for the given tenant. Accepts a
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module XeroKiwi
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
data/llms-full.txt CHANGED
@@ -2158,14 +2158,18 @@ exception, no special flag. An empty page after `modified_since:` is
2158
2158
  indistinguishable from a filter that matched nothing (intentional — the
2159
2159
  caller can treat them identically).
2160
2160
 
2161
- ## `include_archived:` — archived contacts
2161
+ ## `include_archived:` — archived contacts and tracking categories
2162
2162
 
2163
- Contacts only. Maps to Xero's `includeArchived` query param, which returns
2164
- archived contacts **alongside** active ones in the same pass.
2163
+ Contacts and tracking categories only. Maps to Xero's `includeArchived`
2164
+ query param, which returns archived records **alongside** active ones in
2165
+ the same pass.
2165
2166
 
2166
2167
  ```ruby
2167
2168
  client.contacts(tenant, include_archived: true)
2168
2169
  client.each_contact(tenant, include_archived: true) { |contact| … }
2170
+
2171
+ client.tracking_categories(tenant, include_archived: true)
2172
+ client.each_tracking_category(tenant, include_archived: true) { |category| … }
2169
2173
  ```
2170
2174
 
2171
2175
  This is not the same as filtering on `contact_status`. A
@@ -2177,6 +2181,11 @@ It matters beyond contacts themselves: Xero keeps serving archived
2177
2181
  contacts as members of contact groups, so without this you can't tell
2178
2182
  which group members are archived locally.
2179
2183
 
2184
+ For tracking categories it reaches the options too. Without it, Xero leaves
2185
+ out archived categories *and* the archived options under active ones. Line
2186
+ items keep pointing at an archived option, so a sync that mirrors the list
2187
+ without this flag deletes options its invoices still refer to.
2188
+
2180
2189
  ## Combining everything
2181
2190
 
2182
2191
  Mix and match freely:
@@ -3545,8 +3554,11 @@ categories.first.options.map(&:name) # => ["Eastside", "Westside"]
3545
3554
  the `Xero-Tenant-Id` header set, and returns a `XeroKiwi::Page` of
3546
3555
  `TrackingCategory` objects.
3547
3556
 
3548
- This endpoint isn't paged — an organisation has at most two active
3549
- categories. `each_tracking_category` exists so all ten list resources behave
3557
+ Archived categories, and archived options under active ones, are left out
3558
+ unless you pass `include_archived: true`. See [Querying](../querying.md).
3559
+
3560
+ This endpoint isn't paged — Xero returns every category in one response, and
3561
+ an organisation has at most two active ones. `each_tracking_category` exists so all ten list resources behave
3550
3562
  consistently, but there's no reason to reach for it over the plain call.
3551
3563
 
3552
3564
  ## Fetching a single category
@@ -3632,10 +3644,12 @@ so it falls back to structural equality — every attribute must match.
3632
3644
  ### Building a lookup from option ID to names
3633
3645
 
3634
3646
  Line items carry only IDs and denormalised names; if you need the canonical
3635
- option list, fetch the definitions once per sync and index them.
3647
+ option list, fetch the definitions once per sync and index them. Include
3648
+ archived ones, or a line item tagged with an archived option raises
3649
+ `KeyError`.
3636
3650
 
3637
3651
  ```ruby
3638
- options = client.tracking_categories(tenant_id).flat_map do |category|
3652
+ options = client.tracking_categories(tenant_id, include_archived: true).flat_map do |category|
3639
3653
  category.options.map { |option| [option.tracking_option_id, [category.name, option.name]] }
3640
3654
  end.to_h
3641
3655
 
@@ -3649,8 +3663,13 @@ end
3649
3663
 
3650
3664
  ### Ignoring archived categories
3651
3665
 
3666
+ Xero leaves archived categories out unless you ask for them, so a plain
3667
+ `client.tracking_categories(tenant_id)` already returns only active ones.
3668
+ Filter when you fetched archived ones too, for a lookup like the one above:
3669
+
3652
3670
  ```ruby
3653
- active = client.tracking_categories(tenant_id).select(&:active?)
3671
+ categories = client.tracking_categories(tenant_id, include_archived: true)
3672
+ active = categories.select(&:active?)
3654
3673
  ```
3655
3674
 
3656
3675
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xero-kiwi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Douglas Greyling