This page explains how prices and availability are determined in Oscar. In
short, it seems quite complicated at first as there are several parts to it, but what
this buys is flexibility: buckets of it.

Oscar, on the other hand, distinguishes products from stockrecords and provides
a swappable ‘strategy’ component for selecting the appropriate stockrecord,
calculating prices and availability information.

The product model captures the core data about the product (title, description,
images) while a stockrecord represents fulfillment information for one
particular partner (number in stock, base price). A product can have multiple
stockrecords although only one is selected by the strategy to determine pricing and
availability.

By using your own custom strategy class, a wide range of pricing, tax and
availability problems can be easily solved.

Oscar uses a ‘strategy’ object to determine product availability and pricing. A
new strategy instance is assigned to the request by the basket middleware. A
Selector
class determines the appropriate strategy for the
request. By modifying the
Selector
class, it’s possible to return
different strategies for different customers.

Given a product, the strategy class is responsible for:

Selecting a “pricing policy”, an object detailing the prices of the product and whether tax is known.

Selecting an “availability policy”, an object responsible for
availability logic (ie is the product available to buy) and customer
messaging.

Selecting the appropriate stockrecord to use for fulfillment. If a product
can be fulfilled by several fulfilment partners, then each will have their
own stockrecord.

These three entities are wrapped up in a PurchaseInfo object, which is a
simple named tuple. The strategy class provides fetch_for_product and
fetch_for_parent methods which takes a product and returns a PurchaseInfo
instance:

The strategy class is accessed in several places in Oscar’s codebase. In templates, a
purchase_info_for_product template tag is used to load the price and availability
information into the template context:

While this probably seems like quite an involved way of looking up a product’s
price, it gives the developer an immense amount of flexibility. Here’s a few
examples of things you can do with a strategy class:

Transact in multiple currencies. The strategy
class can use the customer’s location to select a stockrecord from a local
distribution partner which will be in the local currency of the customer.

Elegantly handle different tax models. A strategy can return prices including
tax for a UK or European visitor, but without tax for US
visitors where tax is only determined once shipping details are confirmed.

Charge different prices to different customers. A strategy can return a
different pricing policy depending on the user/session.

Use a chain of preferred partners for fulfillment. A site could have many
stockrecords for the same product, each from a different fulfillment partner.
The strategy class could select the partner with the best margin and stock
available. When stock runs out with that partner, the strategy could
seamlessly switch to the next best partner.

These are the kinds of problems that other e-commerce frameworks would struggle
with.

This method is provided to allow purchase info to be determined using a
basket line’s attributes. For instance, “bundle” products often use
basket line attributes to store SKUs of contained products. For such
products, we need to look at the availability of each contained product
to determine overall availability.

This should be used for when the price of a product is known in advance.

It can work for when tax isn’t known (like in the US).

Note that this price class uses the tax-exclusive price for offers, even if
the tax is known. This may not be what you want. Use the
TaxInclusiveFixedPrice class if you want offers to use tax-inclusive
prices.

Like pricing policies, availability policies are simple classes with several
properties and methods. The job of an availability policy is to provide
availability messaging to show to the customer as well as methods to determine
if the product is available to buy.

Pricing policy mixin for use with the Structured base strategy. This
mixin applies a fixed rate tax to the base price from the product’s
stockrecord. The price_incl_tax is quantized to two decimal places.
Rounding behaviour is Decimal’s default

Here’s an example strategy.py module which is used to charge VAT on prices.

# myproject/partner/strategy.pyfromoscar.apps.partnerimportstrategy,pricesclassSelector(object):""" Custom selector to return a UK-specific strategy that charges VAT """defstrategy(self,request=None,user=None,**kwargs):returnUKStrategy()classIncludingVAT(strategy.FixedRateTax):""" Price policy to charge VAT on the base price """# We can simply override the tax rate on the core FixedRateTax. Note# this is a simplification: in reality, you might want to store tax# rates and the date ranges they apply in a database table. Your# pricing policy could simply look up the appropriate rate.rate=D('0.20')classUKStrategy(strategy.UseFirstStockRecord,IncludingVAT,strategy.StockRequired,strategy.Structured):""" Typical UK strategy for physical goods. - There's only one warehouse/partner so we use the first and only stockrecord - Enforce stock level. Don't allow purchases when we don't have stock. - Charge UK VAT on prices. Assume everything is standard-rated. """

Here’s an example strategy.py module which is suitable for use in the US
where taxes can’t be calculated until the shipping address is known. You
normally need to use a 3rd party service to determine taxes - details omitted
here.

fromoscar.apps.partnerimportstrategy,pricesclassSelector(object):""" Custom selector class to returns a US strategy """defstrategy(self,request=None,user=None,**kwargs):returnUSStrategy()classUSStrategy(strategy.UseFirstStockRecord,strategy.DeferredTax,strategy.StockRequired,strategy.Structured):""" Typical US strategy for physical goods. Note we use the ``DeferredTax`` mixin to ensure prices are returned without tax. - Use first stockrecord - Enforce stock level - Taxes aren't known for prices at this stage """