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

Allow configuring VAT Price Generator class #3451

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/app/models/spree/variant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def create_stock_items
end

def build_vat_prices
VatPriceGenerator.new(self).run
Spree::Config.variant_vat_prices_generator_class.new(self).run
end

def set_position
Expand Down
8 changes: 8 additions & 0 deletions core/lib/spree/app_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,14 @@ def default_pricing_options

class_name_attribute :variant_search_class, default: 'Spree::Core::Search::Variant'

# Allows implementing custom vat prices generation
# @!attribute [rw] variant_vat_prices_generator_class
# @see Spree::Variant::VatPriceGenerator
# @return [Class] an object that conforms to the API of
# the standard variant vat prices generator class
# Spree::Variant::VatPriceGenerator.
class_name_attribute :variant_vat_prices_generator_class, default: 'Spree::Variant::VatPriceGenerator'

# promotion_chooser_class allows extensions to provide their own PromotionChooser
class_name_attribute :promotion_chooser_class, default: 'Spree::PromotionChooser'

Expand Down
73 changes: 65 additions & 8 deletions guides/source/developers/taxation/value-added-tax.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ consumer_price / (1 + tax_rate) = expected_revenue
consumer_price - expected_revenue = vat
```

Solidus's [Spree::Calculator::DefaultTax][default-tax-calculator] handles
sales tax and VAT. If a tax rate is VAT and should be included in the price, it
Solidus's [Spree::Calculator::DefaultTax][default-tax-calculator] handles
sales tax and VAT. If a tax rate is VAT and should be included in the price, it
calculates all of the line items that share that tax rate on the order:

```
Expand All @@ -40,7 +40,7 @@ end
### VAT amounts are stored in `Spree::Adjustment`s

Note that while VAT does not adjust an order's total, Solidus still creates
`Spree::Adjustment` objects to store tax amount. These objects have an
`Spree::Adjustment` objects to store tax amount. These objects have an
`included` value of `true` so that the tax is not added to the price.

## Example order with multiple VAT rates
Expand All @@ -52,7 +52,7 @@ Our United Kingdom-based company is required to follow these tax regulations:

- Items of clothing should be taxed at a 5% rate.
- Consumer electronics should be taxed at a 10% rate.
- We are required to display the VAT paid to the customer.
- We are required to display the VAT paid to the customer.

If a customer orders a single clothing item:

Expand Down Expand Up @@ -91,17 +91,74 @@ If a customer adds a consumer electronics product to the order:
- The tax calculator calculates the VAT for the clothing items: `37.98 - (37.98
/ (1 + 0.05)) = 1.81`.
- The tax calculator calculates the VAT for the consumer electronics item:
`16.99 - (16.99 / (1 + 0.10)) = 1.54`.
`16.99 - (16.99 / (1 + 0.10)) = 1.54`.

We can now show the display the final included VAT in the price when the
UK-based customer arrives at the checkout summary page:
UK-based customer arrives at the checkout summary page:

```
£17.99 – 1 x T-shirt
£19.99 – 1 x T-shirt
£16.99 – 1 x Power adapter
£1.81 – Clothing tax (5%)
£1.54 – Consumer electronics tax (10%)

£54.97 – TOTAL
```

## Customize your VAT generation

If the provided model in core does not fit your business needs, you
can easily customize the VAT generation logic by defining your own
VAT generator class. Let's walk into this with an example:

Let's suppose you need to show the same gross price across different
countries, no matter what the VAT is but still keeping the VAT tax
to be visible in checkout.

You need to customize the logic used by Solidus to generate the price
in countries that use VAT (with a TaxRate that has `included_in_price`
set to `true`).

### Create your own VAT Prices Generator class

You can create your own class that implements this logic. It has to be
compliant with the interface of the class provided by default in Solidus
core, which is [Spree::Variant::VatPriceGenerator][Spree::Variant::VatPriceGenerator].

We suggest to inherit from that class and override only the method that
you need to be different, for example:

```ruby
# app/spree/variant/custom_vat_price_generator.rb

# frozen_string_literal: true

module Spree
class Variant < Spree::Base
class CustomVatPriceGenerator < VatPriceGenerator
def run
# Early return if there is no VAT rates in the current store.
return if !variant.tax_category || variant_vat_rates.empty?

country_isos_requiring_price.each do |country_iso|
# Don't re-create the default price
next if variant.default_price && variant.default_price.country_iso == country_iso

foreign_price = find_or_initialize_price_by(country_iso, variant.default_price.currency)
foreign_price.amount = variant.default_price.amount
end
end
end
end
end
```

Now that you have created your custom class, you can easily ask Solidus to
use it, by setting the following configuration in an initializer:

```ruby
Spree::Config.variant_vat_prices_generator_class = 'Spree::Variant::CustomVatPriceGenerator'
```

[Spree::Variant::VatPriceGenerator]: https://github.com/solidusio/solidus/blob/master/core/app/models/spree/variant/vat_price_generator.rb