-
-
Notifications
You must be signed in to change notification settings - Fork 730
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
[vouchers] error moving between summary and cart pages #11117
[vouchers] error moving between summary and cart pages #11117
Conversation
ef43e32
to
3cddd4d
Compare
3cddd4d
to
60aa3c5
Compare
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 like a good fix! I haven't reviewed the dependent PR though because it didn't seem ready.
It would be good to fix the typo, and I've left some comments to consider for bonus points :)
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 was about to approve but changes were requested already. So I'll move this back to In Dev.
9c330f9
to
dddc886
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Amount calculation is handled by VoucherAdjustmentService.calculate
It now uses `order.pre_discount_total` to make any calculation, that means you can call it multiple time and you will still get the same adjustment amount, included_tax and tax adjustment when needed. This is assuming nothing changed on the order.
Testing that VoucherAdjustmentsService.calculate has been called after a transition doens't work, skipping test for now.
This is to make sure the voucher are recalculated when a customer update the order content from the `/cart` page. This is tested with system test
This is specificly for voucher with a tax component, but it will also become relevant for percentage based voucher.
Plus, update other related spec to be consistent
It was confusing as I was re assigning a variable given as a parameter
Voucher will be automatically applied when the order transition to the confirmation step. No need to do the work twice.
It is important that the calculated voucher adjustments don't change if they are recalculated and it is equally important that they are updated if the order has changed
dddc886
to
0e0850e
Compare
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 work!
|
||
def assert_db_voucher_adjustment(amount, tax_amount) | ||
adjustment = order_within_zone.voucher_adjustments.first | ||
#adjustment.reload |
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.
This line is removed in another commit.
We need to do this to make sure when display the payment method again. Plus spec
Thanks for the thorough testing @drummer83 !
I believe this is an existing behaviour, nothing to do with voucher. But I agree it's a little bit confusing, it should at least redirect to step 2 in case you need to change payment method
I don't think that was intentional, from memory the transaction fee was excluded from voucher calculation, but I haven't had time to double check that. I fixed some of the issues, but I am still looking at anything related to payment fees. |
@filipefurtad0 I am trying to create an order with a payment and payment fee. I am not quite sure how to create the payment fee, do you have any pointers ? let(:bogus_payment) { create(:bogus_payment_method, distributors: [create(:enterprise)]) }
before do
payment = create(:payment, amount: 1, payment_method: bogus_payment)
order.payments << payment
order.save!
order.update_payment_fees!
end I think I need to setup some sort of fees on the payment ? |
Ok, looks like you keep working within this PR so I will move back to In Dev. |
Hey @rioug,
For a transaction fee to be applied, in addition to the payment method, we'd need to set up a calculator. But maybe there's an easier way, by using the factory for orders with fees In case you need more granularity, like setting the calculator type, or values, then the approach on the payment_spec.rb would be best, I guess. Hope this helps. |
If a user come back to checkout step 2 from step 3, the order will have payment and possibly payment fee existing. This can interfere with voucher calculation, so we clear them. The user can then select a payment method again if needed
Error messages have been updated to be more user friendly. This spec was missed somehow.
This is an existing bug so I won't be fixing it here. But as you noticed, it will be recalculated as we proceed to checkout again so it's a "minor" issue
I looked at this again, and transaction fees are included in the tax calculation for tax excluded from price. Nothing should have changed here. So the "AFTER" is correct here. I think I fixed all the other issue |
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, but pending a question about the payments.clear
call.
@@ -47,6 +47,10 @@ def add_voucher | |||
return false | |||
end | |||
|
|||
# Clear payments and payment_fee, to not affect voucher adjustment calculation | |||
@order.all_adjustments.payment_fee.destroy_all | |||
@order.payments.clear |
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.
Sorry but I have to ask, is this potentially clearing records of actual payments?
I'm guessing at this point the payments (and indeed order) are in an "incomplete" state, so it's ok to delete. But perhaps we should add a scope just in case? Eg:
@order.payments.incomplete.clear
I looked at the Payment model and expected to see a before_destroy
for this but didn't. Maybe it should be there..
@mkllnk do you have any insights?
# Clear payments and payment fees, to not affect voucher adjustment calculation | ||
def clear_payments | ||
@order.all_adjustments.payment_fee.destroy_all | ||
@order.payments.clear |
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.
That's a good question: do we ever have complete payments in this code path?
It looks like they would influence the calculation if we kept them. So that would need special consideration.
Looking into the state machine, we can restart the checkout any time until the order is finalised. At the time of finalising the order, the payment has been taken already. So I think, it can happen that we take a payment and then face a stock conflict and have to restart the checkout.
@rioug, do you agree with my theory? It would mean that you need to calculate totals for voucher amounts considering payments instead of clearing them out, I think.
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.
My understanding is that payment are processed once we confirm the order, see below:
openfoodnetwork/app/controllers/split_checkout_controller.rb
Lines 115 to 126 in ad37c40
def confirm_order | |
return unless summary_step? && @order.confirmation? | |
return unless validate_summary! && @order.errors.empty? | |
@order.customer.touch :terms_and_conditions_accepted_at | |
return true if redirect_to_payment_gateway | |
@order.process_payments! | |
@order.confirm! | |
order_completion_reset @order | |
end |
and once the order is confirmed then the state machine will finalise the order. So If I understand correctly we shouldn't have any completed payments when navigating between checkout steps.
Also if the checkout is restarted, the the user will be going through the payment step again and will be able to (re) choose the payment method.
I added this to fix a specific scenario where the user goes through the checkout till the confirmation step, then goes back to the payment step and add a voucher covering the order amount. In this case we need to remove any existing payment/payment fee as now there is no payment required.
Would we have an already completed payment if we face a stock conflict and have to restart the checkout ? You would think that we would check the stock situation before taking a payment.
From what I can see, we would be redirected to cart if there is a stock issue when navigation checkout steps:
redirect_to_cart_path && return unless valid_order_line_items? |
openfoodnetwork/app/controllers/concerns/checkout_callbacks.rb
Lines 66 to 70 in ad37c40
def valid_order_line_items? | |
@order.insufficient_stock_lines.empty? && | |
OrderCycleDistributedVariants.new(@order.order_cycle, @order.distributor). | |
distributes_order_variants?(@order) | |
end |
I couldn't see any other checks so maybe I am missing something here.
Anyway, I'll apply @dacook suggestion to be on the safer side.
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.
Would we have an already completed payment if we face a stock conflict and have to restart the checkout ? You would think that we would check the stock situation before taking a payment.
From what I can see, we would be redirected to cart if there is a stock issue when navigation checkout steps
Of course we check the stock before we take a payment but there's always room for race conditions. We often process several checkouts in the same second and it can happen that two people try to checkout the same last item at the same time. It's really hard to predict what exactly happens because it depends on the timing and where the error is raised.
Actually, the CurrentOrderLocker should prevent this. So maybe it's not a problem any more. I'm just scared that this race condition will come back to haunt us... 😨
Use destroy_all so we don't have to manually delete the payment fees adjustment
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.
👍 Good one
Hi @rioug, ConclusionTo unblock the percentage PR and to keep things simple I'd vote to merge this one and fix the open issues in separate PRs. I will create issues for those. Please go ahead and merge if you agree or let me know if you don't. Testing notes AFTER staging
General issues AFTER staging
|
What? Why?
Matt's work in #11003 fix some part of this issue but it doesn't cover the scenario when there is a tax included or excluded from the price.
Reviewers, new code starts here : 9fccea3
What should we test?
Assuming you have a shop with a voucher set up, follow the scenario below for voucher with no tax, with tax included in price and tax excluded from the price:
-> Check the voucher is still displayed properly
Additional test :
As above proceed to the summary step, and then go to the /cart page, and then follow the scenario below, ,again for voucher with no tax, with tax included in price and tax excluded from the price:
-> check total and voucher are updated accordingly
-> Check the voucher is still there on the payment step
-> Check the voucher is correct on the summary step
Payment fees and voucher
Payment fees are calculated based on the item total, and are recalculated when confirming the order. Vouchers are calculated based on the order total. The main thing to check here is to make sure
Release notes
Changelog Category: User facing changes
The title of the pull request will be included in the release notes.
Dependencies
This PR
#11003#11135 need to be merged first