2 from __future__ import unicode_literals
4 from datetime import timedelta
5 from django.conf import settings
6 from django.urls import reverse
7 from django.db import models
8 from django.utils.timezone import now
9 from django.utils.translation import ugettext_lazy as _, ungettext
10 from catalogue.utils import get_random_hash
11 from .payment_methods import methods, method_by_slug
14 class Plan(models.Model):
15 """ Plans are set up by administrators. """
20 (MONTH, _('a month')),
22 (PERPETUAL, _('in perpetuity')),
25 interval = models.SmallIntegerField(_('inteval'), choices=intervals)
26 min_amount = models.DecimalField(_('min_amount'), max_digits=10, decimal_places=2)
27 allow_recurring = models.BooleanField(_('allow recurring'))
28 allow_one_time = models.BooleanField(_('allow one time'))
31 verbose_name = _('plan')
32 verbose_name_plural = _('plans')
35 return "%s %s" % (self.min_amount, self.get_interval_display())
38 ordering = ('interval',)
40 def payment_methods(self):
41 for method in methods:
42 if self.allow_recurring and method.is_recurring or self.allow_one_time and not method.is_recurring:
45 def get_next_installment(self, date):
46 if self.interval == self.PERPETUAL:
48 elif self.interval == self.YEAR:
49 return date.replace(year=date.year + 1)
50 elif self.interval == self.MONTH:
52 date = (date.replace(day=1) + timedelta(31)).replace(day=1) + timedelta(day - 1)
54 date = date.replace(day=1)
59 class Schedule(models.Model):
60 """ Represents someone taking up a plan. """
61 key = models.CharField(_('key'), max_length=255, unique=True)
62 email = models.EmailField(_('email'))
63 membership = models.ForeignKey('Membership', verbose_name=_('membership'), null=True, blank=True, on_delete=models.PROTECT)
64 plan = models.ForeignKey(Plan, verbose_name=_('plan'), on_delete=models.PROTECT)
65 amount = models.DecimalField(_('amount'), max_digits=10, decimal_places=2)
66 method = models.CharField(_('method'), max_length=255, choices=[(method.slug, method.name) for method in methods])
67 is_active = models.BooleanField(_('active'), default=False)
68 is_cancelled = models.BooleanField(_('cancelled'), default=False)
69 started_at = models.DateTimeField(_('started at'), auto_now_add=True)
70 expires_at = models.DateTimeField(_('expires_at'), null=True, blank=True)
74 verbose_name = _('schedule')
75 verbose_name_plural = _('schedules')
80 def save(self, *args, **kwargs):
82 self.key = get_random_hash(self.email)
83 return super(Schedule, self).save(*args, **kwargs)
85 def get_absolute_url(self):
86 return reverse('club_schedule', args=[self.key])
88 def get_payment_method(self):
89 return method_by_slug[self.method]
92 return self.expires_at is not None and self.expires_at < now()
94 def create_payment(self):
96 self.expires_at = self.plan.get_next_installment(n)
99 self.payment_set.create(payed_at=n)
102 class Payment(models.Model):
103 schedule = models.ForeignKey(Schedule, verbose_name=_('schedule'), on_delete=models.PROTECT)
104 created_at = models.DateTimeField(_('created at'), auto_now_add=True)
105 payed_at = models.DateTimeField(_('payed at'), null=True, blank=True)
108 verbose_name = _('payment')
109 verbose_name_plural = _('payments')
112 return "%s %s" % (self.schedule, self.payed_at)
115 class Membership(models.Model):
116 """ Represents a user being recognized as a member of the club. """
117 user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
118 created_at = models.DateTimeField(_('created at'), auto_now_add=True)
121 verbose_name = _('membership')
122 verbose_name_plural = _('memberships')
125 return u'tow. ' + str(self.user)
128 def is_active_for(self, user):
129 if user.is_anonymous:
131 return Schedule.objects.filter(
132 models.Q(expires_at=None) | models.Q(expires_at__lt=now()),
133 membership__user=user,
138 class ReminderEmail(models.Model):
139 days_before = models.SmallIntegerField(_('days before'))
140 subject = models.CharField(_('subject'), max_length=1024)
141 body = models.TextField(_('body'))
144 verbose_name = _('reminder email')
145 verbose_name_plural = _('reminder emails')
146 ordering = ['days_before']
149 if self.days_before >= 0:
150 return ungettext('a day before expiration', '%d days before expiration', n=self.days_before)
152 return ungettext('a day after expiration', '%d days after expiration', n=-self.days_before)