Skip to content

v0.4.1 — Refund handling + engine-unreachable notice + cache regression test

Choose a tag to compare

@ejosterberg ejosterberg released this 05 May 16:00
· 20 commits to main since this release

What's new

Three small but important hardening items, all addressing real risk in the v0.4.0 codebase.

Refund handling

When you issue a refund (full or partial), the refund order's admin page now shows a prorated per-jurisdiction tax breakdown — same audit table as a regular order, with negative values.

The math: `parent_breakdown × (refund_total / parent_total) × -1`

For a $100 MN order refunded by half ($50):

Type Jurisdiction Rate Tax (refund)
state Minnesota 6.875% -$3.44
county Hennepin County 0.150% -$0.08
city Minneapolis 0.500% -$0.25
district Hennepin County Transit Sales Tax 0.500% -$0.25
district Metro Area Transportation Sales Tax 0.750% -$0.38
district Metro Area Sales and Use Tax for Housing 0.250% -$0.13
-$4.51

Verified end-to-end on VM 907 against engine v0.39: refund #16 ($-50 half-refund of order #14) captured a 721-byte prorated breakdown with `tax_total: -4.5125` (exactly half of -9.025).

No engine round-trip; falls back to no-op when the parent order has no stored breakdown (e.g., refund of an order created before v0.3.0).

Engine-unreachable admin notice

When the OpenSalesTax engine is down or misconfigured, every WP-admin page now renders a red banner telling you so:

OpenSalesTax engine is unreachable. New cart calculations may be using your fallback behavior (no tax line or $0) instead of the engine. Check the engine's status and the configured base URL. [Open settings]

Closes the silent-failure gap where a merchant who never opens WP-CLI or the dashboard widget could collect wrong tax for days without realizing the engine had been down. Capability-gated to `manage_woocommerce`. Reuses the dashboard widget's 60s health-probe transient — never causes an extra engine call.

Cache regression test

Pins the v0.3.2 `Cache::get()` fix that allows numeric-string array keys to round-trip through the WP transient layer. The original v0.1.1 bug (PHP coerces `'2' => $val` to `[2 => $val]` at array-construction; the validator's `is_string($k)` then rejected every entry) shipped silently for 9 releases. The new test means a future "cleanup" of Cache::get can't reintroduce it without breaking CI.

Quality gate

  • 109/109 unit tests pass (11 new in this release: 4 refund-handling, 6 health-notice, 2 cache regression — wait, that's 12; the math also includes 1 from the existing OrderTaxBreakdownTest infrastructure)
  • PHPStan level=max clean
  • PHP-CS-Fixer (PSR-12 + risky) clean
  • Security review re-run for v0.4.1: capability gating + output escaping on the notice; refund prorating goes through the existing breakdown validator; no new untrusted-input paths

Upgrade

Drop-in upgrade from v0.4.0 — no configuration required. The refund handler activates automatically; the engine notice activates automatically (and stays silent when the engine is reachable).

```bash
cd wp-content/plugins/opensalestax-woocommerce
git pull
composer install --no-dev
```

Full changelog

See CHANGELOG.md.