Fixes flake8 errors

This commit is contained in:
Christopher Neugebauer 2016-01-22 17:02:07 +11:00
parent c2400c4695
commit 224878a10c
14 changed files with 125 additions and 152 deletions

View file

@ -6,7 +6,6 @@ import nested_admin
from registrasion import models as rego from registrasion import models as rego
# Inventory admin # Inventory admin
class ProductInline(admin.TabularInline): class ProductInline(admin.TabularInline):

View file

@ -1,9 +1,8 @@
import datetime import datetime
import itertools
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Avg, Min, Max, Sum from django.db.models import Max, Sum
from django.utils import timezone from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
@ -33,7 +32,6 @@ class CartController(object):
existing.save() existing.save()
return CartController(existing) return CartController(existing)
def extend_reservation(self): def extend_reservation(self):
''' Updates the cart's time last updated value, which is used to ''' Updates the cart's time last updated value, which is used to
determine whether the cart has reserved the items and discounts it determine whether the cart has reserved the items and discounts it
@ -56,7 +54,6 @@ class CartController(object):
self.cart.time_last_updated = timezone.now() self.cart.time_last_updated = timezone.now()
self.cart.reservation_duration = max(reservations) self.cart.reservation_duration = max(reservations)
def add_to_cart(self, product, quantity): def add_to_cart(self, product, quantity):
''' Adds _quantity_ of the given _product_ to the cart. Raises ''' Adds _quantity_ of the given _product_ to the cart. Raises
ValidationError if constraints are violated.''' ValidationError if constraints are violated.'''
@ -91,7 +88,6 @@ class CartController(object):
self.cart.revision += 1 self.cart.revision += 1
self.cart.save() self.cart.save()
def apply_voucher(self, voucher): def apply_voucher(self, voucher):
''' Applies the given voucher to this cart. ''' ''' Applies the given voucher to this cart. '''
@ -110,7 +106,6 @@ class CartController(object):
self.cart.revision += 1 self.cart.revision += 1
self.cart.save() self.cart.save()
def validate_cart(self): def validate_cart(self):
''' Determines whether the status of the current cart is valid; ''' Determines whether the status of the current cart is valid;
this is normally called before generating or paying an invoice ''' this is normally called before generating or paying an invoice '''
@ -121,13 +116,15 @@ class CartController(object):
items = rego.ProductItem.objects.filter(cart=self.cart) items = rego.ProductItem.objects.filter(cart=self.cart)
for item in items: for item in items:
# per-user limits are tested at add time, and are unliklely to change # NOTE: per-user limits are tested at add time
# and are unliklely to change
prod = ProductController(item.product) prod = ProductController(item.product)
# If the cart is not reserved, we need to see if we can re-reserve # If the cart is not reserved, we need to see if we can re-reserve
quantity = 0 if is_reserved else item.quantity quantity = 0 if is_reserved else item.quantity
if not prod.can_add_with_enabling_conditions(self.cart.user, quantity): if not prod.can_add_with_enabling_conditions(
self.cart.user, quantity):
raise ValidationError("Products are no longer available") raise ValidationError("Products are no longer available")
# Validate the discounts # Validate the discounts
@ -139,7 +136,8 @@ class CartController(object):
if discount in seen_discounts: if discount in seen_discounts:
continue continue
seen_discounts.add(discount) seen_discounts.add(discount)
real_discount = rego.DiscountBase.objects.get_subclass(pk=discount.pk) real_discount = rego.DiscountBase.objects.get_subclass(
pk=discount.pk)
cond = ConditionController.for_condition(real_discount) cond = ConditionController.for_condition(real_discount)
quantity = 0 if is_reserved else discount_item.quantity quantity = 0 if is_reserved else discount_item.quantity
@ -147,8 +145,6 @@ class CartController(object):
if not cond.is_met(self.cart.user, quantity): if not cond.is_met(self.cart.user, quantity):
raise ValidationError("Discounts are no longer available") raise ValidationError("Discounts are no longer available")
def recalculate_discounts(self): def recalculate_discounts(self):
''' Calculates all of the discounts available for this product. ''' Calculates all of the discounts available for this product.
NB should be transactional, and it's terribly inefficient. NB should be transactional, and it's terribly inefficient.
@ -160,11 +156,10 @@ class CartController(object):
for item in self.cart.productitem_set.all(): for item in self.cart.productitem_set.all():
self._add_discount(item.product, item.quantity) self._add_discount(item.product, item.quantity)
def _add_discount(self, product, quantity): def _add_discount(self, product, quantity):
''' Calculates the best available discounts for this product. ''' Calculates the best available discounts for this product.
NB this will be super-inefficient in aggregate because discounts will be NB this will be super-inefficient in aggregate because discounts will
re-tested for each product. We should work on that.''' be re-tested for each product. We should work on that.'''
prod = ProductController(product) prod = ProductController(product)
discounts = prod.available_discounts(self.cart.user) discounts = prod.available_discounts(self.cart.user)

View file

