models.py 6.43 KB
Newer Older
1
2
3
4
5
from datetime import date, timedelta
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
6
7
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
8
9
10
11

from core.models import User

def validate_type(value):
Skia's avatar
Skia committed
12
    if value not in settings.SITH_SUBSCRIPTIONS.keys():
13
14
15
        raise ValidationError(_('Bad subscription type'))

def validate_payment(value):
16
    if value not in settings.SITH_SUBSCRIPTION_PAYMENT_METHOD:
17
18
        raise ValidationError(_('Bad payment method'))

19
20
21
class Subscriber(User):
    class Meta:
        proxy = True
22
23

    def is_subscribed(self):
Skia's avatar
Skia committed
24
25
        s = self.subscriptions.last()
        return s.is_valid_now() if s is not None else False
26
27

class Subscription(models.Model):
28
    member = models.ForeignKey(Subscriber, related_name='subscriptions')
29
30
    subscription_type = models.CharField(_('subscription type'),
                                         max_length=255,
Skia's avatar
Skia committed
31
                                         choices=((k, v['name']) for k,v in sorted(settings.SITH_SUBSCRIPTIONS.items())))
32
33
    subscription_start = models.DateField(_('subscription start'))
    subscription_end = models.DateField(_('subscription end'))
34
    payment_method = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD)
Skia's avatar
Skia committed
35
36
    location = models.CharField(choices=settings.SITH_SUBSCRIPTION_LOCATIONS,
            max_length=20, verbose_name=_('location'))
Skia's avatar
Skia committed
37
    # TODO add location!
38

39
    class Meta:
40
        ordering = ['subscription_start',]
41
42

    def clean(self):
43
44
45
46
47
48
49
50
        try:
            for s in Subscription.objects.filter(member=self.member).exclude(pk=self.pk).all():
                if s.is_valid_now():
                    raise ValidationError(_("You can not subscribe many time for the same period"))
        except: # This should not happen, because the form should have handled the data before, but sadly, it still
                # calls the model validation :'(
                # TODO see SubscriptionForm's clean method
            raise ValidationError(_("You are trying to create a subscription without member"))
51

52
53
54
55
    def save(self):
        super(Subscription, self).save()
        from counter.models import Customer
        if not Customer.objects.filter(user=self.member).exists():
Skia's avatar
Skia committed
56
            Customer(user=self.member, account_id=Customer.generate_account_id(self.id), amount=0).save()
Skia's avatar
Skia committed
57
        self.member.make_home()
58

59
60
61
    def get_absolute_url(self):
        return reverse('core:user_profile', kwargs={'user_id': self.member.pk})

62
    def __str__(self):
63
64
65
66
67
        if hasattr(self, "member") and self.member is not None:
            return self.member.username+' - '+str(self.pk)
        else:
            return 'No user - '+str(self.pk)

68

69
    @staticmethod
70
    def compute_start(d=date.today(), duration=1):
71
72
        """
        This function computes the start date of the subscription with respect to the given date (default is today),
Skia's avatar
Skia committed
73
        and the start date given in settings.SITH_START_DATE.
74
        It takes the nearest past start date.
Skia's avatar
Skia committed
75
        Exemples: with SITH_START_DATE = (8, 15)
76
77
78
79
            Today      -> Start date
            2015-03-17 -> 2015-02-15
            2015-01-11 -> 2014-08-15
        """
80
81
        if duration <= 2: # Sliding subscriptions for 1 or 2 semesters
            return d
82
83
        today = d
        year = today.year
Skia's avatar
Skia committed
84
        start = date(year, settings.SITH_START_DATE[0], settings.SITH_START_DATE[1])
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
        start2 = start.replace(month=(start.month+6)%12)
        if start > start2:
            start, start2 = start2, start
        if today < start:
            return start2.replace(year=year-1)
        elif today < start2:
            return start
        else:
            return start2

    @staticmethod
    def compute_end(duration, start=None):
        """
        This function compute the end date of the subscription given a start date and a duration in number of semestre
        Exemple:
            Start - Duration -> End date
            2015-09-18 - 1 -> 2016-03-18
            2015-09-18 - 2 -> 2016-09-18
            2015-09-18 - 3 -> 2017-03-18
            2015-09-18 - 4 -> 2017-09-18
        """
        if start is None:
107
            start = Subscription.compute_start(duration=duration)
108
        # This can certainly be simplified, but it works like this
109
110
111
112
113
        try:
            return start.replace(month=(start.month-1+6*duration)%12+1,
                             year=start.year+int(duration/2)+(1 if start.month > 6 and duration%2 == 1 else 0))
        except ValueError as e:
            return start.replace(day=1, month=(start.month+6*duration)%12+1,
114
115
                             year=start.year+int(duration/2)+(1 if start.month > 6 and duration%2 == 1 else 0))

116

Skia's avatar
Skia committed
117
    def can_be_edited_by(self, user):
Skia's avatar
Skia committed
118
        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user.is_in_group(settings.SITH_GROUPS['root']['name'])
Skia's avatar
Skia committed
119

120
121
122
    def is_valid_now(self):
        return self.subscription_start <= date.today() and date.today() <= self.subscription_end

123
124
125
126
def guy_test(date, duration=4):
    print(str(date)+" - "+str(duration)+" -> "+str(Subscription.compute_start(date, duration)))
def bibou_test(duration, date=date.today()):
    print(str(date)+" - "+str(duration)+" -> "+str(Subscription.compute_end(duration, Subscription.compute_start(date, duration))))
127
128
129
130
131
132
133
134
135
136
def guy():
    guy_test(date(2015, 7, 11))
    guy_test(date(2015, 8, 11))
    guy_test(date(2015, 2, 17))
    guy_test(date(2015, 3, 17))
    guy_test(date(2015, 1, 11))
    guy_test(date(2015, 2, 11))
    guy_test(date(2015, 8, 17))
    guy_test(date(2015, 9, 17))
    print('='*80)
137
138
139
140
141
142
143
144
145
    guy_test(date(2015, 7, 11), 1)
    guy_test(date(2015, 8, 11), 2)
    guy_test(date(2015, 2, 17), 3)
    guy_test(date(2015, 3, 17), 4)
    guy_test(date(2015, 1, 11), 1)
    guy_test(date(2015, 2, 11), 2)
    guy_test(date(2015, 8, 17), 3)
    guy_test(date(2015, 9, 17), 4)
    print('='*80)
146
147
148
149
150
151
152
153
    bibou_test(1, date(2015, 2, 18))
    bibou_test(2, date(2015, 2, 18))
    bibou_test(3, date(2015, 2, 18))
    bibou_test(4, date(2015, 2, 18))
    bibou_test(1, date(2015, 9, 18))
    bibou_test(2, date(2015, 9, 18))
    bibou_test(3, date(2015, 9, 18))
    bibou_test(4, date(2015, 9, 18))
154
    print('='*80)
Skia's avatar
Skia committed
155
    bibou_test(1, date(2000, 2, 29))
156
157
158
    bibou_test(2, date(2000, 2, 29))
    bibou_test(1, date(2000, 5, 31))
    bibou_test(1, date(2000, 7, 31))
159
160
161
162
163
164
165
    bibou_test(1)
    bibou_test(2)
    bibou_test(3)
    bibou_test(4)

if __name__ == "__main__":
    guy()