models.py 6.26 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
    # TODO add location!
36

37
    class Meta:
38
        ordering = ['subscription_start',]
39
40

    def clean(self):
41
42
43
44
45
46
47
48
        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"))
49

50
51
52
53
54
    def save(self):
        super(Subscription, self).save()
        from counter.models import Customer
        if not Customer.objects.filter(user=self.member).exists():
            Customer(user=self.member, account_id=Customer.generate_account_id(), amount=0).save()
55

56
57
58
    def get_absolute_url(self):
        return reverse('core:user_profile', kwargs={'user_id': self.member.pk})

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

65

66
    @staticmethod
67
    def compute_start(d=date.today(), duration=1):
68
69
        """
        This function computes the start date of the subscription with respect to the given date (default is today),
Skia's avatar
Skia committed
70
        and the start date given in settings.SITH_START_DATE.
71
        It takes the nearest past start date.
Skia's avatar
Skia committed
72
        Exemples: with SITH_START_DATE = (8, 15)
73
74
75
76
            Today      -> Start date
            2015-03-17 -> 2015-02-15
            2015-01-11 -> 2014-08-15
        """
77
78
        if duration <= 2: # Sliding subscriptions for 1 or 2 semesters
            return d
79
80
        today = d
        year = today.year
Skia's avatar
Skia committed
81
        start = date(year, settings.SITH_START_DATE[0], settings.SITH_START_DATE[1])
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
        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:
104
            start = Subscription.compute_start(duration=duration)
105
        # This can certainly be simplified, but it works like this
106
107
108
109
110
        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,
111
112
                             year=start.year+int(duration/2)+(1 if start.month > 6 and duration%2 == 1 else 0))

113

Skia's avatar
Skia committed
114
    def can_be_edited_by(self, user):
Skia's avatar
Skia committed
115
        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
116

117
118
119
    def is_valid_now(self):
        return self.subscription_start <= date.today() and date.today() <= self.subscription_end

120
121
122
123
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))))
124
125
126
127
128
129
130
131
132
133
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)
134
135
136
137
138
139
140
141
142
    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)
143
144
145
146
147
148
149
150
    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))
151
    print('='*80)
Skia's avatar
Skia committed
152
    bibou_test(1, date(2000, 2, 29))
153
154
155
    bibou_test(2, date(2000, 2, 29))
    bibou_test(1, date(2000, 5, 31))
    bibou_test(1, date(2000, 7, 31))
156
157
158
159
160
161
162
    bibou_test(1)
    bibou_test(2)
    bibou_test(3)
    bibou_test(4)

if __name__ == "__main__":
    guy()