You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

abstract_models.py 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. from decimal import Decimal
  2. import datetime
  3. from django.core import exceptions
  4. from django.db import models
  5. from django.utils.translation import ugettext as _
  6. class AbstractVoucher(models.Model):
  7. """
  8. A voucher. This is simply a link to a collection of offers.
  9. Note that there are three possible "usage" models:
  10. (a) Single use
  11. (b) Multi-use
  12. (c) Once per customer
  13. """
  14. name = models.CharField(_("Name"), max_length=128,
  15. help_text=_("""This will be shown in the checkout and basket once the voucher is entered"""))
  16. code = models.CharField(_("Code"), max_length=128, db_index=True, unique=True,
  17. help_text=_("""Case insensitive / No spaces allowed"""))
  18. offers = models.ManyToManyField('offer.ConditionalOffer', related_name='vouchers',
  19. limit_choices_to={'offer_type': "Voucher"})
  20. SINGLE_USE, MULTI_USE, ONCE_PER_CUSTOMER = ('Single use', 'Multi-use', 'Once per customer')
  21. USAGE_CHOICES = (
  22. (SINGLE_USE, _("Can be used once by one customer")),
  23. (MULTI_USE, _("Can be used multiple times by multiple customers")),
  24. (ONCE_PER_CUSTOMER, _("Can only be used once per customer")),
  25. )
  26. usage = models.CharField(_("Usage"), max_length=128, choices=USAGE_CHOICES, default=MULTI_USE)
  27. start_date = models.DateField(_('Start Date'))
  28. end_date = models.DateField(_('End Date'))
  29. # Audit information
  30. num_basket_additions = models.PositiveIntegerField(_('Times added to basket'), default=0)
  31. num_orders = models.PositiveIntegerField(_('Times on orders'), default=0)
  32. total_discount = models.DecimalField(_('Total discount'), decimal_places=2, max_digits=12, default=Decimal('0.00'))
  33. date_created = models.DateField(auto_now_add=True)
  34. class Meta:
  35. get_latest_by = 'date_created'
  36. abstract = True
  37. verbose_name = _("Voucher")
  38. verbose_name_plural = _("Vouchers")
  39. def __unicode__(self):
  40. return self.name
  41. def clean(self):
  42. if self.start_date and self.end_date and self.start_date > self.end_date:
  43. raise exceptions.ValidationError(_('End date should be later than start date'))
  44. def save(self, *args, **kwargs):
  45. self.code = self.code.upper()
  46. super(AbstractVoucher, self).save(*args, **kwargs)
  47. def is_active(self, test_date=None):
  48. """
  49. Test whether this voucher is currently active.
  50. """
  51. if not test_date:
  52. test_date = datetime.date.today()
  53. return self.start_date <= test_date and test_date < self.end_date
  54. def is_available_to_user(self, user=None):
  55. """
  56. Test whether this voucher is available to the passed user.
  57. Returns a tuple of a boolean for whether it is successulf, and a message
  58. """
  59. is_available, message = False, ''
  60. if self.usage == self.SINGLE_USE:
  61. is_available = self.applications.count() == 0
  62. if not is_available:
  63. message = _("This voucher has already been used")
  64. elif self.usage == self.MULTI_USE:
  65. is_available = True
  66. elif self.usage == self.ONCE_PER_CUSTOMER:
  67. if not user.is_authenticated():
  68. is_available = False
  69. message = _("This voucher is only available to signed in users")
  70. else:
  71. is_available = self.applications.filter(voucher=self, user=user).count() == 0
  72. if not is_available:
  73. message = _("You have already used this voucher in a previous order")
  74. return is_available, message
  75. def record_usage(self, order, user):
  76. """
  77. Records a usage of this voucher in an order.
  78. """
  79. if user.is_authenticated():
  80. self.applications.create(voucher=self, order=order, user=user)
  81. else:
  82. self.applications.create(voucher=self, order=order)
  83. self.num_orders += 1
  84. self.save()
  85. def record_discount(self, discount):
  86. """
  87. Record a discount that this offer has given
  88. """
  89. self.total_discount += discount
  90. self.save()
  91. @property
  92. def benefit(self):
  93. return self.offers.all()[0].benefit
  94. class AbstractVoucherApplication(models.Model):
  95. """
  96. For tracking how often a voucher has been used
  97. """
  98. voucher = models.ForeignKey('voucher.Voucher', related_name="applications")
  99. # It is possible for an anonymous user to apply a voucher so we need to allow
  100. # the user to be nullable
  101. user = models.ForeignKey('auth.User', blank=True, null=True)
  102. order = models.ForeignKey('order.Order')
  103. date_created = models.DateField(auto_now_add=True)
  104. class Meta:
  105. abstract = True
  106. verbose_name = _("Voucher Application")
  107. verbose_name_plural = _("Voucher Applications")
  108. def __unicode__(self):
  109. return _("'%(voucher)s' used by '%(user)s'") % {
  110. 'voucher': self.voucher,
  111. 'user': self.user}