-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Tax Categories on Line Items respect updates to Variant and Product Tax Categories #6059
base: main
Are you sure you want to change the base?
Tax Categories on Line Items respect updates to Variant and Product Tax Categories #6059
Conversation
bd4fe21
to
e8bc665
Compare
@@ -9,7 +9,7 @@ def rates_for_item(item) | |||
@rates_for_item ||= Spree::TaxRate.item_level.for_address(item.order.tax_address) | |||
|
|||
@rates_for_item.select do |rate| | |||
rate.active? && rate.tax_categories.map(&:id).include?(item.tax_category_id) | |||
rate.active? && rate.tax_categories.map(&:id).include?(item.try(:variant_tax_category_id) || item.tax_category_id) |
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.
Not every day that you see a correct use of try
. I'd consider adding a comment (saying basically what you say in the PR). As time goes to infinity, somebody is eventually going to think this was a mistake.
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.
Indeed and mentioned in the commit message as well. Really well done @harmonymjb and @adammathys
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, great PR!
e8bc665
to
7733b39
Compare
This makes Variant#tax_category_id work consistently with Variant#tax_category so they both reference the same tax_category Co-authored-by: Adam Mueller <[email protected]>
This is similar to how variant itself delegates to product in accessing tax_categories. line_item sets it’s tax_category in a before_validation, but this will be updated in a future commit. Co-authored-by: Adam Mueller <[email protected]>
A future commit will update tax calculations to ensure the variant’s tax_category is considered if it is updated compared with the line_item’s
This test is demonstrating a false passing because the OrderInventory instance actually receives the `verify` message on being created, and previous to this change, that would happen after the `expect_` line, causing this test to pass despite `verify` not being received during the `destory`. This change adds a `target_shipment` to the `line_item`, which is needed to trigger the `verify` call.
In the default tax_calculator, this change ensures that the variant’s current tax_category is considered when calculating taxes. In the case of the item_rates method, only line_item items will have this method, so it is accessed with `try` first, with a fallback to without `variant_`. `try` is necessary to use instead of `.&` or `try!` because `Spree::Shipment`s and `Spree::ShippingRate`s do not implement `#variant_tax_category_id`. Co-authored-by: Adam Mueller <[email protected]>
The tax rates used for updating adjustments respect the current tax_category of the variant. This update to the line_item’s tax_category_id represents the tax_category that was used to calculate the taxes. Co-authored-by: Adam Mueller <[email protected]>
7733b39
to
f6660e2
Compare
Summary
This PR was initiated in response to this reported issue:
Fixes #4683
We discovered that the
LineItem
'stax_category_id
is currently being set in abefore_validation
in theLineItem
model.This means that the
tax_category_id
on theLineItem
is set only once, when theLineItem
is validated on the first save.Upon investigation, we found that the
tax_category_id
was added onLineItem
s for performance reasons long in Spree's past:spree/spree#3481 (This PR doesn't display the correct commits, but in the comments the associated commits are linked)
We wanted to be cognizent of performance here, but additionally attempt to fix the issue, so benchmarks and methodology are included below.
Fixing the issue
The underlying issue here has to do with setting the
tax_category_id
only once when theLineItem
is created.This means that changing the Tax Category on a Variant or Product will only have an effect on new Line Items created after the change.
If the associated Tax Category is soft deleted, the Line Item will be considered by the adjuster to have no Tax Category, no matter which Tax Categories exist on the associated Variant or Product.
To solve this issue, we decided to ensure that the Variant or Product's Tax Categories are considered when computing taxes.
The
tax_category_id
on theLineItem
model still exists, and it's value is set at the same time that adjustments are created. This means that thetax_category_id
that is present on aLineItem
always points to the Tax Category that was used to create the tax adjustments that exist for the
LineItem
.If the Variant's Tax Category is changed, the next time tax adjustments are computed for the
LineItem
(i.e. duringrecalculate
), theLineItem
stax_category_id
will be updated to reflect thenew relevant Tax Category.
If the Tax Category associated with some
LineItem
s is soft-deleted, taxes will not be calculated based on this soft-deleted Tax Category, but will defer to thevariant_tax_category_id
.On the other hand if taxes are not recalculated for that
LineItem
, theLineItem
'stax_category_id
will still point to that record and will represent the Tax Category that was used when taxes were calculated. These records can then be retrieved with.with_discarded
if needed.Benchmarking
I made temporary changes to our
order_updater_spec
tax_recalculation
context:And I ran the test 10 times before and after the changes:
On
main
:After Changes (this branch):
An average increase of 1.799ms per
recalculate
call on orders with 50 Line Items.Checklist
Check out our PR guidelines for more details.
The following are mandatory for all PRs:
The following are not always needed: