Overview
Calculator Model Diagram
Key relationships:- Calculator computes amounts for various features
- Used by Tax Rates to calculate tax amounts
- Used by Shipping Methods to calculate shipping costs
- Used by Promotion Actions to calculate discounts
- Calculators store preferences (rates, percentages, etc.) for their calculations
Spree::Calculator model and there are several subclasses provided to deal with various types of calculations flat rate, percentage discount, sales tax, VAT, etc. All calculators extend the Spree::Calculator class and must provide the following methods:
calculable object, which are typically one of Spree::ShippingMethod, Spree::TaxRate, or Spree::Promotion::Actions::CreateAdjustment. These three classes use the Spree::CalculatedAdjustments module described below to provide an easy way to calculate adjustments for their objects.
Available Calculators
The following are descriptions of the currently available calculators in Spree. If you would like to add your own, please see the Creating a New Calculator section.Default Tax
For information about this calculator, please read the Taxes guide.Flat Percent Per Item Total
This calculator has one preference:flat_percent and can be set like this:
$31 and the calculator was configured to have a flat percent amount of 10, the discount would be $3.10, because $31 x 10% = $3.10.
Flat Rate
This calculator can be used to provide a flat rate discount. This calculator has two preferences:amount and currency. These can be set like this:
Flexi Rate
This calculator is typically used for promotional discounts when you want a specific discount for the first product, and then subsequent discounts for other products, up to a certain amount. This calculator takes three preferences:first_item: The discounted price of the first items.additional_item: The discounted price of subsequent items.max_items: The maximum number of items this discount applies to.
- up to the
max_items
first_item preference is set to $10, your additional_items preference is set to $5, and your max_items preference is set to 4, the total discount would be $25:
$10for the first item$5for each of the3subsequent items:$5 \* 3 = $15$0for the remaining6items
Per Item
The Per Item calculator (Spree::Calculator::Shipping::PerItem) is a shipping calculator that charges a flat amount for every item in a shipment.
This calculator takes two preferences:
amount: The flat amount charged per item.currency: The currency for this calculator.
amount preference by the total item quantity in the shipment package:
amount of 5 and a package containing 3 items in total, the calculator computes an amount of 15 (5 x 3).
Percent Per Item
The Percent Per Item calculator (Spree::Calculator::PercentOnLineItem) applies a percentage discount to a single line item. It takes two preferences:
percent: The percentage to apply to the line item’s amount.apply_only_on_full_priced_items: When enabled, skips line items that are already on sale.
line item amount x percent / 100, capped at the line item’s amount so a promotion adjustment never pushes the total negative.
For example, a $30 line item at 10% yields a $3 discount ($30 x 10% = $3).
Price Sack
The Price Sack calculator is useful for when you want to provide a discount for an order which is over a certain price. The calculator has four preferences:minimal_amount: The minimum amount for the line items total to trigger the calculator.discount_amount: The amount to discount from the order if the line items total is equal to or greater than theminimal_amount.normal_amount: The amount to discount from the order if the line items total is less than theminimal_amount.currency: The currency for this calculator. Defaults to the store currency
minimal_amount preference of $50, a normal_amount preference of $2, and a discount_amount of $5. An order with a line items total of $60 would result in a discount of $5 for the whole order. An order of $20 would result in a discount of $2.
Creating a New Calculator
To create a new calculator for Spree, you need to do two things. The first is to inherit from theSpree::Calculator class and define description and compute methods on that class:
Spree::ShippingCalculator instead, and define a compute_package method:
config/initializers/spree.rb inside your application config variable defined for brevity:
- Spree 5.2+
- Spree 5.1 and below
config/initializers/spree.rb
app/models/spree/calculator/shipping/my_own_calculator.rb you should call:
- Spree 5.2+
- Spree 5.1 and below
config/initializers/spree.rb
Determining Availability
By default, all shipping method calculators are available at all times. If you wish to make this dependent on something from the order, you can re-define theavailable? method inside your calculator:
app/models/custom_calculator.rb
Calculated Adjustments
If you wish to use Spree’s calculator functionality for your own application, you can include theSpree::CalculatedAdjustments module into a model of your choosing.
app/models/plan.rb
Spree.calculators is a fixed-member struct (SpreeCalculators, defined in spree/core/lib/spree/core/engine.rb) that exposes only the four built-in buckets:
shipping_methodstax_ratespromotion_actions_create_adjustmentspromotion_actions_create_item_adjustments
Plan.calculators internally calls Spree.calculators.send(:plans) (the tableized model name), so both registration and lookup raise NoMethodError until you extend the struct to add a matching plans member. Ruby structs cannot gain members at runtime, so this means redefining the SpreeCalculators struct (or reassigning Spree.calculators to an object that responds to plans) before you register anything onto it.
Once the struct exposes a plans member you can register calculators:
- Spree 5.2+
- Spree 5.1 and below
config/initializers/spree.rb
Spree::CalculatedAdjustments provides a has_one :calculator association (with accepts_nested_attributes_for and a presence validation), delegates compute to that calculator, exposes a with_calculator scope, calculator_type / calculator_type= accessors, and the Plan.calculators registry shown above. To work out what the calculator would compute an amount to be, call compute on an instance:
create_adjustment, update_adjustment, or compute_amount. If you also need to build adjustments, include Spree::AdjustmentSource, which adds create_adjustment(order, adjustable, included = false). That method calls a compute_amount you define on the including model (as Spree::TaxRate and the Spree::Promotion::Actions classes do). There is no update_adjustment method in core.
Related Documentation
- Adjustments — the records calculators compute amounts for.
- Dependencies — swap out calculators via the Dependencies system.

