Skip to content

Reset the shipping breakdown on every cart calculate#2476

Merged
glennjacobs merged 2 commits into
1.xfrom
fix/shipping-option-resets-breakdown-2199
May 19, 2026
Merged

Reset the shipping breakdown on every cart calculate#2476
glennjacobs merged 2 commits into
1.xfrom
fix/shipping-option-resets-breakdown-2199

Conversation

@glennjacobs
Copy link
Copy Markdown
Contributor

Summary

  • ApplyShipping now constructs a fresh ShippingBreakdown on each run rather than mutating the cart's previously-cached one.
  • The previous if (\$cart->shippingOptionOverride) { \$shippingBreakdown->items = collect(); } clear is removed — it was a partial workaround for the same issue.
  • Adds a regression test that swaps the cart's shipping option mid-request and asserts both the breakdown item count and shipping subtotal reflect only the latest option.

Why

ApplyShipping was seeded from \$cart->shippingBreakdown ?: new ShippingBreakdown and then put()'d the resolved option into the existing items collection. Calling CartSession::setShippingOption() (or otherwise recalculating the cart) within the same request added the new option to the items collection alongside the previous one — \$shippingBreakdown->items->sum('price.value') then summed both. The page refresh fix that reporters noticed was because shippingBreakdown is runtime-only and disappears between requests.

The breakdown is purely a derived view of the single currently-selected option, so starting fresh every time is both correct and simpler.

Fixes #2199.

Test plan

  • vendor/bin/pest --testsuite=core — 504 passing
  • Manual: call CartSession::setShippingOption() twice in a row with different options → cart total reflects only the latest

ApplyShipping reused the cart's existing ShippingBreakdown and only
cleared its items when a shippingOptionOverride was set. Switching
shipping options via CartSession::setShippingOption() therefore
appended the new option to the breakdown while keeping the old one,
so the shipping subtotal summed both prices until the next page load.

Start each run with a fresh ShippingBreakdown — the option is always
re-resolved from the shipping address (or the override), and the
breakdown is purely a derived value from that single option.

Fixes #2199
@alecritson
Copy link
Copy Markdown
Collaborator

In this case, what happens if a developer adds a custom pipeline class that needs to add additional shipping costs/breakdowns before they are calculated?

@glennjacobs
Copy link
Copy Markdown
Contributor Author

In this case, what happens if a developer adds a custom pipeline class that needs to add additional shipping costs/breakdowns before they are calculated?

The post-ApplyShipping slot is the supported extension point for additional shipping costs; that still works. The pre-ApplyShipping slot was never reliable (override path already cleared it) and is the right thing to break in service of fixing the duplicate-option bug. If they want a documented hook for pre-resolution adjustments, that's a separate feature, not something to revert this fix for.

@glennjacobs glennjacobs merged commit 5e6dec0 into 1.x May 19, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Roadmap May 19, 2026
@glennjacobs glennjacobs deleted the fix/shipping-option-resets-breakdown-2199 branch May 19, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Shipping Option Change adds up the costs

2 participants