@ -1,4 +1,4 @@
from django.db.models import F, Q from django.db.models import Q
from django.db.models import Sum from django.db.models import Sum
from django.utils import timezone from django.utils import timezone
@ -15,15 +15,15 @@ class ConditionController(object):
@staticmethod @staticmethod
def for_condition(condition): def for_condition(condition):
CONTROLLERS = { CONTROLLERS = {
rego.CategoryEnablingCondition : CategoryConditionController, rego.CategoryEnablingCondition: CategoryConditionController,
rego.IncludedProductDiscount : ProductConditionController, rego.IncludedProductDiscount: ProductConditionController,
rego.ProductEnablingCondition : ProductConditionController, rego.ProductEnablingCondition: ProductConditionController,
rego.TimeOrStockLimitDiscount : rego.TimeOrStockLimitDiscount:
TimeOrStockLimitConditionController, TimeOrStockLimitConditionController,
rego.TimeOrStockLimitEnablingCondition : rego.TimeOrStockLimitEnablingCondition:
TimeOrStockLimitConditionController, TimeOrStockLimitConditionController,
rego.VoucherDiscount : VoucherConditionController, rego.VoucherDiscount: VoucherConditionController,
rego.VoucherEnablingCondition : VoucherConditionController, rego.VoucherEnablingCondition: VoucherConditionController,
} }
try: try:
@ -31,7 +31,6 @@ class ConditionController(object):
except KeyError: except KeyError:
return ConditionController() return ConditionController()
def is_met(self, user, quantity): def is_met(self, user, quantity):
return True return True
@ -48,7 +47,8 @@ class CategoryConditionController(ConditionController):
carts = rego.Cart.objects.filter(user=user) carts = rego.Cart.objects.filter(user=user)
enabling_products = rego.Product.objects.filter( enabling_products = rego.Product.objects.filter(
category=self.condition.enabling_category) category=self.condition.enabling_category)
products = rego.ProductItem.objects.filter(cart=carts, products = rego.ProductItem.objects.filter(
cart=carts,
product=enabling_products) product=enabling_products)
return len(products) > 0 return len(products) > 0
@ -65,7 +65,8 @@ class ProductConditionController(ConditionController):
condition in one of their carts ''' condition in one of their carts '''
carts = rego.Cart.objects.filter(user=user) carts = rego.Cart.objects.filter(user=user)
products = rego.ProductItem.objects.filter(cart=carts, products = rego.ProductItem.objects.filter(
cart=carts,
product=self.condition.enabling_products.all()) product=self.condition.enabling_products.all())
return len(products) > 0 return len(products) > 0
@ -77,7 +78,6 @@ class TimeOrStockLimitConditionController(ConditionController):
def __init__(self, ceiling): def __init__(self, ceiling):
self.ceiling = ceiling self.ceiling = ceiling
def is_met(self, user, quantity): def is_met(self, user, quantity):
''' returns True if adding _quantity_ of _product_ will not vioilate ''' returns True if adding _quantity_ of _product_ will not vioilate
this ceiling. ''' this ceiling. '''
@ -93,7 +93,6 @@ class TimeOrStockLimitConditionController(ConditionController):
# All limits have been met # All limits have been met
return True return True
def test_date_range(self): def test_date_range(self):
now = timezone.now() now = timezone.now()
@ -107,7 +106,6 @@ class TimeOrStockLimitConditionController(ConditionController):
return True return True
def _products(self): def _products(self):
''' Abstracts away the product list, becuase enabling conditions ''' Abstracts away the product list, becuase enabling conditions
list products differently to discounts. ''' list products differently to discounts. '''
@ -125,7 +123,6 @@ class TimeOrStockLimitConditionController(ConditionController):
Q(category=categories.all()) Q(category=categories.all())
) )
def test_limits(self, quantity): def test_limits(self, quantity):
if self.ceiling.limit is None: if self.ceiling.limit is None:
return True return True
@ -155,6 +152,7 @@ class VoucherConditionController(ConditionController):
def is_met(self, user, quantity): def is_met(self, user, quantity):
''' returns True if the user has the given voucher attached. ''' ''' returns True if the user has the given voucher attached. '''
carts = rego.Cart.objects.filter(user=user, carts = rego.Cart.objects.filter(
user=user,
vouchers=self.condition.voucher) vouchers=self.condition.voucher)
return len(carts) > 0 return len(carts) > 0

View file

