diff --git a/core/models.py b/core/models.py index b3bd10de..45b8f78f 100644 --- a/core/models.py +++ b/core/models.py @@ -230,7 +230,7 @@ class User(AbstractBaseUser): @cached_property def is_subscribed(self): - s = self.subscriptions.last() + s = self.subscriptions.filter(subscription_start__lte=timezone.now()).last() return s.is_valid_now() if s is not None else False _club_memberships = {} diff --git a/sith/settings.py b/sith/settings.py index 3f2576c9..d5ce3c17 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -421,6 +421,9 @@ SITH_CAN_CREATE_SUBSCRIPTIONS = [ 1, ] +# Number of weeks before the end of a subscription when the subscriber can resubscribe +SITH_SUBSCRIPTION_END = 10 + # Subscription durations are in semestres # Be careful, modifying this parameter will need a migration to be applied SITH_SUBSCRIPTIONS = { diff --git a/subscription/models.py b/subscription/models.py index 8d28488d..9a820a6a 100644 --- a/subscription/models.py +++ b/subscription/models.py @@ -64,7 +64,7 @@ class Subscription(models.Model): def clean(self): try: for s in Subscription.objects.filter(member=self.member).exclude(pk=self.pk).all(): - if s.is_valid_now(): + if s.is_valid_now() and s.subscription_end - timedelta(weeks=settings.SITH_SUBSCRIPTION_END) > date.today(): 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 :'( @@ -138,7 +138,7 @@ class Subscription(models.Model): return 'No user - ' + str(self.pk) @staticmethod - def compute_start(d=None, duration=1): + def compute_start(d=None, duration=1, user=None): """ This function computes the start date of the subscription with respect to the given date (default is today), and the start date given in settings.SITH_START_DATE. @@ -150,12 +150,14 @@ class Subscription(models.Model): """ if not d: d = date.today() + if user is not None and user.subscriptions.exists(): + d = user.subscriptions.last().subscription_end if duration <= 2: # Sliding subscriptions for 1 or 2 semesters return d return get_start_of_semester(d) @staticmethod - def compute_end(duration, start=None): + def compute_end(duration, start=None, user=None): """ This function compute the end date of the subscription given a start date and a duration in number of semestre Exemple: @@ -166,7 +168,8 @@ class Subscription(models.Model): 2015-09-18 - 4 -> 2017-09-18 """ if start is None: - start = Subscription.compute_start(duration=duration) + start = Subscription.compute_start(duration=duration, user=user) + # This can certainly be simplified, but it works like this try: return start.replace(month=int(round((start.month - 1 + 6 * duration) % 12 + 1, 0)), diff --git a/subscription/tests.py b/subscription/tests.py index 49ae423b..77660beb 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -137,3 +137,24 @@ class DecimalDurationTest(TestCase): start=s.subscription_start) s.save() self.assertTrue(s.subscription_end == date(2017, 12, 29)) + + +class SpecialCasesOfSubscription(TestCase): + def setUp(self): + call_command("populate") + self.user = User.objects.filter(username="public").first() + + @mock.patch('subscription.models.date', FakeDate) + def test_subscription_before_end_of_actual_one(self): + user = User.objects.filter(pk=self.user.pk).first() + s = Subscription(member=user, subscription_type=list(settings.SITH_SUBSCRIPTIONS.keys())[3], + payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0]) + s.subscription_start = date(2015, 8, 29) + s.subscription_end = s.compute_end(duration=2, + start=s.subscription_start) + s.save() + self.assertTrue(s.subscription_end == date(2016, 8, 29)) + date_mock_today(2016, 8, 25) + d = Subscription.compute_end(duration=2, + user=user) + self.assertTrue(d == date(2017, 8, 29)) diff --git a/subscription/views.py b/subscription/views.py index 76e26ea1..a2e5f7a8 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -117,10 +117,12 @@ class NewSubscription(CreateView): def form_valid(self, form): form.instance.subscription_start = Subscription.compute_start( - duration=settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type]['duration']) + duration=settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type]['duration'], + user=form.instance.member) form.instance.subscription_end = Subscription.compute_end( duration=settings.SITH_SUBSCRIPTIONS[form.instance.subscription_type]['duration'], - start=form.instance.subscription_start + start=form.instance.subscription_start, + user=form.instance.member ) return super(NewSubscription, self).form_valid(form)