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]
93 return self.expires_at is not None and self.expires_at < now()
95 def create_payment(self):
97 self.expires_at = self.plan.get_next_installment(n)
100 self.payment_set.create(payed_at=n)
103 class Payment(models.Model):
104 schedule = models.ForeignKey(Schedule, verbose_name=_('schedule'), on_delete=models.PROTECT)
105 created_at = models.DateTimeField(_('created at'), auto_now_add=True)
106 payed_at = models.DateTimeField(_('payed at'), null=True, blank=True)
109 verbose_name = _('payment')
110 verbose_name_plural = _('payments')
113 return "%s %s" % (self.schedule, self.payed_at)
116 class Membership(models.Model):
117 """ Represents a user being recognized as a member of the club. """
118 user = models.OneToOneField(settings.AUTH_USER_MODEL, verbose_name=_('user'), on_delete=models.CASCADE)
119 created_at = models.DateTimeField(_('created at'), auto_now_add=True)
122 verbose_name = _('membership')
123 verbose_name_plural = _('memberships')
126 return u'tow. ' + str(self.user)
129 class ReminderEmail(models.Model):
130 days_before = models.SmallIntegerField(_('days before'))
131 subject = models.CharField(_('subject'), max_length=1024)
132 body = models.TextField(_('body'))
135 verbose_name = _('reminder email')
136 verbose_name_plural = _('reminder emails')
137 ordering = ['days_before']
140 if self.days_before >= 0:
141 return ungettext('a day before expiration', '%d days before expiration', n=self.days_before)
143 return ungettext('a day after expiration', '%d days after expiration', n=-self.days_before)