From 1333fcdea1790b3ab70a7d9e4d913b302b7e78b6 Mon Sep 17 00:00:00 2001 From: Christopher Neugebauer Date: Sun, 4 Sep 2016 11:30:29 +1000 Subject: [PATCH] Refactors flags and discount classes to be DRYer. --- registrasion/models/conditions.py | 142 ++++++++++++++++-------------- 1 file changed, 75 insertions(+), 67 deletions(-) diff --git a/registrasion/models/conditions.py b/registrasion/models/conditions.py index 41e1a320..837753e1 100644 --- a/registrasion/models/conditions.py +++ b/registrasion/models/conditions.py @@ -9,7 +9,75 @@ from django.utils.translation import ugettext_lazy as _ from model_utils.managers import InheritanceManager -# Product Modifiers +# Condition Types + +class TimeOrStockLimitCondition(models.Model): + ''' Attributes for a condition that is limited by timespan or a count of + purchased or reserved items. + + Attributes: + start_time (Optional[datetime]): When the condition should start being + true. + + end_time (Optional[datetime]): When the condition should stop being + true. + + limit (Optional[int]): How many items may fall under the condition + the condition until it stops being false -- for all users. + ''' + + class Meta: + abstract = True + + start_time = models.DateTimeField( + null=True, + blank=True, + verbose_name=_("Start time"), + help_text=_("When the condition should start being true"), + ) + end_time = models.DateTimeField( + null=True, + blank=True, + verbose_name=_("End time"), + help_text=_("When the condition should stop being true."), + ) + limit = models.PositiveIntegerField( + null=True, + blank=True, + verbose_name=_("Limit"), + help_text=_( + "How many times this condition may be applied for all users." + ), + ) + + +class VoucherCondition(models.Model): + ''' A condition is met when a voucher code is in the current cart. ''' + + class Meta: + abstract = True + + voucher = models.OneToOneField( + inventory.Voucher, + on_delete=models.CASCADE, + verbose_name=_("Voucher"), + db_index=True, + ) + + +class IncludedProductCondition(models.Model): + class Meta: + abstract = True + + enabling_products = models.ManyToManyField( + inventory.Product, + verbose_name=_("Including product"), + help_text=_("If one of these products are purchased, this condition " + "is met."), + ) + + +# Discounts @python_2_unicode_compatible class DiscountBase(models.Model): @@ -154,7 +222,7 @@ class DiscountForCategory(models.Model): quantity = models.PositiveIntegerField() -class TimeOrStockLimitDiscount(DiscountBase): +class TimeOrStockLimitDiscount(TimeOrStockLimitCondition, DiscountBase): ''' Discounts that are generally available, but are limited by timespan or usage count. This is for e.g. Early Bird discounts. @@ -175,27 +243,8 @@ class TimeOrStockLimitDiscount(DiscountBase): verbose_name = _("discount (time/stock limit)") verbose_name_plural = _("discounts (time/stock limit)") - start_time = models.DateTimeField( - null=True, - blank=True, - verbose_name=_("Start time"), - help_text=_("This discount will only be available after this time."), - ) - end_time = models.DateTimeField( - null=True, - blank=True, - verbose_name=_("End time"), - help_text=_("This discount will only be available before this time."), - ) - limit = models.PositiveIntegerField( - null=True, - blank=True, - verbose_name=_("Limit"), - help_text=_("This discount may only be applied this many times."), - ) - -class VoucherDiscount(DiscountBase): +class VoucherDiscount(VoucherCondition, DiscountBase): ''' Discounts that are enabled when a voucher code is in the current cart. These are normally configured in the Admin page at the same time as creating a Voucher object. @@ -210,15 +259,8 @@ class VoucherDiscount(DiscountBase): verbose_name = _("discount (enabled by voucher)") verbose_name_plural = _("discounts (enabled by voucher)") - voucher = models.OneToOneField( - inventory.Voucher, - on_delete=models.CASCADE, - verbose_name=_("Voucher"), - db_index=True, - ) - -class IncludedProductDiscount(DiscountBase): +class IncludedProductDiscount(IncludedProductCondition, DiscountBase): ''' Discounts that are enabled because another product has been purchased. e.g. A conference ticket includes a free t-shirt. @@ -233,13 +275,6 @@ class IncludedProductDiscount(DiscountBase): verbose_name = _("discount (product inclusions)") verbose_name_plural = _("discounts (product inclusions)") - enabling_products = models.ManyToManyField( - inventory.Product, - verbose_name=_("Including product"), - help_text=_("If one of these products are purchased, the discounts " - "below will be enabled."), - ) - class RoleDiscount(object): ''' Discounts that are enabled because the active user has a specific @@ -330,7 +365,7 @@ class FlagBase(models.Model): ) -class TimeOrStockLimitFlag(FlagBase): +class TimeOrStockLimitFlag(TimeOrStockLimitCondition, FlagBase): ''' Product groupings that can be used to enable a product during a specific date range, or when fewer than a limit of products have been sold. @@ -352,28 +387,9 @@ class TimeOrStockLimitFlag(FlagBase): verbose_name = _("flag (time/stock limit)") verbose_name_plural = _("flags (time/stock limit)") - start_time = models.DateTimeField( - null=True, - blank=True, - help_text=_("Products included in this condition will only be " - "available after this time."), - ) - end_time = models.DateTimeField( - null=True, - blank=True, - help_text=_("Products included in this condition will only be " - "available before this time."), - ) - limit = models.PositiveIntegerField( - null=True, - blank=True, - help_text=_("The number of items under this grouping that can be " - "purchased."), - ) - @python_2_unicode_compatible -class ProductFlag(FlagBase): +class ProductFlag(IncludedProductCondition, FlagBase): ''' The condition is met because a specific product is purchased. Attributes: @@ -389,12 +405,6 @@ class ProductFlag(FlagBase): def __str__(self): return "Enabled by products: " + str(self.enabling_products.all()) - enabling_products = models.ManyToManyField( - inventory.Product, - help_text=_("If one of these products are purchased, this condition " - "is met."), - ) - @python_2_unicode_compatible class CategoryFlag(FlagBase): @@ -422,7 +432,7 @@ class CategoryFlag(FlagBase): @python_2_unicode_compatible -class VoucherFlag(FlagBase): +class VoucherFlag(VoucherCondition, FlagBase): ''' The condition is met because a Voucher is present. This is for e.g. enabling sponsor tickets. ''' @@ -434,8 +444,6 @@ class VoucherFlag(FlagBase): def __str__(self): return "Enabled by voucher: %s" % self.voucher - voucher = models.OneToOneField(inventory.Voucher) - # @python_2_unicode_compatible class RoleFlag(object):