Skip to content

Instantly share code, notes, and snippets.

@codeinthehole
Created July 18, 2013 12:10
Show Gist options
  • Save codeinthehole/6028798 to your computer and use it in GitHub Desktop.
Save codeinthehole/6028798 to your computer and use it in GitHub Desktop.
Description of the multi-stockrecord problem for Oscar and a few possible solutions

Problem

We need to support multiple stockrecords per product.

Example stories:

  • Customers in the UK use a stockrecord from a UK partner, customers from the US use a stockrecord from a US partner etc. We use IP lookup to determine which stockrecord is appropriate for a customer (this is the Meridian problem).
  • A product is available in several second-hand versions, each with a different price and description (like Alibris from Borders UK if anyone remembers that). The customer can choose which stockrecord/partner to use when adding to basket.
  • A product has several possible partners. We fulfil from one partner until it's stocklevel is zero then switch to the next one dynamically.

Implementation notes

Fundamentally, the price and availability of a product now depend on the request, session and user. The current API for looking up prices can't handle this as prices and availability are looked up as simple attributes:

{{ product.stockrecord.price_incl_tax }}
{{ product.is_available_to_buy }}

These properties won't have access to the request.

Sometimes the appropriate stockrecord for a product will be looked up dynamically (eg Meridian) but sometimes it will be set in advance and will need to be stored within the basket line.

Basket adjustments

I think we're going to need to add a new field to the basket line to track which stockrecord will be used. It will need to be NULLable for backwards compatibility. Then the basket will be able to determine its line prices without needing the request instance to look things up dynamically.

Handling a NULL value for the stockrecord is tricky. We could assume that this indicates that there is a one-to-one relationship between products and stockrecord - and possibly grab that stockrecord and save it. If the stockrecord field is NULL and there are multiple stockrecords per products, we would have to raise an exception as we would have no way of knowing which was the right stock record.

Order adjustments

Everything around the order should work ok as it stores its prices internally.

Product adjustments

Products are the trickiest problem as this is such a big API change. It mainly affects templates though - there aren't many places in python land where a product price is accessed directly.

Possible solutions for templates

Idea 1: template filters

To get prices in templates we could provide a set of template filters:

{% load stockrecord_filters %}

{{ product|price_incl_tax }}
{{ product|availability_code }}

{% if product|is_available_to_buy %} ... {% endif %}

Seems a bit clunky.

Idea 2: load stockrecord via template tag

Use a templatetag to load the appropriate stockrecord into the template context:

{% load stockrecord_tags %}

{% get_stockrecord product as record %}

{{ record.price_incl_tax }}
{{ record.is_available_to_buy }}

This is probably better although some properties (eg is_available_to_buy) don't really belong on the stockrecord. We could return a different object from a StockRecord instance though.

Idea 3: attach data onto the product instance

We could attach properties onto the product instance directly:

{% load stockrecord_tags %}

{% update_product product %}

{{ product.price_incl_tax }}
{{ product.is_available_to_buy }}

We could even do this on batch:

{% load stockrecord_tags %}

{% update_products products %}

{% for product in products %}
    {{ product.price_incl_tax }}
    {{ product.is_available_to_buy }}
{% endfor %}

which might be faster.

Backwards compatibility

All the above options would require a lot of template changes. To mitigate this, we could keep a stockrecord property on the product model that returns the first stockrecord available. This would avoid Oscar projects which have a one-to-one relationship from having to make lots of template changes.

But it might make things confusing going forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment