How to create a custom benefit¶
Oscar ships with several offer benefits for building offers. There are three types:
Basket discounts. These lead to a discount off the price of items in your basket.
Shipping discounts.
Post-order actions. These are benefits that don’t affect your order total but trigger some action once the order is placed. For instance, if your site supports loyalty points, you might create an offer that gives 200 points when a certain product is bought.
Oscar also lets you create your own benefits for use in offers.
Custom benefits¶
A custom benefit can be used by creating a benefit class and registering it so it is available to be used.
A benefit class must be a proxy class and have the following methods:
from oscar.apps.offer import models
class MyCustomBenefit(models.Benefit):
class Meta:
proxy = True
@property
def name(self):
return "My Custom Benefit"
@property
def description(self):
"""
Describe what the benefit does.
This is used in the dashboard when selecting benefits for offers.
"""
def apply(self, basket, condition, offer):
"""
Apply the benefit to the passed basket and mark the appropriate
items as consumed.
The condition and offer are passed as these are sometimes required
to implement the correct consumption behaviour.
Should return an instance of
``oscar.apps.offer.models.ApplicationResult``
"""
def apply_deferred(self, basket, order, application):
"""
Perform a 'post-order action' if one is defined for this benefit
Should return a message indicating what has happened. This will be
stored with the order to provide audit of post-order benefits.
"""
As noted in the docstring, the apply
method must return an instance of
oscar.apps.offer.models.ApplicationResult
. There are three subclasses
provided:
oscar.apps.offer.models.BasketDiscount
. This takes an amount as it’s constructor parameter.
oscar.apps.offer.models.ShippingDiscount
. This indicates that the benefit affects the shipping charge.
oscar.apps.offer.models.PostOrderAction
. This indicates that the benefit does nothing to the order total, but does fire an action once the order has been placed. It takes a singledescription
parameter to its constructor which is a message that describes what action will be taken once the order is placed.
Here’s an example of a post-order action benefit:
from oscar.apps.offer import models
class ChangesCustomersName(models.Benefit):
class Meta:
proxy = True
name = description = "Changes customer's name"
def apply(self, basket, condition, offer):
# We need to mark all items from the matched condition as 'consumed'
# so that they are unavailable to be used with other offers.
condition.consume_items(basket, ())
return models.PostOrderAction(
"You will have your name changed to Barry!")
def apply_deferred(self, basket, order, application):
if basket.owner:
basket.owner.first_name = "Barry"
basket.owner.save()
return "Your name has been changed to Barry!"
return "We were unable to change your name as you are not signed in"
Create benefit instance¶
To make this benefit available to be used in offers, do the following:
from oscar.apps.offer.custom import create_benefit
create_benefit(ChangesCustomersName)
Now you should see this benefit in the dashboard when creating/updating an offer.
Deploying custom benefits¶
To avoid manual steps in each of your test/stage/production environments, use Django data migrations to create benefits.