You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tweak - Match TaxJar cache entries across cart and order paths (WOOTAX-258) (#2983)
* WOOTAX-258: match TaxJar cache entries across cart and order paths
The transient cache key was an md5 of the raw request body, so two requests
that would receive the same answer from TaxJar routinely missed each other.
Two causes, fixed separately:
* The line item `id` was built from WooCommerce's cart item key on the cart
path and from the numeric order item ID on the order path, so the same
basket produced two different bodies. Both paths now derive `id` from the
tax-relevant inputs alone (product, tax code, quantity, unit price,
discount, tax location), with an occurrence counter to keep genuinely
identical lines distinct. The product ID stays the first `-` segment,
which get_itemized_tax_rates() and the rate-override hooks rely on.
* The key was byte-sensitive, so a differently-cased city, a stray double
space or "5" vs "5.00" split the cache. The key now comes from a canonical
projection of the body: whitespace and case folded, amounts given one
representation, key order fixed, line items sorted. Numeric normalization
is applied by field name so a leading-zero ZIP is never reinterpreted.
The body sent to TaxJar is unchanged apart from `id`, which TaxJar treats as
an opaque echo field.
* WOOTAX-258: address PR review — @SInCE stamps and cache-hit coverage
Review follow-ups on #2983:
- The five new private cache-key helpers were stamped `@since 3.4.0`; the
release in progress is 3.6.10.
- `calculate_backend_totals()` passes the order-item-ID-keyed map from
`get_backend_line_items()` straight into `calculate_tax()` without going
through `group_items_by_location()`, so `array_values()` is the only thing
keeping `line_items` a JSON array rather than an object on every admin-side
request. The one existing `calculate_tax()` test returns at the cross-state
guard and never reaches it. Adds a test that captures the encoded body and
asserts a zero-indexed list, checking the raw JSON as well as the decoded
array since `json_decode()` hides the array/object distinction.
- `smartcalcs_cache_request()` had no coverage at all: the existing tests
compare `get_cache_signature()` outputs in isolation, verifying the
ingredients but never the result. Adds a test that counts
`smartcalcs_request()` invocations across two equivalent-but-byte-different
bodies and asserts one HTTP call plus a populated signature transient. It
asserts specifically on `tj_tax_<md5(signature)>` and on the *absence* of the
`tj_tax_<zip>_<state>` key, which only ever caches 400 zip-to-state
mismatches and would otherwise mask a broken signature.
Both new tests were verified to fail against mutated guards.
* update since docs
* Chore: Renumber unreleased release from 3.7.0 to 3.6.12.
The pending TaxJar response-cache work is retargeted from the 3.7.0 minor
to the 3.6.x patch line. Update the unreleased changelog and readme
headings, and move the five @SInCE stamps on the new cache-normalization
helpers so they document the version that will actually ship.
* Fix - Re-key the non-taxable record onto canonical TaxJar line item ids.
get_line_items() and get_backend_line_items() record exempt lines under the
context-specific `<product_id>-<cart_item_key>` / `<product_id>-<order_item_id>`
id, but assign_canonical_line_item_ids() then rewrites each line item's id to
`<product_id>-<fingerprint>-<occurrence>`, and that canonical id is what TaxJar
echoes back. get_itemized_tax_rates() looks the record up by the echoed id, so
the two key shapes could never match: the guard never fired and the 0% breakdown
line of a non-taxable product overwrote the shared Standard-class rate row.
That silently reverted the unreleased 3.6.12 fix for mixed taxable/non-taxable
carts. Both call sites now move the record onto the canonical ids, restoring the
invariant the property docblock already states ("Keyed by TaxJar line item id").
Applies @Abdalsalaam's review suggestions on #2983 verbatim, at both call sites.
Also updates three tests that indexed get_line_items()'s return positionally.
This PR keys that array by cart item key (and the backend one by order item ID)
and pins it in test_get_line_items_is_keyed_by_cart_item_key, so the tests now
take the single element rather than element zero.
Full suite: 399 tests, 975 assertions, green.
---------
Co-authored-by: Iyut <iyut85@yahoo.com>
Copy file name to clipboardExpand all lines: changelog.txt
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,7 @@
14
14
* Fix - Calculate tax correctly for carts mixing taxable and non-taxable products, so a non-taxable product no longer resets the standard tax rate to zero.
15
15
* Tweak - Centralize TaxJar address handling in an internal value object. No change to tax calculation.
16
16
* Tweak - Store tax rate rows against the postcode the rate was quoted for when the address postcode holds more than one comma-separated value.
17
+
* Tweak - Reduce redundant TaxJar API calls by matching cached tax responses across the cart and order paths and ignoring irrelevant formatting differences.
17
18
18
19
= 3.6.11 - 2026-08-05 =
19
20
* Fix - Prevent a fatal error during cart and checkout tax calculation when TaxJar returns an incomplete tax response.
0 commit comments