Skip to content
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

Conversation

rioug
Copy link
Collaborator

@rioug rioug commented Jun 26, 2023

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:

  • Go through checkout and add a voucher at the payment step
  • Proceed to summary and click on "edit order details"
  • Go back to summary step by clicking checkout button
    -> 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:

  • Update quantity
    -> check total and voucher are updated accordingly
  • Click on the checkout button
  • Go through checkout steps again
    -> 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

  • when a voucher cover the order total or more, payment not is required, so the payment fee shouldn't apply
  • when using a percentage based payment fee, the payment fee shouldn't change when confirming an order with a voucher

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

@rioug rioug force-pushed the 10857-voucher-error-moving-between-summary-and-cart-take2 branch from ef43e32 to 3cddd4d Compare June 26, 2023 06:12
@rioug rioug force-pushed the 10857-voucher-error-moving-between-summary-and-cart-take2 branch from 3cddd4d to 60aa3c5 Compare June 26, 2023 23:35
@dacook dacook self-requested a review June 28, 2023 04:56
Copy link
Member

@dacook dacook left a 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 :)

spec/services/voucher_adjustments_service_spec.rb Outdated Show resolved Hide resolved
app/models/spree/order/checkout.rb Outdated Show resolved Hide resolved
app/controllers/spree/orders_controller.rb Outdated Show resolved Hide resolved
spec/system/consumer/split_checkout_tax_incl_spec.rb Outdated Show resolved Hide resolved
Copy link
Member

@mkllnk mkllnk left a 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.

app/services/voucher_adjustments_service.rb Show resolved Hide resolved
app/services/voucher_adjustments_service.rb Outdated Show resolved Hide resolved
spec/services/voucher_adjustments_service_spec.rb Outdated Show resolved Hide resolved
app/controllers/spree/orders_controller.rb Outdated Show resolved Hide resolved
spec/system/consumer/split_checkout_tax_incl_spec.rb Outdated Show resolved Hide resolved
@rioug rioug force-pushed the 10857-voucher-error-moving-between-summary-and-cart-take2 branch 2 times, most recently from 9c330f9 to dddc886 Compare June 30, 2023 04:51
@rioug rioug requested a review from dacook June 30, 2023 04:57
@dacook

This comment was marked as outdated.

@dacook

This comment was marked as outdated.

@rioug rioug self-assigned this Jul 14, 2023
Matt-Yorkley and others added 13 commits July 14, 2023 14:46
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
@rioug rioug force-pushed the 10857-voucher-error-moving-between-summary-and-cart-take2 branch from dddc886 to 0e0850e Compare July 14, 2023 04:49
@rioug rioug added the priority We focus on this issue right now label Jul 14, 2023
@rioug rioug requested a review from mkllnk July 14, 2023 05:27
Copy link
Member

@mkllnk mkllnk left a 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
Copy link
Member

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
@rioug
Copy link
Collaborator Author

rioug commented Jul 28, 2023

Thanks for the thorough testing @drummer83 !

Editing the cart after completing step 1 and 2 of checkout already, redirects to step 1 when clicking checkout. This has already been completed (as step 2 has been as well), so shouldn't we redirect to step 3 instead? Shipping method should be remembered.

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

Tax calculation for tax excluded from price changed:

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.

@rioug
Copy link
Collaborator Author

rioug commented Jul 28, 2023

@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 ?
This is what I tried so far :

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 ?

@drummer83
Copy link
Contributor

Ok, looks like you keep working within this PR so I will move back to In Dev.

@drummer83 drummer83 removed their assignment Jul 28, 2023
@filipefurtad0
Copy link
Contributor

Hey @rioug,

This is what I tried so far :

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 (:completed_order_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.
@rioug
Copy link
Collaborator Author

rioug commented Jul 31, 2023

@drummer83

Editing an order on /cart page doesn't update transaction fees. This happens only after proceeding to checkout again.

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

Tax calculation for tax excluded from price changed. Was this intentional and decided somewhere? ❓

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

@rioug rioug requested review from mkllnk and dacook July 31, 2023 05:33
Copy link
Member

@dacook dacook left a 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
Copy link
Member

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
Copy link
Member

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.

Copy link
Collaborator Author

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:

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?

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.

Copy link
Member

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
@rioug rioug requested a review from mkllnk August 7, 2023 01:00
Copy link
Member

@dacook dacook left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Good one

@drummer83 drummer83 added pr-staged-au staging.openfoodnetwork.org.au pr-staged-uk staging.openfoodnetwork.org.uk and removed pr-staged-au staging.openfoodnetwork.org.au labels Aug 8, 2023
@drummer83
Copy link
Contributor

drummer83 commented Aug 8, 2023

Hi @rioug,
We're getting closer. 👍
Thanks for continuing your work on this!

Conclusion

To 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

Test case Tested for 'No tax', 'Tax incl. in price', 'Tax excl. from price'
Moving between summary and VIEWING cart ✔️
Moving between summary and INCREASING cart ✔️ 1st checkout: if order total < voucher amount then 'no payment required' is shown and it's listed on step 3 (img 5); ❌ After editing and increasing the cart (still order total < voucher amount) the 'no payment required' is NOT displayed, a payment method needs to be selected and then on step 3 the payment method and transaction fee is displayed even though the voucher covers the order total (img 6); ➡️ #11358
Moving between summary and REDUCING cart ✔️ 1st checkout: if order total < voucher amount then 'no payment required' is shown and it's listed on step 3 (img 5); ❌ After editing and reducing the cart (still order total < voucher amount) the 'no payment required' is NOT displayed, a payment method needs to be selected and then on step 3 the payment method and transaction fee is displayed even though the voucher covers the order total (img 6); ➡️ same issue as above
Voucher removed from order when moving between summary and cart? No. ✔️
Order total > voucher amount ✔️
Order total < 0 due to editing order (#11233) ✔️
Payment fee doesn't change when applying the voucher ✔️
Payment fee is not applied when order total <= voucher amount ❌ Payment fee is still applied when editing the cart after being on step 3 of checkout already (img 6). ➡️ same issue as above

Image 5:
image

Image 6:
image

General issues AFTER staging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority We focus on this issue right now
Projects
Archived in project
7 participants