How Pricing Selection works in Solidus

Reading Time: 2 minutes

Solidus is known for its flexibility, but some stores need special rules to chose what price to use. Hence, it might depend on roles, quantity, location, etc. We'll guide you on how Solidus works internally to find the right price and how can be modified at the configuration level. No more monkey-patching!


Solidus pricing: internals

Solidus is very flexible when it comes to deciding what price to use for a certain product/variant. It has a super simple mechanism to delegate everything to two classes:


And both are controlled by the following setting:


Spree::Variant::PricingSelector has hardcoded what pricing option it needs.

The first thing is to have a look at the Spree::Core::ControllerHelpers::Pricing module, that's where the helper to find the right options is located. If you find the code, it looks like this:

def current_pricing_options

That current_pricing_options is used everywhere to find the price, and even for building cache keys, etc. For example:

# display price helper
def display_price(product_or_variant)

# from the views
- cache [I18n.locale, current_pricing_options, @product] do
  = display_price(@product)

What can we do with this flexibility?

Endless possible combinations, some examples would be:

  • Pricing levels
  • Pricing per roles
  • Wholesale prices
  • Employee discounts
  • Sale prices
  • Prices by season
  • Etc

Pricing levels

Let's say you want to have different pricing levels depending on how often your clients buy, or special arrangements from your sales department. Then, all you need to do is the following:

  • Add a new Pricing Level column to the Users and Prices tables
  • Modify in the backend the User and Price forms to include a new column
  • Create a new Pricing Options module to include Pricing Level and its defaults
  • Create a new Pricing Selector module to find prices based on the new Pricing Level

The code might look like this:

module Store
  module Variant
    class PricingOptions < ::Spree::Variant::PricingOptions
      def self.default_price_attributes
            currency: Spree::Config.currency,
            country_iso: Spree::Config.admin_vat_country_iso,
            pricing_Level: 1

      def self.from_context(context)
          currency: context.current_store.try!(:default_currency).presence || Spree::Config[:currency],
          country_iso: context.current_store.try!(:cart_tax_country_iso).presence
          pricing_level: context.spree_current_user.try(:pricing_Level).presence || 1

module Store
  module Variant
    class PriceSelector < ::Spree::Variant::PriceSelector
      def self.pricing_options_class

      def price_for(price_options)
        variant.currently_valid_prices.detect do |price|
          ( price.country_iso == price_options.desired_attributes[:country_iso] || price.country_iso.nil? ) && 
              price.currency == price_options.desired_attributes[:currency] && 
              price.pricing_level == price_options.desired_attributes[:pricing_level]

# Specify what pricing selector to use in spree initializer:
Spree.config do |config|
  config.variant_price_selector_class = 'Store::Variant::PriceSelector'

And that's it! Solidus takes care of the rest.

As you can see, it is very easy to customize how to select what price to use in Solidus. If you still need some help customizing your Solidus, you can contact us and we will be more than happy to help!

Thanks for reading!

Advanced Level
Clearing the air: How to test new features with Rails?
What is Product Management in e-commerce?
What is VTEX platform and why should you migrate your ecommerce to it?
Copy link
Powered by Social Snap