This article provides context about creating custom shipping calculators in the case that the provided calculators do not meet your store's needs.
Before developing a custom calculator, you should make sure that the calculator you need doesn't already exist in Solidus or one of its extensions.
Solidus comes with a set of default calculators that account for typical shipping scenarios:
If the calculators that come with Solidus are not enough for your needs, you
might want to use an extension like
solidus_active_shipping
that provides additional
API-based rate calculation functionality for common carriers like UPS, USPS, and
FedEx. Alternatively, you could develop your own custom calculator.
A custom calculator should accept a Spree::Stock::Package
(a package
) and
return a cost.
Use the package.order
method to access the current order's information, and
the package.contents
methods to access the current package's contents. As a
developer, you should always deal with the package.contents
. Otherwise, you
may be quoting an entire order when you only want to quote one of many shipments
on an order.
Typically, a calculator uses the following order information:
Spree::Address
used as the order's shipping address.Spree::LineItem
objects associated with the order.Spree::Variant
product information (such as the weight and dimensions)
associated with each line item in the order.For an example of a typical calculator, we recommend reading the source code for Solidus's stock flat rate calculator .
For a more complicated example of what is possible with custom calculators, see
the
solidus_active_shipping
base calculator
. This
calculator collects enough information about an order to send to a carrier and
get a rate quote back.
Spree::ShippingCalculator
classYour custom shipping calculator should inherit from the existing
Spree::ShippingCalculator
class. We recommend following the same directory
structure that Spree models do, so your new calculator would be created at:
/app/models/my_store/calculator/shipping/custom_shipping_calculator.rb
Then, follow the pattern of Spree's built-in calculators and inherit from
Spree::ShippingCalculator
:
module MyStore
class Calculator::Shipping::CustomShippingCalculator < Spree::ShippingCalculator
end
end
Your custom shipping calculator requires at least two methods:
self.description
method that provides a name for the custom calculator.compute_package(package)
that provides the return value for a package
being shipped.For example:
module MyStore
class Calculator::Shipping::CustomShippingCalculator < Spree::ShippingCalculator
def self.description
"Custom Shipping Calculator"
end
def compute_package(package)
12.00
end
end
end
Once you have created the logic for the new shipping calculator, you need to register it so that administrators can create new shipping methods that use the custom calculator.
For example, you can register it in your /config/initializers/spree.rb
initializer:
Rails.application.config.spree.calculators.shipping_methods << MyStore::Calculator::Shipping::CustomShippingCalculator
By default, shipping calculators are always available to be used by shipping
methods. This is because the available?
method on the base
Spree::Calculator
class
returns true
by default.
You may want to make the calculator availability change depending on some aspect
of the current order. To do this, you can override the available?
method in
your custom calculator:
module MyStore
class Calculator::Shipping::CustomShippingCalculator < Spree::ShippingCalculator
...
def available?(order)
order.currency == "USD"
end
end
end
For more information about availability and filtering shipping methods, see the Shipping method filters article.
In addition to providing relevant information about shipping addresses and product variants, you can use information about the product itself to inform a calculator's results. A product's tax category or shipping category could be meaningful information for shipping calculations. By default, each package contains only items in the same shipping category.
For example, you might want your calculator to handle your product with a shipping category of "Oversized" differently than it would a product with the "Default" shipping category.
For example, you might want your calculator to handle products with different shipping categories in specific ways: an product with the "Oversized" category should not be treated like a product with the "Default" category.
Solidus is an open source platform supported by the community. We encourage everyone using Solidus to contribute back to the documentation and the code.
If you’re interested in contributing to the docs, get started with the contributing guidelines. If you see something that needs fixing and can’t do it yourself, please send us an email.