Permalink
Browse files

Replaced tuple (label, value) against structure ExtraEntryLine which

contains an extra field data to hold custom data for displaying in
orders and invoices.
  • Loading branch information...
1 parent 44ec15d commit 9f96684a966570cb1569a2d7f8250c17d7d97f1e @jrief committed Feb 28, 2012
View
50 shop/cart/cart_modifiers_base.py
@@ -1,6 +1,27 @@
# -*- coding: utf-8 -*-
+class ExtraEntryLine(object):
+ """
+ This object holds all the data which is added to an item as extra line when
+ the cart is transformed into an order.
+ """
+ def __init__(self, label, value, data=None):
+ """
+ @param label: A descriptive text about this line useful for the administrator.
+ @param value: The decimal should be the amount that should get added to
+ the current subtotal. It can be a negative value.
+ The price difference for this item.
+ @param data: A dictionary created by the modifier to store custom data.
+ TODO: add modifier_classpath: The full qualified class path of the modifier
+ which created this extra entry line. Useful when reprocessing orders,
+ so that we know who is able to interpret the ``data`` field.
+ """
+ self.label = label
+ self.value = value
+ self.data = data
+
+
class BaseCartModifier(object):
"""
Price modifiers are the cart's counterpart to backends.
@@ -72,7 +93,7 @@ def process_cart_item(self, cart_item, state):
"""
field = self.get_extra_cart_item_price_field(cart_item)
if field != None:
- price = field[1]
+ price = field.value
cart_item.current_total = cart_item.current_total + price
cart_item.extra_price_fields.append(field)
return cart_item
@@ -95,7 +116,7 @@ def process_cart(self, cart, state):
"""
field = self.get_extra_cart_price_field(cart)
if field != None:
- price = field[1]
+ price = field.value
cart.current_total = cart.current_total + price
cart.extra_price_fields.append(field)
return cart
@@ -106,41 +127,40 @@ def process_cart(self, cart, state):
def get_extra_cart_item_price_field(self, cart_item):
"""
- Get an extra price field tuple for the current cart_item:
+ Get an extra item line for the current cart_item:
- This allows to modify the price easily, simply return a
- ('Label', Decimal('amount')) from an override. This is expected to be
- a tuple. The decimal should be the amount that should get added to the
- current subtotal. It can be a negative value.
+ This allows to modify the price easily, simply return an object of
+ type ExtraEntryLine or None if no extra line shall be added.
In case your modifier is based on the current price (for example in
order to compute value added tax for this cart item only) your
override can access that price via ``cart_item.current_total``.
A tax modifier would do something like this:
- >>> return ('taxes', Decimal(9))
+ >>> data = { 'foo': 'bar' }
+ >>> return ExtraEntryLine(label='taxes', value=Decimal(9), data=data)
And a rebate modifier would do something along the lines of:
- >>> return ('rebate', Decimal(-9))
+ >>> data = { 'foo': 'bar' }
+ >>> return ExtraEntryLine(label='rebate', value=Decimal(-9), data=data)
More examples can be found in shop.cart.modifiers.*
"""
return None # Does nothing by default
def get_extra_cart_price_field(self, cart):
"""
- Get an extra price field tuple for the current cart:
+ Get an extra line for the current cart:
- This allows to modify the price easily, simply return a
- ('Label', Decimal('amount')) from an override. This is expected to be
- a tuple. The decimal should be the amount that should get added to the
- current subtotal. It can be a negative value.
+ This allows to modify the price easily, simply return an object of
+ type ExtraEntryLine or None if no extra line shall be added.
In case your modifier is based on the current price (for example in
order to compute value added tax for the whole current price) your
override can access that price via ``cart.current_total``. That is the
subtotal, updated with all cart modifiers so far)
- >>> return ('Taxes total', 19.00)
+ >>> data = { 'foo': 'bar' }
+ >>> return ExtraEntryLine(label='Taxes total', Decimal(19.00), data=data)
"""
return None
View
8 shop/cart/modifiers/rebate_modifiers.py
@@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
from decimal import Decimal
-from shop.cart.cart_modifiers_base import BaseCartModifier
+from shop.cart.cart_modifiers_base import BaseCartModifier, ExtraEntryLine
class BulkRebateModifier(BaseCartModifier):
@@ -16,8 +16,8 @@ def get_extra_cart_item_price_field(self, cart_item):
"""
REBATE_PERCENTAGE = Decimal('10')
NUMBER_OF_ITEMS_TO_TRIGGER_REBATE = 5
- result_tuple = None
+ result = None
if cart_item.quantity >= NUMBER_OF_ITEMS_TO_TRIGGER_REBATE:
rebate = (REBATE_PERCENTAGE / 100) * cart_item.line_subtotal
- result_tuple = ('Rebate', -rebate)
- return result_tuple # Returning None is ok
+ result = ExtraEntryLine(label='Rebate', value=-rebate)
+ return result # Returning None is ok
View
8 shop/cart/modifiers/tax_modifiers.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
-from shop.cart.cart_modifiers_base import BaseCartModifier
+from shop.cart.cart_modifiers_base import BaseCartModifier, ExtraEntryLine
class TenPercentGlobalTaxModifier(BaseCartModifier):
@@ -19,8 +19,7 @@ def get_extra_cart_price_field(self, cart):
Add a field on cart.extra_price_fields:
"""
taxes = (self.TAX_PERCENTAGE / 100) * cart.current_total
- result_tuple = ('Taxes total', taxes)
- return result_tuple
+ return ExtraEntryLine(label='Taxes total', value=taxes)
class TenPercentPerItemTaxModifier(BaseCartModifier):
@@ -37,5 +36,4 @@ class TenPercentPerItemTaxModifier(BaseCartModifier):
def get_extra_cart_item_price_field(self, cart_item):
tax_amount = (self.TAX_PERCENTAGE / 100) * cart_item.current_total
- result_tuple = ('Taxes (10%)', tax_amount)
- return result_tuple
+ return ExtraEntryLine(label='Taxes (10%)', value=tax_amount)
View
2 shop/models/defaults/bases.py
@@ -267,7 +267,7 @@ def __init__(self, *args, **kwargs):
# That will hold extra fields to display to the user
# (ex. taxes, discount)
super(BaseCartItem, self).__init__(*args, **kwargs)
- self.extra_price_fields = [] # list of tuples (label, value)
+ self.extra_price_fields = [] # list of ExtraEntryLine's
# These must not be stored, since their components can be changed
# between sessions / logins etc...
self.line_subtotal = Decimal('0.0')
View
14 shop/models/defaults/managers.py
@@ -99,11 +99,12 @@ def create_from_cart(self, cart):
order.save()
# Let's serialize all the extra price arguments in DB
- for label, value in cart.extra_price_fields:
+ for extra_entry in cart.extra_price_fields:
eoi = ExtraOrderPriceField()
eoi.order = order
- eoi.label = str(label)
- eoi.value = value
+ eoi.label = str(extra_entry.label)
+ eoi.value = extra_entry.value
+ eoi.data = extra_entry.data
eoi.save()
# There, now move on to the order items.
@@ -121,12 +122,13 @@ def create_from_cart(self, cart):
order_item.line_subtotal = item.line_subtotal
order_item.save()
# For each order item, we save the extra_price_fields to DB
- for label, value in item.extra_price_fields:
+ for extra_entry in item.extra_price_fields:
eoi = ExtraOrderItemPriceField()
eoi.order_item = order_item
# Force unicode, in case it has àö...
- eoi.label = unicode(label)
- eoi.value = value
+ eoi.label = unicode(extra_entry.label)
+ eoi.value = extra_entry.value
+ eoi.data = extra_entry.data
eoi.save()
processing.send(self.model, order=order, cart=cart)
View
3 shop/models/ordermodel.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from distutils.version import LooseVersion
+from jsonfield.fields import JSONField
from django.conf import settings
from django.db import models
from django.db.models.signals import pre_delete
@@ -59,6 +60,7 @@ class ExtraOrderPriceField(models.Model):
order = models.ForeignKey(Order, verbose_name=_('Order'))
label = models.CharField(max_length=255, verbose_name=_('Label'))
value = CurrencyField(verbose_name=_('Amount'))
+ data = JSONField(null=True, blank=True, verbose_name=_('Serialized extra data'))
# Does this represent shipping costs?
is_shipping = models.BooleanField(default=False, editable=False,
verbose_name=_('Is shipping'))
@@ -77,6 +79,7 @@ class ExtraOrderItemPriceField(models.Model):
order_item = models.ForeignKey(OrderItem, verbose_name=_('Order item'))
label = models.CharField(max_length=255, verbose_name=_('Label'))
value = CurrencyField(verbose_name=_('Amount'))
+ data = JSONField(null=True, blank=True, verbose_name=_('Serialized extra data'))
class Meta(object):
app_label = 'shop'
View
8 shop/templates/shop/cart.html
@@ -35,8 +35,8 @@
{% for extra_price_field in form.instance.extra_price_fields %}
<tr>
<td colspan="2">&nbsp;</td>
- <td>{{ extra_price_field.0 }}</td>
- <td>{{ extra_price_field.1 }}</td>
+ <td>{{ extra_price_field.label }}</td>
+ <td>{{ extra_price_field.value }}</td>
</tr>
{% endfor %}
<tr><td colspan="2">&nbsp;</td><td>{% trans "Line Total" %}:</td><td>{{ form.instance.line_total }}</td></tr>
@@ -49,8 +49,8 @@
{% for extra_price_field in cart.extra_price_fields %}
<tr>
<td colspan="2">&nbsp;</td>
- <td>{{ extra_price_field.0 }}</td>
- <td>{{ extra_price_field.1 }}</td>
+ <td>{{ extra_price_field.label }}</td>
+ <td>{{ extra_price_field.value }}</td>
</tr>
{% endfor %}
<tr><td colspan="2">&nbsp;</td><td><b>{% trans "Cart Total" %}</b></td><td><b>{{cart.total_price}}</b></td></tr>
View
4 shop/tests/cart_modifiers.py
@@ -112,7 +112,7 @@ def test_tax_amount_is_correct(self):
modifier = TenPercentPerItemTaxModifier()
item = self.MockItem()
field = modifier.get_extra_cart_item_price_field(item)
- self.assertTrue(field[1] == Decimal('10'))
+ self.assertTrue(field.value == Decimal('10'))
def test_tax_amount_is_correct_after_modifier(self):
modifier = TenPercentPerItemTaxModifier()
@@ -121,4 +121,4 @@ def test_tax_amount_is_correct_after_modifier(self):
item.extra_price_fields.append(previous_option)
item.current_total = item.current_total + previous_option[1]
field = modifier.get_extra_cart_item_price_field(item)
- self.assertTrue(field[1] == Decimal('11'))
+ self.assertTrue(field.value == Decimal('11'))

0 comments on commit 9f96684

Please sign in to comment.