Problem/Motivation
When using the ShippingEvents::SHIPPING_RATES event, rates are altered, but those alterations are not reflected in the order.
This means any discounts or markups are shown in the shipping pane, but are not included in the shipping price.
I set this to major, not to be dramatic, but because sites that use the event to mark up rates may have orders being placed with the wrong shipping costs.
Steps to reproduce
- Add a
ShippingEvents::SHIPPING_RATESevent subscriber with a custom module. - Add two flat rate options through the UI.
- Alter both rates with your event subscriber.
Result:
When the checkout pane is loaded, the default selected rate is correct, because calculateRates was called, and the rate was applied to the shipment. When you change to the second rate, the rates are correct in the shipping information pane, but the check for $should_refresh prevents the EarlyOrderProcessor from applying the altered rates to the order.
Proposed resolution
Not sure. commenting out:
if (!$should_refresh) {
continue;
}Allows the altered rates from the event subscriber to be applied, but also causes the rates to be collected, which causes needless requests and responses from carriers.
We should apply the rates upon every selection, but we certainly don't need to recalculate the rates every time a selection is made.
Remaining tasks
Verify the bug through testing, and find a way to reflect the new rates on the shipment.
| Comment | File | Size | Author |
|---|---|---|---|
| #23 | 3424688-23.patch | 13.86 KB | khiminrm |
| #21 | 3424688-21.patch | 939 bytes | khiminrm |
| #16 | Include the discount in the displayed amount - result.png | 39.79 KB | khiminrm |
| #16 | Include the discount in the displayed amount.png | 47.25 KB | khiminrm |
| #16 | Only show the discount on the order total summary - result.png | 33.61 KB | khiminrm |
Issue fork commerce_shipping-3424688
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
tonytheferg commentedFinding in my testing that the event rate alterations only apply if I comment out this section in the EarlyOrderProcessor.php:
https://git.drupalcode.org/project/commerce_shipping/-/blob/8.x-2.x/src/...
Comment #3
tonytheferg commentedComment #4
tonytheferg commentedComment #5
tonytheferg commentedComment #6
tonytheferg commentedCurious how much stuff blows up by not continuing if
!$should_refresh. 🤣Comment #7
tonytheferg commentedIt may be good to invoke the event in the test and make selections here between the two rates, and assert that the order summary reflects those changes:
https://git.drupalcode.org/project/commerce_shipping/-/blob/8.x-2.x/test...
The event is tested here, but there is no verification that the altered rate is applied to the order after selecting between the two altered rates:
https://git.drupalcode.org/project/commerce_shipping/-/blob/8.x-2.x/test...
Comment #8
tonytheferg commentedThe more I think about this, (and I don't know the codebase that well) I think this needs to be fixed in the
LateOrderProcessor. So that the$rateis passed to the$shipment_amount.https://git.drupalcode.org/project/commerce_shipping/-/blob/8.x-2.x/src/...
Comment #9
tonytheferg commentedMaybe we could set the altered rates in
data, so that we could use them, and then unset the data on refresh.Comment #10
tonytheferg commentedThis works... though I realize it may not be desirable to set the original rate as the altered rate...
I think it shows that the original rate is getting passed to the shipment when there is no refresh while selecting new rates.
One work around might be to just
$rate->setOriginalAmount($new_price);in my event subscriber instead of$rate->setAmount($new_price);Comment #12
jsacksick commentedDefinitely not the right fix... Having the original amount allows us to show a strike-through price in case the amount is lower (that is used by the promotion module for example).
I'd be curious to know if your behavior persists after downgrading to a lower commerce_shipping version. (I'm suspecting this regression was introduced not so long ago).
Comment #13
tonytheferg commentedYeah.
Well, it's present in 8.x-2.5 which was released in Jan 2023. I didn't chase it any farther back than that due to composer dependancies on my environment.
I think in my use case I can just set the Original amounts in addition to setting the Amount in my Event Subscriber.
This doesn't trigger any unnecessary recalculations, nor does it hinder shipping promotions from being applied, so it works pretty well.
I think the issue should stay open until someone has time to track it down.
Comment #14
poker10 commentedWe are experiencing this issue as well. We are using the
ShippingEvents::SHIPPING_RATESevent subscriber to alter one of the shipping rates - to calculate it dynamically via 3rd party API. Just setting$rate->setAmount($new_price);does not work as supposed (the rate is displayed correctly in shipping pane, but not in the order). Workaround in #13 works. I did not have time to track the exact problem down yet.Comment #16
khiminrm commentedI've tested custom event subscriber and can confirm, it updates only shipping rates amount, not order total.
I've also tested shipment promotions.
Created 'Fixed amount off the shipment amount' with 2$ amount.
With these settings:
I had such results:
And with these settings:
Such results:
I've checked also PromotionSubscriber.php, which uses the same 'ShippingEvents::SHIPPING_RATES' event. It updates only the amount of the rates and not order total. And it updates the amount of the rates only when 'Include the discount in the displayed amount' option is selected in the promotion.
Comment #17
khiminrm commentedI think there is conflict between shipment promotions and custom event subscriber to the event.
I've found that when commenting these lines https://git.drupalcode.org/project/commerce_shipping/-/commit/90b5400440... the custom rates from the event subscriber works, but when there is shipment promotion and custom event subscriber for changing rates, there is a mess. So maybe we need review changes made for https://www.drupal.org/project/commerce_shipping/issues/3107367 and add more conditions in the EarlyOrderProcessor. But if there is custom event subscriber and it alters a rate, maybe it should be in higher priority than promoted rate? Trying to find solution...
Comment #18
jsacksick commentedCan you check by any chance if the patch from #3413473: Duplicate promotion adjustments added to order items because of the promotion subscriber has an impact?
Comment #19
khiminrm commented@jsacksick I've tested the patch. didn't notice changes.
Comment #20
tonytheferg commentedThis is reproducible without promotions.
Comment #21
khiminrm commentedI've found that we need to set shipment amount in
EarlyOrderProcessoronly if the shipment has adjustments and we should calculate this as rate amount + any discounts. I've tested only with fixed amount off promotion, without any promotion and it looks like it works. When there is some discount it's calculated from the altered rate amount. So in custom event subscriber can contain only $rate->setAmount() without $rate->setOriginalAmount().Attaching a quick patch I've created and tested along with the patch from https://www.drupal.org/project/commerce_shipping/issues/3413473. Haven't tested without it yet.
Comment #22
khiminrm commentedLooks like we can't use adjustments in EarlyOrderProcessor to calculate the shipment amount with discounts as on this step we can have wrong adjustments.
Comment #23
khiminrm commentedAnother solution is to use new additional field in shipment and property in rate to save the shipment amount just before applying promotions in PromotionSubscriber and re-use this value in EarlyOrderProcessor.
I've called this field
raw_amount. Not best name, I think, but just for testing, reviewing should work.So it should be amount value after all rate alterations and just before PromotionSubscriber.
Attaching a patch, but it includes also fixes from https://www.drupal.org/project/commerce_shipping/issues/3413473. Can try to remove those fixes and re-test and attach patch without the fixes.
Comment #24
tonytheferg commentedWell if another amount field is considered, we should include that field in the form display so that users can manually specify an amount through the UI.
See:
https://www.drupal.org/project/commerce_shipping/issues/3420292
And related issues
Comment #25
khiminrm commented@tonytheferg not sure about the case when we should use it on the form. This is just to save final altered value just before applying the promotions and make this all work with custom event subscriber where we alter the rate amount by using $rate->setAmount() or/and when the promotions are used. Can you share your ideas why we would we need those field on the form?
Comment #26
khiminrm commented@tonytheferg thanks! I will check those issue, but maybe tomorrow.
Comment #27
tonytheferg commentedNo problem. See Ryan's quote in the IS linked.
I think we should think about that and account for those thoughts.
A third amount field seems like a bit much IMO seeing as we have original_amount, and amount already.
Comment #28
khiminrm commentedI agree regarding third field. I don't like this idea too, but I don't see other solution how to save the latest altered amount without promotions applied. I couldn't find a way how to calculate this amount in EarlyOrderProcessor.
@jsacksick what do you think? What else we can try to do there?
Comment #29
jsacksick commentedI don't really get why there is a need for a new field... Thought that is why original amount was added already?
Comment #30
jsacksick commentedSo the patch from #23 has changes from the other issue I linked in comment #18.
I don't think introducing another persistent field with a confusing name is going to help. If all we need to do is store the amount before alterations (which was originally the intent of "original_amount", then we can/should use the shipment data for that.
We would set the value from the early order processor and unset it from the late order processor or something.
This would simplify the code and wouldn't require adding additional getters/setters etc.
Comment #31
jsacksick commentedThe reason why the amount is "reset" from the early order processor is that it represents the unaltered shipping rate amount, prior to invoking event subscribers and prior to applying promotions.
In case we don't reset it, then the subscribers are going to alter an already altered amount. So in case there is a price markup applied from a subscriber, we'll keep applying the markup on each refresh indefinitely?
Comment #33
tonytheferg commentedI just wan't to reiterate #20
The steps to reproduce in OP have no promotions applied.
Comment #34
khiminrm commented@tonytheferg yes, I know about it. But as I wrote in https://www.drupal.org/project/commerce_shipping/issues/3424688#comment-... those change which was done for promotion fixes, breaks calculations when custom subscriber is used to alter the rates.
You can try just to comment
in EarlyOrderProcessor and re-test.
And if you can, please, test also my solution from the MR. Thanks!
Comment #37
khiminrm commentedComment #38
jsacksick commented@tonytheferg: Did you get a chance to test the MR?
Comment #39
tonytheferg commentedI can try to have a look today.
Comment #40
tonytheferg commentedWith brief manual testing, the patch seems to fix the behavior reported in the issue. I don't understand how promotions were breaking this, but If you guys are confident this is the fix, then I say +1
Comment #41
tonytheferg commentedI think we definitely need to make sure that the test is checking for an altered rate from an event subscriber, and also accounting for a couple of selections being made on the checkout pane.
This bug was not caught before because there wasn't sufficient testing in to test that the event subscriber rate was applied both to the checkout Pane and also to the order summary, so I would highly recommend adding a Functional Javascript test to make sure that this doesn't get broken later down the road.
Comment #42
tonytheferg commentedSetting to needs work for more explicit functional tests.
Comment #44
jsacksick commentedSince you've confirmed the fix and I'm about to tag a new release, went ahead and merged the MR. We can expand the tests in a followup issue, in the meantime, closing this one.
Comment #46
rhovlandInteresting. I encountered this during development of the best rate shipping module and got around it by setting both the amount and the original amount. Didn't know it was actually a bug!