Let's refresh this topic
We discussed here a couple of years ago: when a shipping method uses the Amount Rule (e.g. "free shipping above 60€"), the eligibility check is done against the cart subtotal BEFORE coupon/cart discounts (subtotalnetto/subtotalbrutto).
Example:
- Free shipping threshold: 60€
- Cart subtotal: 64€ -> free shipping becomes eligible
- Customer applies a 20% coupon -> final payable amount is 51.20€ (belo the 60€ threshold)
- Free shipping is still applied, because the Amount Rule never looks at the discounted amount (wdnetto/wdbrutto), only the pre-discount one.
You mentioned back then that
wdnetto (subtotal minus discounts) could be used for this, but that it includes all discounts, not only "gift" type ones - which is exactly right, and for our case (regular percentage coupons) that's the value we want.
I put together a small, fully backward-compatible patch that adds this as an OPT-IN option (off by default, so nothing changes unless a store owner explicitly enables it):
-
getPossibleShippingMethods() in
shipping.php gets two new optional trailing parameters (discounted netto/brutto). When a new component parameter (
shipping_amount_rule_use_discounted) is enabled AND a discounted amount is passed, the Amount Rule check uses the post-discount amount instead of the pre-discount one.
-
order.php and
view.html.php (checkout) now pass
wdnetto/wdbrutto through to that function.
- New Global Configuration -> Shipping field to toggle it on/off.
Reasoning for making it opt-in rather than changing default behavior: some shops may deliberately want the free-shipping threshold based on gross cart value as a marketing incentive regardless of coupons, so I didn't want to silently change that for existing installs.
One more thing worth mentioning: coupons already have their own independent "Free Shipping" toggle (General Options tab), which
addShippingCosts() in
cart.php uses to force the selected method's cost to 0 regardless of order value - that's a deliberate per-coupon override and should always win. So
getPossibleShippingMethods() also accepts the coupon's
free_shipping flag;
when it's set, the new discounted-amount check is skipped entirely and core's existing behavior takes over, so a coupon that explicitly grants free shipping still works exactly as it does today, no matter what the new Amount-Rule toggle is set to.
I've tested it on a live Phoca Cart 6 shop with both the toggle on and off, coupon applied/not applied, and it behaves as expected in all cases with no regressions when the toggle is off.
You marked this as Feature Request on
https://github.com/PhocaCz/PhocaCart/issues/235
Here is video demonstration:
https://www.youtube.com/watch?v=nbf9xHj5OGw
There is possible addition (open for discussion)
The coupon-override above currently skips the discounted-amount check for ALL amount-rule methods once a "Free Shipping" coupon is active - not just the one that's actually free. In most shops that probably doesn't matter, because the final price ends up at 0 regardless of which method the customer picks (addShippingCosts() forces it). But if a shop uses Amount Rule ranges to offer different carriers/delivery options (not just different prices) for different order values, this could unnecessarily widen the list of offered shipping methods while such a coupon is active - e.g. a mid-range paid tier method might show up as "eligible" (even though its own price bracket doesn't really match the discounted total) simply because a free-shipping coupon happens to be active.
A tighter version would only skip the discounted-amount check for methods that are genuinely free (cost == 0 and cost_additional == 0), leaving paid amount-rule tiers filtered against the discounted amount as normal even when such a coupon is active. That way the coupon override only affects the one method it's actually meant to affect.
The change would be localized to the Amount Rule block inside
getPossibleShippingMethods():
current (broader) version:
Code: Select all
$useDiscountedAmount = ($shipping_amount_rule_use_discounted == 1 && $couponFreeShipping != 1);
narrower version:
Code: Select all
$isFreeMethod = ((float)$v->cost == 0 && (float)$v->cost_additional == 0);
$useDiscountedAmount = ($shipping_amount_rule_use_discounted == 1 && !($couponFreeShipping == 1 && $isFreeMethod));
Happy to include either version in the PR - wanted to lay out both here
first since it changes behavior slightly beyond the original bug report.