-
-
Notifications
You must be signed in to change notification settings - Fork 729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Checkout] Shipping fees update, remove order callback #13023
[Checkout] Shipping fees update, remove order callback #13023
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. That should speed up the app.
spec/system/admin/orders_spec.rb
Outdated
order2.contents.update_item(Spree::LineItem.where(order_id: order2.id).first, | ||
{ quantity: 5 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
order2.contents.update_item(Spree::LineItem.where(order_id: order2.id).first, | |
{ quantity: 5 }) | |
order2.contents.update_item(Spree::LineItem.find_by(order: order2), { quantity: 5 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
It seems more reasonable to be enforcing this at the controller level 👍
d7216ae
to
14e18f7
Compare
It should be handled in the controller, it's currently handled in `Spree::OrderContents#remove`. As long as we don't manually remove line item from an order we should be good. Currently it gets trigerred each time the order is saved, which seems to happen mutiple time when we finalize an order. It's a bit useless to recalculated the fees over and over Context, it was added here : openfoodfoundation@217eda8
And update related specs
User Order::Contents#update_item to update line item on an order, it ensures the order is properly updated
14e18f7
to
1afa7fe
Compare
Hey @rioug , Thanks for outlining the test scenarios, with the focus on the shipping method fees. I went through them, and if a cash payment method is used, I can confirm that adding items after reaching the However, the PR introduces a regression with Stripe, which only occurs, if the shipping method has a shipping fee. Below, when the order is setup using a shipping method with:
We can see, the payment total is twice the value of the order total, which results in a The same scenarios 1) and 2) in current master: The Stripe payment total equals the order total, so the (order-)payment state is In the tests above, the payment method was set with a transaction fee. However, this does not seem to be relevant in this case: the issue is observable as well, when no transaction fee is set: What do you think is causing this? It might be useful to note that this only occurs on checkout, and not for orders placed in the backoffice. Please let me know if you feel you need more tests to debug the issue. |
Thanks @filipefurtad0 I managed to reproduce the issue on my machine. I think it might be due to "stripe payment intent" not being updated appropriately when we update the order. I'll have a look at it. |
For payment that complete during the checkout (Paypal, Stripe) the amount was recorded twice against `order.payment_total`. This is because the `payment_total` gets updated in an afer_save Payment callback when a payment is completed, and then once more when we process payment in `Spree::Order#process_each_payment`. This is an existing issue on master, but it was hidden by the `update_shipping_fees!` callback, it trigerred an update of the order's total, which then updated `order.payment_total` with the correct value. Now that we removed the callback, the bug showed up. Note, I updated the stripe specs for consistency even though they are currently disabled.
@openfoodfoundation/reviewers Bug fix start at : c71ae35 |
|
||
if payment.completed? | ||
self.payment_total += payment.amount | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit weird to take a payment without updating the total. But I guess that we are just moving the responsibility of updating the total out of the callback. And at some point, we may not want payments in a callback either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was cause for me to look it up to make sure I understood. I found that four controllers update the order.payment_total
(via OrderManagement::Order::Updater#update_totals_and_states
):
checkout_controller.rb
, voucher_adjustments_controller.rb
, api/v0/shipments_controller.rb
, admin/adjustments_controller.rb
It is updated by counting up all payments. That seems like a much safer method than the incrementing above.
order.payment_total = payments.completed.sum(:amount)
Very good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue was actually caused by this :
openfoodnetwork/app/models/spree/payment.rb
Lines 235 to 237 in 31c7173
def update_order | |
OrderManagement::Order::Updater.new(order).after_payment_update(self) | |
end |
which is triggered by an
after_save
callback.So by the time the code reach these deleted lines the payment was already added to
order.payment_total
. It was hidden by the fact OrderManagement::Order::Updater#update_totals_and_states
was triggered further down the line, which now does not always happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. I can see that this triggers the same code (order.payment_total = payments.completed.sum(:amount)
)
If we can be sure that update_totals_and_states
is always triggered down the line (by a controller), then perhaps we can remove this model callback also! But I'm afraid to suggest it in this PR..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would need more investigation. I believe the payment callback is there to ensure the order.payment_total
is updated when a payment is completed outside the checkout. Ie, capturing a cash payment in the backoffice. There might be other scenarios as well, It's not something I would want to do here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, I have a suggestion to potentially simplify the spec, but it's fine either way.
@@ -69,6 +69,7 @@ | |||
|
|||
click_on "Complete order" | |||
expect(page).to have_content "Your order has been processed successfully" | |||
expect(page.find("#amount-paid").text).to have_content "$19.99" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using an ID, can we test for the associated label instead? (also below)
expect(page.find("#amount-paid").text).to have_content "$19.99" | |
expect(page).to have_content "Amount Paid\n$19.99" |
let(:payment) { build(:payment) } | ||
before { allow(order).to receive_messages pending_payments: [payment], total: 10 } | ||
|
||
it "should return false if no pending_payments available" do | ||
it "returns false if no pending_payments available" do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for tidying these 👍
|
||
if payment.completed? | ||
self.payment_total += payment.amount | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was cause for me to look it up to make sure I understood. I found that four controllers update the order.payment_total
(via OrderManagement::Order::Updater#update_totals_and_states
):
checkout_controller.rb
, voucher_adjustments_controller.rb
, api/v0/shipments_controller.rb
, admin/adjustments_controller.rb
It is updated by counting up all payments. That seems like a much safer method than the incrementing above.
order.payment_total = payments.completed.sum(:amount)
Very good!
Hey @rioug, Nice, the issue with the payment is fixed now 🎉
Having an order on step/state resulted in correct update of the shipping fee, which included added or removed items. As an example, with a 10% rate on shipping, changing the line item quantity from 2: to 4:
i) editing line items quantity resulted in correct update of the shipping fee, which included added or removed items. Same example as above, with a 10% rate on shipping, changing the line item quantity from 2: to 4: Looks good, I think we're ready to merge this one. Thanks again 💪 |
What? Why?
Now that checkout workflow is restarted when an order is updated, it fixes the issue with shipping fee calculation. That said, while investigating the issue, I realised shipment fees were recalculated multiple times when completing an order , which seemed unnecessary. I tracked down the issue to a callback ( 😮 surprise! 😮 surprise! ) :
openfoodnetwork/app/models/spree/order.rb
Line 109 in ee2a6bf
Given that we have https://github.com/openfoodfoundation/openfoodnetwork/blob/master/app/models/spree/order_contents.rb that should be used to managed adding/updating/removing an order's line item.
Spree::OrderContents
already handle updating shipment and shipment fees, so now thebefore_save
callback becomes redundant.Drawback : shipment fees won't be updated is someone directly update a line item on an order. There isn't anyway to prevent that (as far as I know), we (as the dev team) need to enforce the use
Spree::OrderContents
for any line item update.What should we test?
As an enterprise manager:
As a customer:
--> they should be matching.
Same scenario as above but this time once on step 3 of checkout, use "Edit" link next to "Order Details" to update your order
As an enterprise manager
As an enterprise manager, in the backoffice
--> check the shipping fee is calculated correctly
-- Add or update a line item in the order
--> check the shipping fee is updated correctly
Release notes
Changelog Category (reviewers may add a label for the release notes):
The title of the pull request will be included in the release notes.
Dependencies
#12954 needs to be merged first