Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

abstract_models.py 5.4KB

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