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:


Spree::Variant::PricingOptions
Spree::Variant::PricingSelector

And both are controlled by the following setting:


Spree::Config.variant_price_selector_class

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
  Spree::Config.pricing_options_class.from_context(self)
end

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)
  product_or_variant.price_for(current_pricing_options).to_html
end

# 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
        }
      end

      def self.from_context(context)
        new(
          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
        )
      end
    end
  end
end

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

      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]
        end.try!(:money)
      end
  end
end

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

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!

0 Shares:
You May Also Like
Read More

Customize Solidus mailers

Reading Time: 2 minutesSolidus has a set of mailers which notify some actions such as confirmation of an order, notification when a…