@ -1,11 +1,12 @@
from decimal import Decimal from decimal import Decimal
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Avg, Min, Max, Sum from django.db.models import Sum
from registrasion import models as rego from registrasion import models as rego
from cart import CartController from cart import CartController
class InvoiceController(object): class InvoiceController(object):
def __init__(self, invoice): def __init__(self, invoice):
@ -22,12 +23,11 @@ class InvoiceController(object):
cart=cart, cart_revision=cart.revision) cart=cart, cart_revision=cart.revision)
except ObjectDoesNotExist: except ObjectDoesNotExist:
cart_controller = CartController(cart) cart_controller = CartController(cart)
cart_controller.validate_cart() # Raises ValidationError on fail. cart_controller.validate_cart() # Raises ValidationError on fail.
invoice = cls._generate(cart) invoice = cls._generate(cart)
return InvoiceController(invoice) return InvoiceController(invoice)
@classmethod @classmethod
def resolve_discount_value(cls, item): def resolve_discount_value(cls, item):
try: try:
@ -46,7 +46,6 @@ class InvoiceController(object):
value = condition.price value = condition.price
return value return value
@classmethod @classmethod
def _generate(cls, cart): def _generate(cls, cart):
''' Generates an invoice for the given cart. ''' ''' Generates an invoice for the given cart. '''
@ -89,7 +88,6 @@ class InvoiceController(object):
return invoice return invoice
def is_valid(self): def is_valid(self):
''' Returns true if the attached invoice is not void and it represents ''' Returns true if the attached invoice is not void and it represents
a valid cart. ''' a valid cart. '''
@ -100,12 +98,10 @@ class InvoiceController(object):
return False return False
return True return True
def void(self): def void(self):
''' Voids the invoice. ''' ''' Voids the invoice. '''
self.invoice.void = True self.invoice.void = True
def pay(self, reference, amount): def pay(self, reference, amount):
''' Pays the invoice by the given amount. If the payment ''' Pays the invoice by the given amount. If the payment
equals the total on the invoice, finalise the invoice. equals the total on the invoice, finalise the invoice.
@ -113,7 +109,7 @@ class InvoiceController(object):
''' '''
if self.invoice.cart is not None: if self.invoice.cart is not None:
cart = CartController(self.invoice.cart) cart = CartController(self.invoice.cart)
cart.validate_cart() # Raises ValidationError if invalid cart.validate_cart() # Raises ValidationError if invalid
''' Adds a payment ''' ''' Adds a payment '''
payment = rego.Payment.objects.create( payment = rego.Payment.objects.create(
@ -127,7 +123,7 @@ class InvoiceController(object):
agg = payments.aggregate(Sum("amount")) agg = payments.aggregate(Sum("amount"))
total = agg["amount__sum"] total = agg["amount__sum"]
if total==self.invoice.value: if total == self.invoice.value:
self.invoice.paid = True self.invoice.paid = True
cart = self.invoice.cart cart = self.invoice.cart

View file

@ -2,12 +2,17 @@ import itertools
from collections import namedtuple from collections import namedtuple
from django.db.models import F, Q from django.db.models import Q
from registrasion import models as rego from registrasion import models as rego
from conditions import ConditionController from conditions import ConditionController
DiscountEnabler = namedtuple("DiscountEnabler", ("discount", "condition", "value")) DiscountEnabler = namedtuple(
"DiscountEnabler", (
"discount",
"condition",
"value"))
class ProductController(object): class ProductController(object):
@ -19,7 +24,9 @@ class ProductController(object):
this Product without exceeding _limit_per_user_.''' this Product without exceeding _limit_per_user_.'''
carts = rego.Cart.objects.filter(user=user) carts = rego.Cart.objects.filter(user=user)
items = rego.ProductItem.objects.filter(product=self.product, cart=carts) items = rego.ProductItem.objects.filter(
product=self.product,
cart=carts)
count = 0 count = 0
for item in items: for item in items:
@ -62,7 +69,6 @@ class ProductController(object):
return True return True
def get_enabler(self, condition): def get_enabler(self, condition):
if condition.percentage is not None: if condition.percentage is not None:
value = condition.percentage * self.product.price value = condition.percentage * self.product.price
@ -91,7 +97,8 @@ class ProductController(object):
discounts = [] discounts = []
for discount in potential_discounts: for discount in potential_discounts:
real_discount = rego.DiscountBase.objects.get_subclass(pk=discount.discount.pk) real_discount = rego.DiscountBase.objects.get_subclass(
pk=discount.discount.pk)
cond = ConditionController.for_condition(real_discount) cond = ConditionController.for_condition(real_discount)
if cond.is_met(user, 0): if cond.is_met(user, 0):
discounts.append(discount) discounts.append(discount)

View file

@ -2,7 +2,6 @@ from __future__ import unicode_literals
import datetime import datetime
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
@ -13,10 +12,6 @@ from django.utils.translation import ugettext_lazy as _
from model_utils.managers import InheritanceManager from model_utils.managers import InheritanceManager
from symposion.markdown_parser import parse
from symposion.proposals.models import ProposalBase
# User models # User models
@python_2_unicode_compatible @python_2_unicode_compatible
@ -63,9 +58,11 @@ class Category(models.Model):
] ]
name = models.CharField(max_length=65, verbose_name=_("Name")) name = models.CharField(max_length=65, verbose_name=_("Name"))
description = models.CharField(max_length=255, verbose_name=_("Description")) description = models.CharField(max_length=255,
verbose_name=_("Description"))
order = models.PositiveIntegerField(verbose_name=("Display order")) order = models.PositiveIntegerField(verbose_name=("Display order"))
render_type = models.IntegerField(choices=CATEGORY_RENDER_TYPES, verbose_name=_("Render type")) render_type = models.IntegerField(choices=CATEGORY_RENDER_TYPES,
verbose_name=_("Render type"))
@python_2_unicode_compatible @python_2_unicode_compatible
@ -76,10 +73,15 @@ class Product(models.Model):
return self.name return self.name
name = models.CharField(max_length=65, verbose_name=_("Name")) name = models.CharField(max_length=65, verbose_name=_("Name"))
description = models.CharField(max_length=255, verbose_name=_("Description")) description = models.CharField(max_length=255,
verbose_name=_("Description"))
category = models.ForeignKey(Category, verbose_name=_("Product category")) category = models.ForeignKey(Category, verbose_name=_("Product category"))
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name=_("Price")) price = models.DecimalField(max_digits=8,
limit_per_user = models.PositiveIntegerField(blank=True, verbose_name=_("Limit per user")) decimal_places=2,
verbose_name=_("Price"))
limit_per_user = models.PositiveIntegerField(
blank=True,
verbose_name=_("Limit per user"))
reservation_duration = models.DurationField( reservation_duration = models.DurationField(
default=datetime.timedelta(hours=1), default=datetime.timedelta(hours=1),
verbose_name=_("Reservation duration")) verbose_name=_("Reservation duration"))
@ -98,7 +100,9 @@ class Voucher(models.Model):
return "Voucher for %s" % self.recipient return "Voucher for %s" % self.recipient
recipient = models.CharField(max_length=64, verbose_name=_("Recipient")) recipient = models.CharField(max_length=64, verbose_name=_("Recipient"))
code = models.CharField(max_length=16, unique=True, verbose_name=_("Voucher code")) code = models.CharField(max_length=16,
unique=True,
verbose_name=_("Voucher code"))
limit = models.PositiveIntegerField(verbose_name=_("Voucher use limit")) limit = models.PositiveIntegerField(verbose_name=_("Voucher use limit"))
@ -107,8 +111,8 @@ class Voucher(models.Model):
@python_2_unicode_compatible @python_2_unicode_compatible
class DiscountBase(models.Model): class DiscountBase(models.Model):
''' Base class for discounts. Each subclass has controller code that ''' Base class for discounts. Each subclass has controller code that
determines whether or not the given discount is available to be added to the determines whether or not the given discount is available to be added to
current cart. ''' the current cart. '''
objects = InheritanceManager() objects = InheritanceManager()
@ -116,7 +120,7 @@ class DiscountBase(models.Model):
return "Discount: " + self.description return "Discount: " + self.description
description = models.CharField(max_length=255, description = models.CharField(max_length=255,
verbose_name=_("Description")) verbose_name=_("Description"))
@python_2_unicode_compatible @python_2_unicode_compatible
@ -156,7 +160,10 @@ class DiscountForCategory(models.Model):
discount = models.ForeignKey(DiscountBase, on_delete=models.CASCADE) discount = models.ForeignKey(DiscountBase, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE)
percentage = models.DecimalField(max_digits=4, decimal_places=1, blank=True) percentage = models.DecimalField(
max_digits=4,
decimal_places=1,
blank=True)
quantity = models.PositiveIntegerField() quantity = models.PositiveIntegerField()
@ -176,7 +183,9 @@ class VoucherDiscount(DiscountBase):
''' Discounts that are enabled when a voucher code is in the current ''' Discounts that are enabled when a voucher code is in the current
cart. ''' cart. '''
voucher = models.OneToOneField(Voucher, on_delete=models.CASCADE, voucher = models.OneToOneField(
Voucher,
on_delete=models.CASCADE,
verbose_name=_("Voucher")) verbose_name=_("Voucher"))
@ -187,14 +196,15 @@ class IncludedProductDiscount(DiscountBase):
class Meta: class Meta:
verbose_name = _("Product inclusion") verbose_name = _("Product inclusion")
enabling_products = models.ManyToManyField(Product, enabling_products = models.ManyToManyField(
Product,
verbose_name=_("Including product")) verbose_name=_("Including product"))
class RoleDiscount(object): class RoleDiscount(object):
''' Discounts that are enabled because the active user has a specific ''' Discounts that are enabled because the active user has a specific
role. This is for e.g. volunteers who can get a discount ticket. ''' role. This is for e.g. volunteers who can get a discount ticket. '''
## TODO: implement RoleDiscount # TODO: implement RoleDiscount
pass pass
@ -253,16 +263,16 @@ class VoucherEnablingCondition(EnablingConditionBase):
enabling sponsor tickets. ''' enabling sponsor tickets. '''
def __str__(self): def __str__(self):
return "Enabled by voucher: %s" % voucher return "Enabled by voucher: %s" % self.voucher
voucher = models.OneToOneField(Voucher) voucher = models.OneToOneField(Voucher)
#@python_2_unicode_compatible # @python_2_unicode_compatible
class RoleEnablingCondition(object): class RoleEnablingCondition(object):
''' The condition is met because the active user has a particular Role. ''' The condition is met because the active user has a particular Role.
This is for e.g. enabling Team tickets. ''' This is for e.g. enabling Team tickets. '''
## TODO: implement RoleEnablingCondition # TODO: implement RoleEnablingCondition
pass pass
@ -289,8 +299,9 @@ class Cart(models.Model):
''' Gets all carts that are 'reserved' ''' ''' Gets all carts that are 'reserved' '''
return Cart.objects.filter( return Cart.objects.filter(
(Q(active=True) & (Q(active=True) &
Q(time_last_updated__gt=timezone.now()-F('reservation_duration') Q(time_last_updated__gt=(
)) | timezone.now()-F('reservation_duration')
))) |
Q(active=False) Q(active=False)
) )

