-
-
Notifications
You must be signed in to change notification settings - Fork 708
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
10432 vouchers bare minimum checkout #10587
10432 vouchers bare minimum checkout #10587
Conversation
53028e1
to
cb3ab94
Compare
@mkllnk I committed my latest changes, it still a WIP on handling taxes when tax is not included in the order price : e19d7da I went with using the same TODO:
def compute_amount(order)
amount = calculator.compute(order)
# Use the tax on top of order price to check the amount to use
total = order.total + order.additional_tax_total
return -total if amount.abs > total
amount
end I am trying to set up test data to unit test this, looks like the existing order factories don't offer what I need.
|
d665fef
to
f24e605
Compare
app/models/voucher.rb
Outdated
amount: amount, | ||
updated_at: Time.zone.now | ||
) | ||
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.
Ideally all the calculation would be encapsulated in a Calculator
but I don't think creating the tax adjustment belongs in one of them. So I kept it in the Voucher
class.
That means we need to call Voucher.adjust!
and we can't just rely on "Spree::Ajustment.update_adjustment!" ( It is call by the order updater
)
openfoodnetwork/app/models/spree/adjustment.rb
Lines 100 to 117 in c34ced2
def update_adjustment!(calculable = nil, force: false) | |
return amount if immutable? && !force | |
if calculable.nil? && adjustable.nil? | |
delete | |
return 0.0 | |
end | |
if originator.present? | |
amount = originator.compute_amount(calculable || adjustable) | |
update_columns( | |
amount: amount, | |
updated_at: Time.zone.now, | |
) | |
end | |
amount | |
end |
I found a bug where the cart disappear after applying a voucher. I'll be looking at that but don't think it should delay the reviewing |
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.
Wow, great work. This is bigger than I imagined. Nice small commits though. 👍
I left some comments. Let me know what you think.
app/models/voucher.rb
Outdated
if order.additional_tax_total.positive? | ||
handle_tax_excluded_from_price(order, amount) | ||
else | ||
handle_tax_included_in_price(order, 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.
I think it's possible that an order has items including tax and items excluding tax and even items having both if they are subject to two tax categories. I think that we need to find all items for each type of tax calculation and then create adjustments for whichever kind is present. It means that we can't use the existing totals and have to add it up ourselves. Or am I overcomplicating it?
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 am not sure about that, I always though that it was one or the other. Maybe something to clarify with Lynne/Kirsten.
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.
Just to summarise here as well: It's possible to have mixed included and excluded tax on an order and even on single items but we are ignoring that for now and implement that later.
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.
So, this implementation is incomplete and has a bug? Seems risky to leave it in, but maybe necessary for the interim.
I get a weird bug when adding a voucher to an order, where the page reload but the cart disappear. I figured out it's because the angularjs application isn't loading properly and the ng-cloak below means the raw template stays hidden openfoodnetwork/app/views/shared/menu/_large_menu.html.haml Lines 37 to 38 in 2f6b730
Code extract responsible for adding the voucher : if add_voucher
return redirect_to checkout_step_path(:payment)
elsif @order.errors.present?
return render_error
end I am not quite sure why this happens but I did notice that when I add the voucher the request is processed as "CABLE_READY" , here we are redirecting to the payment step from the payment step. The car isn't displayed.
If I reload the page, it is processed as "HTML" and the cart is displayed properly
The weird bit is: if I go to the "Payment step" from the "Details step" for instance , request is processed as "CABLE_READY" but the cart is displayed properly 😕 ! The openfoodnetwork/app/views/split_checkout/_form.html.haml Lines 5 to 6 in 2f6b730
I don't think removing |
Fixed by this commit 8672cbe |
73bb6b1
to
748eca0
Compare
app/models/voucher.rb
Outdated
acts_as_paranoid | ||
|
||
belongs_to :enterprise | ||
|
||
has_many :adjustments, | ||
as: :originator, | ||
class_name: 'Spree::Adjustment', | ||
inverse_of: :voucher, | ||
dependent: :nullify |
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.
Since we are using acts_as_paranoid
, do we want to allow a real destruction? If we don't then we could remove the dependent
option and I think then the destroy would fail if it's referenced.
app/models/voucher.rb
Outdated
if order.additional_tax_total.positive? | ||
handle_tax_excluded_from_price(order, amount) | ||
else | ||
handle_tax_included_in_price(order, 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.
Just to summarise here as well: It's possible to have mixed included and excluded tax on an order and even on single items but we are ignoring that for now and implement that later.
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! 💪
It's great how you solved the AngularJS problem with CableCar. This is ready for a second review. It's fairly big but I would imagine that rewriting history is a big task now as well. So maybe the next reviewer just has to be warned that there are a few detours in here. I'll let you decide if you want to update any commits before moving it into Code Review.
Thank you.
Oh, I just saw that it is in Code Review already. I would have left it there but then I saw a merge conflict. |
748eca0
to
6fdc8cf
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.
Exciting! 👍
@@ -1,5 +1,7 @@ | |||
.medium-6 | |||
%div.checkout-substep{"data-controller": "paymentmethod"} | |||
= render partial: "split_checkout/voucher_section", formats: [:cable_ready], locals: { order: @order, voucher_adjustment: @voucher_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.
This formats: [:cable_ready]
looks really weird to me and I think we don't actually need it, along with the multiple-format-rendering in the related controllers and the .cable_ready.haml
extension on the views/split_checkout/_voucher_section
(it can just be regular .html.haml
).
I'll take a look at it...
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.
if you have the partial as a regular .html.haml
then this will break (as you can see in the failing test in your PR) :
def render_voucher_section
render(
status: :ok,
cable_ready: cable_car.replace(
"#voucher-section",
partial(
"split_checkout/voucher_section",
locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
)
)
)
end
That's why I am using formats: [:cable_ready]
. I agree it looks weird but I couldn't find any other solution, do you have any suggestions ?
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.
Ah, I missed those failing request specs on the VoucherAdjustmentsController
. Okay, so this is partly why I was suggesting the changes in that other commit rioug@71e92ae, which is that the code path that runs when you actually use the app and the code path that is being encountered in those tests are actually two separate code paths with different outcomes, and it's really tricky to see which is which by just looking at the code in the specs.
Removing the explicit setting of request headers in that spec and removing the last test in it fixes the tests, and there's nothing to fix outside of the specs because it doesn't actually throw that error outside of the scenarios in the test suite.
I guess the new cops are effective :)
The "apply" button is disabled by default. If left enabled, a customer could try to apply an empty voucher, which results in system trying to move to the order summary step, an unexpected behaviour! We only enable the button when something is entered in the input.
As per review comment, use data-disable-with="false" do prevent Rails from automatically enabling the "Apply" button. We can then remove the timeout hack.
This partial is rendered inside another <form> element, nested form don't work.
…nguish between submission types The voucher apply button is inside form that has another a submit button, it leads to a weird situation where either one will submit the whole payments page form. Adding a named parameter on the voucher apply button means we can distinguish between the two by checking for the presence of params[:apply_voucher].
My editor automatically remove blank character on empty line, that's why rubocop got grumpy here.
It turns out the "tax_rate" association isn't used and wasn't working. Same for the "voucher" one, which I added to be consistent with existing code. Both of these weren't caught by the specs because you can't test associations with a custome relation with 'shouda-matchers' see: thoughtbot/shoulda-matchers#981
On a freshly mirrored prod db, I found these changes. I don't know why.. but hopefully this is correct.
I wrongly assumed that `voucher.create_adjustment` would return nil if failing to create an adjustment. I will in fact return an adjustment object with errors.
d898526
to
5eb6097
Compare
I just rebased on master which includes the fix (previously last commit) already. |
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.
Let's test this again.
Hey @rioug @abdellani , Thanks for the fix and the review. Going through the tests: 1) General test In the back office logged as an enterprise user :
On the website logged as a customer :
Applying the voucher adds a negative amount to the order. 2) Taxes and invoices It is possible to consider taxes on the invoice amounts: Related test cases:
Ok, so I'd say that the bare minimum is implemented 🎉 There are some issues thought - which will perhaps be addressed in the other related PR, but here in advance: x) Edge cases
iii) adding a voucher; visiting the /cart page; emptying the cart -> 🐌 A user can see the warning that the voucher is insufficient to cover for the order total, however this happens on the This is behind a feature toggle - so I think we can merge. Moving to ready to go! |
Great testing, I will merge this. It's good as a first iteration but we should create issues for what you found.
Definitely needs an issue.
Transaction fees are applied after the voucher. Gaetan knew this issue but the adjustments should be updated during checkout and the final result should be correct. I'm confused by your examples. A voucher amount of -$2 doesn't make sense to me in any case. I find the tax amounts confusing as well. I would need to know all the items and their tax rates to verify that it's correct.
All of them. Well, the current implementation just looks at the totals. So if you have a $10 order with a total tax of $2 included (coming from different tax categories, doesn't matter) and you apply a $10 voucher then it should have -$2 included tax taken off. It's all covered. If you apply a $5 voucher then it should take only -$1 tax off. It currently assumes that there's only included tax or only excluded tax, no mix. |
Thanks @mkllnk , Yes, indeed - I'll have to investigate each of these test cases, and make issues out of them.
Ok, great - that was my main point really, to make sure we're all aware of this. PS and a comment a bit outside the testing scope: with the current design, the customer may see an unnecessary "voucher value higher than order" message on step 2, as the order total may become higher than the voucher (due to the transaction fee), on step 3. I think this is misleading, and may suggest customers to place more items in the cart, to make best use of the voucher (i.e., not proceeding with checkout, going back to Maybe we could consider displaying that message on step 3 instead? |
That's a good idea from the UX perspective. I'm not sure why Gaetan didn't do it, maybe it's difficult. Or is Step 3 only displayed on some instances? |
Thanks @mkllnk , I'll raise this on Slack also as discussed in delivery circle.
Step 3 is always displayed |
What? Why?
Implement the minimal checkout functionality to be able to apply a voucher to an order.
What should we test?
You'll need to enable the vouchers feature in the backoffice, see #10523
General test
In the back office logged as an enterprise user :
On the website logged as a customer :
--> You should see a "Apply voucher" section
--> You should see a "$10 Voucher" box and a "Remove code" link
--> it should remove the voucher, and you should see the Input and Apply button as before
--> you should see the voucher applied to the order in the order summary column, highlighted in blue
--> you should see the voucher applied to the order in the order summary
Tax included in price
In the backoffice logged as an admin:
On the website logged as a customer :
--> you should see the voucher applied to the order in the order summary column, highlighted in blue, and a "(Includes tax)" line
--> you should see the voucher applied to the order in the order summary and a "(Includes tax)" line
Tax not included in price
In the backoffice logged as an admin:
On the website logged as a customer :
--> you should see the voucher and the voucher tax portion applied to the order in the order summary column, highlighted in blue, and a "(Includes tax)" line
--> you should see the voucher and the voucher tax portion applied to the order in the order summary and a "(Includes tax)" line
Voucher covers more than the order total
On the website logged as a customer :
--> You should see a "$10 Voucher" box and a "Remove code" link, and a warning.
--> you should see the voucher applied to the order in the order summary column, highlighted in blue. The value should be equal to minus the order total (and not -$10 as before). And the order total should be 0.
Release notes
Changelog Category: User facing changes
The title of the pull request will be included in the release notes.
Dependencies
Backoffice change will need to be merged first #10523Merged alreadyDocumentation updates