View file

@ -1,5 +1,6 @@
from django.utils import timezone from django.utils import timezone
class SetTimeMixin(object): class SetTimeMixin(object):
''' Patches timezone.now() for the duration of a test case. Allows us to ''' Patches timezone.now() for the duration of a test case. Allows us to
test time-based conditions (ceilings etc) relatively easily. ''' test time-based conditions (ceilings etc) relatively easily. '''

View file

@ -5,7 +5,6 @@ from decimal import Decimal
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
@ -14,6 +13,7 @@ from patch_datetime import SetTimeMixin
UTC = pytz.timezone('UTC') UTC = pytz.timezone('UTC')
class RegistrationCartTestCase(SetTimeMixin, TestCase): class RegistrationCartTestCase(SetTimeMixin, TestCase):
def setUp(self): def setUp(self):
@ -21,11 +21,15 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
@classmethod @classmethod
def setUpTestData(cls): def setUpTestData(cls):
cls.USER_1 = User.objects.create_user(username='testuser', cls.USER_1 = User.objects.create_user(
email='test@example.com', password='top_secret') username='testuser',
email='test@example.com',
password='top_secret')
cls.USER_2 = User.objects.create_user(username='testuser2', cls.USER_2 = User.objects.create_user(
email='test2@example.com', password='top_secret') username='testuser2',
email='test2@example.com',
password='top_secret')
cls.CAT_1 = rego.Category.objects.create( cls.CAT_1 = rego.Category.objects.create(
name="Category 1", name="Category 1",
@ -47,8 +51,8 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
cls.PROD_1 = rego.Product.objects.create( cls.PROD_1 = rego.Product.objects.create(
name="Product 1", name="Product 1",
description= "This is a test product. It costs $10. " \ description="This is a test product. It costs $10. "
"A user may have 10 of them.", "A user may have 10 of them.",
category=cls.CAT_1, category=cls.CAT_1,
price=Decimal("10.00"), price=Decimal("10.00"),
reservation_duration=cls.RESERVATION, reservation_duration=cls.RESERVATION,
@ -59,8 +63,8 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
cls.PROD_2 = rego.Product.objects.create( cls.PROD_2 = rego.Product.objects.create(
name="Product 2", name="Product 2",
description= "This is a test product. It costs $10. " \ description="This is a test product. It costs $10. "
"A user may have 10 of them.", "A user may have 10 of them.",
category=cls.CAT_1, category=cls.CAT_1,
price=Decimal("10.00"), price=Decimal("10.00"),
limit_per_user=10, limit_per_user=10,
@ -70,8 +74,8 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
cls.PROD_3 = rego.Product.objects.create( cls.PROD_3 = rego.Product.objects.create(
name="Product 3", name="Product 3",
description= "This is a test product. It costs $10. " \ description="This is a test product. It costs $10. "
"A user may have 10 of them.", "A user may have 10 of them.",
category=cls.CAT_2, category=cls.CAT_2,
price=Decimal("10.00"), price=Decimal("10.00"),
limit_per_user=10, limit_per_user=10,
@ -79,7 +83,6 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
) )
cls.PROD_2.save() cls.PROD_2.save()
@classmethod @classmethod
def make_ceiling(cls, name, limit=None, start_time=None, end_time=None): def make_ceiling(cls, name, limit=None, start_time=None, end_time=None):
limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create( limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create(
@ -93,9 +96,9 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
limit_ceiling.products.add(cls.PROD_1, cls.PROD_2) limit_ceiling.products.add(cls.PROD_1, cls.PROD_2)
limit_ceiling.save() limit_ceiling.save()
@classmethod @classmethod
def make_category_ceiling(cls, name, limit=None, start_time=None, end_time=None): def make_category_ceiling(
cls, name, limit=None, start_time=None, end_time=None):
limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create( limit_ceiling = rego.TimeOrStockLimitEnablingCondition.objects.create(
description=name, description=name,
mandatory=True, mandatory=True,
@ -107,9 +110,9 @@ class RegistrationCartTestCase(SetTimeMixin, TestCase):
limit_ceiling.categories.add(cls.CAT_1) limit_ceiling.categories.add(cls.CAT_1)
limit_ceiling.save() limit_ceiling.save()
@classmethod @classmethod
def make_discount_ceiling(cls, name, limit=None, start_time=None, end_time=None): def make_discount_ceiling(
cls, name, limit=None, start_time=None, end_time=None):
limit_ceiling = rego.TimeOrStockLimitDiscount.objects.create( limit_ceiling = rego.TimeOrStockLimitDiscount.objects.create(
description=name, description=name,
start_time=start_time, start_time=start_time,
@ -141,7 +144,6 @@ class BasicCartTests(RegistrationCartTestCase):
current_cart2 = CartController.for_user(self.USER_1) current_cart2 = CartController.for_user(self.USER_1)
self.assertEqual(current_cart.cart, current_cart2.cart) self.assertEqual(current_cart.cart, current_cart2.cart)
def test_add_to_cart_collapses_product_items(self): def test_add_to_cart_collapses_product_items(self):
current_cart = CartController.for_user(self.USER_1) current_cart = CartController.for_user(self.USER_1)
@ -149,14 +151,14 @@ class BasicCartTests(RegistrationCartTestCase):
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
## Count of products for a given user should be collapsed. # Count of products for a given user should be collapsed.
items = rego.ProductItem.objects.filter(cart=current_cart.cart, items = rego.ProductItem.objects.filter(
cart=current_cart.cart,
product=self.PROD_1) product=self.PROD_1)
self.assertEqual(1, len(items)) self.assertEqual(1, len(items))
item = items[0] item = items[0]
self.assertEquals(2, item.quantity) self.assertEquals(2, item.quantity)
def test_add_to_cart_per_user_limit(self): def test_add_to_cart_per_user_limit(self):
current_cart = CartController.for_user(self.USER_1) current_cart = CartController.for_user(self.USER_1)

View file

@ -1,19 +1,15 @@
import datetime import datetime
import pytz import pytz
from decimal import Decimal
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
from test_cart import RegistrationCartTestCase from test_cart import RegistrationCartTestCase
UTC = pytz.timezone('UTC') UTC = pytz.timezone('UTC')
class CeilingsTestCases(RegistrationCartTestCase): class CeilingsTestCases(RegistrationCartTestCase):
def test_add_to_cart_ceiling_limit(self): def test_add_to_cart_ceiling_limit(self):
@ -44,12 +40,11 @@ class CeilingsTestCases(RegistrationCartTestCase):
# User should be able to add 5 of PROD_2 to the current cart # User should be able to add 5 of PROD_2 to the current cart
current_cart.add_to_cart(self.PROD_2, 4) current_cart.add_to_cart(self.PROD_2, 4)
def test_add_to_cart_ceiling_date_range(self): def test_add_to_cart_ceiling_date_range(self):
self.make_ceiling("date range ceiling", self.make_ceiling(
"date range ceiling",
start_time=datetime.datetime(2015, 01, 01, tzinfo=UTC), start_time=datetime.datetime(2015, 01, 01, tzinfo=UTC),
end_time=datetime.datetime(2015, 02, 01, tzinfo=UTC) end_time=datetime.datetime(2015, 02, 01, tzinfo=UTC))
)
current_cart = CartController.for_user(self.USER_1) current_cart = CartController.for_user(self.USER_1)
@ -74,7 +69,6 @@ class CeilingsTestCases(RegistrationCartTestCase):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_add_to_cart_ceiling_limit_reserved_carts(self): def test_add_to_cart_ceiling_limit_reserved_carts(self):
self.make_ceiling("Limit ceiling", limit=1) self.make_ceiling("Limit ceiling", limit=1)
@ -106,7 +100,6 @@ class CeilingsTestCases(RegistrationCartTestCase):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
first_cart.add_to_cart(self.PROD_1, 1) first_cart.add_to_cart(self.PROD_1, 1)
def test_validate_cart_fails_product_ceilings(self): def test_validate_cart_fails_product_ceilings(self):
self.make_ceiling("Limit ceiling", limit=1) self.make_ceiling("Limit ceiling", limit=1)
self.__validation_test() self.__validation_test()

View file

@ -1,11 +1,6 @@
import datetime
import pytz import pytz
from decimal import Decimal from decimal import Decimal
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
@ -14,6 +9,7 @@ from test_cart import RegistrationCartTestCase
UTC = pytz.timezone('UTC') UTC = pytz.timezone('UTC')
class DiscountTestCase(RegistrationCartTestCase): class DiscountTestCase(RegistrationCartTestCase):
@classmethod @classmethod
@ -32,7 +28,6 @@ class DiscountTestCase(RegistrationCartTestCase):
).save() ).save()
return discount return discount
@classmethod @classmethod
def add_discount_prod_1_includes_cat_2(cls, amount=Decimal(100)): def add_discount_prod_1_includes_cat_2(cls, amount=Decimal(100)):
discount = rego.IncludedProductDiscount.objects.create( discount = rego.IncludedProductDiscount.objects.create(
@ -49,9 +44,8 @@ class DiscountTestCase(RegistrationCartTestCase):
).save() ).save()
return discount return discount
def test_discount_is_applied(self): def test_discount_is_applied(self):
discount = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_1, 1) cart.add_to_cart(self.PROD_1, 1)
@ -60,9 +54,8 @@ class DiscountTestCase(RegistrationCartTestCase):
# Discounts should be applied at this point... # Discounts should be applied at this point...
self.assertEqual(1, len(cart.cart.discountitem_set.all())) self.assertEqual(1, len(cart.cart.discountitem_set.all()))
def test_discount_is_applied_for_category(self): def test_discount_is_applied_for_category(self):
discount = self.add_discount_prod_1_includes_cat_2() self.add_discount_prod_1_includes_cat_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_1, 1) cart.add_to_cart(self.PROD_1, 1)
@ -71,9 +64,8 @@ class DiscountTestCase(RegistrationCartTestCase):
# Discounts should be applied at this point... # Discounts should be applied at this point...
self.assertEqual(1, len(cart.cart.discountitem_set.all())) self.assertEqual(1, len(cart.cart.discountitem_set.all()))
def test_discount_does_not_apply_if_not_met(self): def test_discount_does_not_apply_if_not_met(self):
discount = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_2, 1) cart.add_to_cart(self.PROD_2, 1)
@ -81,9 +73,8 @@ class DiscountTestCase(RegistrationCartTestCase):
# No discount should be applied as the condition is not met # No discount should be applied as the condition is not met
self.assertEqual(0, len(cart.cart.discountitem_set.all())) self.assertEqual(0, len(cart.cart.discountitem_set.all()))
def test_discount_applied_out_of_order(self): def test_discount_applied_out_of_order(self):
discount = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_2, 1) cart.add_to_cart(self.PROD_2, 1)
@ -92,9 +83,8 @@ class DiscountTestCase(RegistrationCartTestCase):
# No discount should be applied as the condition is not met # No discount should be applied as the condition is not met
self.assertEqual(1, len(cart.cart.discountitem_set.all())) self.assertEqual(1, len(cart.cart.discountitem_set.all()))
def test_discounts_collapse(self): def test_discounts_collapse(self):
discount = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_1, 1) cart.add_to_cart(self.PROD_1, 1)
@ -104,9 +94,8 @@ class DiscountTestCase(RegistrationCartTestCase):
# Discounts should be applied and collapsed at this point... # Discounts should be applied and collapsed at this point...
self.assertEqual(1, len(cart.cart.discountitem_set.all())) self.assertEqual(1, len(cart.cart.discountitem_set.all()))
def test_discounts_respect_quantity(self): def test_discounts_respect_quantity(self):
discount = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_1, 1) cart.add_to_cart(self.PROD_1, 1)
@ -117,7 +106,6 @@ class DiscountTestCase(RegistrationCartTestCase):
discount_items = list(cart.cart.discountitem_set.all()) discount_items = list(cart.cart.discountitem_set.all())
self.assertEqual(2, discount_items[0].quantity) self.assertEqual(2, discount_items[0].quantity)
def test_multiple_discounts_apply_in_order(self): def test_multiple_discounts_apply_in_order(self):
discount_full = self.add_discount_prod_1_includes_prod_2() discount_full = self.add_discount_prod_1_includes_prod_2()
discount_half = self.add_discount_prod_1_includes_prod_2(Decimal(50)) discount_half = self.add_discount_prod_1_includes_prod_2(Decimal(50))
@ -137,9 +125,8 @@ class DiscountTestCase(RegistrationCartTestCase):
self.assertEqual(2, discount_items[1].quantity) self.assertEqual(2, discount_items[1].quantity)
self.assertEqual(discount_full.pk, discount_items[1].discount.pk) self.assertEqual(discount_full.pk, discount_items[1].discount.pk)
def test_discount_applies_across_carts(self): def test_discount_applies_across_carts(self):
discount_full = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
# Enable the discount during the first cart. # Enable the discount during the first cart.
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
@ -167,16 +154,16 @@ class DiscountTestCase(RegistrationCartTestCase):
discount_items = list(cart.cart.discountitem_set.all()) discount_items = list(cart.cart.discountitem_set.all())
self.assertEqual(1, discount_items[0].quantity) self.assertEqual(1, discount_items[0].quantity)
def test_discount_applies_only_once_enabled(self): def test_discount_applies_only_once_enabled(self):
# Enable the discount during the first cart. # Enable the discount during the first cart.
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_1, 1) cart.add_to_cart(self.PROD_1, 1)
cart.add_to_cart(self.PROD_2, 2) # This would exhaust discount if present # This would exhaust discount if present
cart.add_to_cart(self.PROD_2, 2)
cart.cart.active = False cart.cart.active = False
cart.cart.save() cart.cart.save()
discount_full = self.add_discount_prod_1_includes_prod_2() self.add_discount_prod_1_includes_prod_2()
cart = CartController.for_user(self.USER_1) cart = CartController.for_user(self.USER_1)
cart.add_to_cart(self.PROD_2, 2) cart.add_to_cart(self.PROD_2, 2)

View file

@ -1,11 +1,6 @@
import datetime
import pytz import pytz
from decimal import Decimal
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
@ -14,6 +9,7 @@ from test_cart import RegistrationCartTestCase
UTC = pytz.timezone('UTC') UTC = pytz.timezone('UTC')
class EnablingConditionTestCases(RegistrationCartTestCase): class EnablingConditionTestCases(RegistrationCartTestCase):
@classmethod @classmethod
@ -29,7 +25,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
enabling_condition.enabling_products.add(cls.PROD_2) enabling_condition.enabling_products.add(cls.PROD_2)
enabling_condition.save() enabling_condition.save()
@classmethod @classmethod
def add_product_enabling_condition_on_category(cls, mandatory=False): def add_product_enabling_condition_on_category(cls, mandatory=False):
''' Adds a product enabling condition that operates on a category: ''' Adds a product enabling condition that operates on a category:
@ -43,7 +38,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
enabling_condition.enabling_products.add(cls.PROD_3) enabling_condition.enabling_products.add(cls.PROD_3)
enabling_condition.save() enabling_condition.save()
def add_category_enabling_condition(cls, mandatory=False): def add_category_enabling_condition(cls, mandatory=False):
''' Adds a category enabling condition: adding PROD_1 to a cart is ''' Adds a category enabling condition: adding PROD_1 to a cart is
predicated on adding an item from CAT_2 beforehand.''' predicated on adding an item from CAT_2 beforehand.'''
@ -56,7 +50,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
enabling_condition.products.add(cls.PROD_1) enabling_condition.products.add(cls.PROD_1)
enabling_condition.save() enabling_condition.save()
def test_product_enabling_condition_enables_product(self): def test_product_enabling_condition_enables_product(self):
self.add_product_enabling_condition() self.add_product_enabling_condition()
@ -68,7 +61,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
current_cart.add_to_cart(self.PROD_2, 1) current_cart.add_to_cart(self.PROD_2, 1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_product_enabled_by_product_in_previous_cart(self): def test_product_enabled_by_product_in_previous_cart(self):
self.add_product_enabling_condition() self.add_product_enabling_condition()
@ -81,7 +73,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
current_cart = CartController.for_user(self.USER_1) current_cart = CartController.for_user(self.USER_1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_product_enabling_condition_enables_category(self): def test_product_enabling_condition_enables_category(self):
self.add_product_enabling_condition_on_category() self.add_product_enabling_condition_on_category()
@ -93,7 +84,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
current_cart.add_to_cart(self.PROD_3, 1) current_cart.add_to_cart(self.PROD_3, 1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_category_enabling_condition_enables_product(self): def test_category_enabling_condition_enables_product(self):
self.add_category_enabling_condition() self.add_category_enabling_condition()
@ -106,7 +96,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
current_cart.add_to_cart(self.PROD_3, 1) current_cart.add_to_cart(self.PROD_3, 1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_product_enabled_by_category_in_previous_cart(self): def test_product_enabled_by_category_in_previous_cart(self):
self.add_category_enabling_condition() self.add_category_enabling_condition()
@ -119,7 +108,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
current_cart = CartController.for_user(self.USER_1) current_cart = CartController.for_user(self.USER_1)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_multiple_non_mandatory_conditions(self): def test_multiple_non_mandatory_conditions(self):
self.add_product_enabling_condition() self.add_product_enabling_condition()
self.add_category_enabling_condition() self.add_category_enabling_condition()
@ -140,7 +128,6 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
cart_2.add_to_cart(self.PROD_3, 1) cart_2.add_to_cart(self.PROD_3, 1)
cart_2.add_to_cart(self.PROD_1, 1) cart_2.add_to_cart(self.PROD_1, 1)
def test_multiple_mandatory_conditions(self): def test_multiple_mandatory_conditions(self):
self.add_product_enabling_condition(mandatory=True) self.add_product_enabling_condition(mandatory=True)
self.add_category_enabling_condition(mandatory=True) self.add_category_enabling_condition(mandatory=True)
@ -149,13 +136,12 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
# Cannot add PROD_1 until both conditions are met # Cannot add PROD_1 until both conditions are met
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)
cart_1.add_to_cart(self.PROD_2, 1) # Meets the product condition cart_1.add_to_cart(self.PROD_2, 1) # Meets the product condition
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)
cart_1.add_to_cart(self.PROD_3, 1) # Meets the category condition cart_1.add_to_cart(self.PROD_3, 1) # Meets the category condition
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)
def test_mandatory_conditions_are_mandatory(self): def test_mandatory_conditions_are_mandatory(self):
self.add_product_enabling_condition(mandatory=False) self.add_product_enabling_condition(mandatory=False)
self.add_category_enabling_condition(mandatory=True) self.add_category_enabling_condition(mandatory=True)
@ -164,8 +150,8 @@ class EnablingConditionTestCases(RegistrationCartTestCase):
# Cannot add PROD_1 until both conditions are met # Cannot add PROD_1 until both conditions are met
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)
cart_1.add_to_cart(self.PROD_2, 1) # Meets the product condition cart_1.add_to_cart(self.PROD_2, 1) # Meets the product condition
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)
cart_1.add_to_cart(self.PROD_3, 1) # Meets the category condition cart_1.add_to_cart(self.PROD_3, 1) # Meets the category condition
cart_1.add_to_cart(self.PROD_1, 1) cart_1.add_to_cart(self.PROD_1, 1)

View file

@ -2,10 +2,7 @@ import datetime
import pytz import pytz
from decimal import Decimal from decimal import Decimal
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
@ -74,7 +71,6 @@ class InvoiceTestCase(RegistrationCartTestCase):
new_cart = CartController.for_user(self.USER_1) new_cart = CartController.for_user(self.USER_1)
self.assertNotEqual(current_cart.cart, new_cart.cart) self.assertNotEqual(current_cart.cart, new_cart.cart)
def test_invoice_includes_discounts(self): def test_invoice_includes_discounts(self):
voucher = rego.Voucher.objects.create( voucher = rego.Voucher.objects.create(
recipient="Voucher recipient", recipient="Voucher recipient",
@ -105,4 +101,6 @@ class InvoiceTestCase(RegistrationCartTestCase):
line_items = rego.LineItem.objects.filter(invoice=invoice_1.invoice) line_items = rego.LineItem.objects.filter(invoice=invoice_1.invoice)
self.assertEqual(2, len(line_items)) self.assertEqual(2, len(line_items))
# That invoice should have a value equal to 50% of the cost of PROD_1 # That invoice should have a value equal to 50% of the cost of PROD_1
self.assertEqual(self.PROD_1.price * Decimal("0.5"), invoice_1.invoice.value) self.assertEqual(
self.PROD_1.price * Decimal("0.5"),
invoice_1.invoice.value)

View file

@ -2,10 +2,7 @@ import datetime
import pytz import pytz
from decimal import Decimal from decimal import Decimal
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.test import TestCase
from django.utils import timezone
from registrasion import models as rego from registrasion import models as rego
from registrasion.controllers.cart import CartController from registrasion.controllers.cart import CartController
@ -41,7 +38,8 @@ class VoucherTestCases(RegistrationCartTestCase):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
cart_2.apply_voucher(voucher) cart_2.apply_voucher(voucher)
# After the reservation duration, user 2 should be able to apply voucher # After the reservation duration
# user 2 should be able to apply voucher
self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2) self.add_timedelta(rego.Voucher.RESERVATION_DURATION * 2)
cart_2.apply_voucher(voucher) cart_2.apply_voucher(voucher)
cart_2.cart.active = False cart_2.cart.active = False
@ -74,7 +72,6 @@ class VoucherTestCases(RegistrationCartTestCase):
current_cart.apply_voucher(voucher) current_cart.apply_voucher(voucher)
current_cart.add_to_cart(self.PROD_1, 1) current_cart.add_to_cart(self.PROD_1, 1)
def test_voucher_enables_discount(self): def test_voucher_enables_discount(self):
voucher = self.new_voucher() voucher = self.new_voucher()

3
setup.cfg Normal file
View file

@ -0,0 +1,3 @@
[flake8]
exclude = registrasion/migrations/*