mirror of
https://github.com/ae-utbm/sith.git
synced 2024-11-21 21:53:30 +00:00
write command test
This commit is contained in:
parent
5a8052ae47
commit
465e0f31d9
@ -1,7 +1,8 @@
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import localdate, now
|
||||||
from model_bakery import seq
|
from model_bakery import seq
|
||||||
from model_bakery.recipe import Recipe, related
|
from model_bakery.recipe import Recipe, related
|
||||||
|
|
||||||
@ -11,13 +12,13 @@ from subscription.models import Subscription
|
|||||||
|
|
||||||
active_subscription = Recipe(
|
active_subscription = Recipe(
|
||||||
Subscription,
|
Subscription,
|
||||||
subscription_start=now() - timedelta(days=30),
|
subscription_start=localdate() - timedelta(days=30),
|
||||||
subscription_end=now() + timedelta(days=30),
|
subscription_end=localdate() + timedelta(days=30),
|
||||||
)
|
)
|
||||||
ended_subscription = Recipe(
|
ended_subscription = Recipe(
|
||||||
Subscription,
|
Subscription,
|
||||||
subscription_start=now() - timedelta(days=60),
|
subscription_start=localdate() - timedelta(days=60),
|
||||||
subscription_end=now() - timedelta(days=30),
|
subscription_end=localdate() - timedelta(days=30),
|
||||||
)
|
)
|
||||||
|
|
||||||
subscriber_user = Recipe(
|
subscriber_user = Recipe(
|
||||||
@ -36,6 +37,17 @@ old_subscriber_user = Recipe(
|
|||||||
)
|
)
|
||||||
"""A user with an ended subscription."""
|
"""A user with an ended subscription."""
|
||||||
|
|
||||||
|
__inactivity = localdate() - settings.SITH_ACCOUNT_INACTIVITY_DELTA
|
||||||
|
very_old_subscriber_user = old_subscriber_user.extend(
|
||||||
|
subscriptions=related(
|
||||||
|
ended_subscription.extend(
|
||||||
|
subscription_start=__inactivity - relativedelta(months=6, days=1),
|
||||||
|
subscription_end=__inactivity - relativedelta(days=1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"""A user which subscription ended enough time ago to be considered as inactive."""
|
||||||
|
|
||||||
ae_board_membership = Recipe(
|
ae_board_membership = Recipe(
|
||||||
Membership,
|
Membership,
|
||||||
start_date=now() - timedelta(days=30),
|
start_date=now() - timedelta(days=30),
|
||||||
|
@ -7,12 +7,15 @@ from django.test import Client, TestCase
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from model_bakery import baker, seq
|
from model_bakery import baker, seq
|
||||||
from model_bakery.recipe import Recipe, related
|
from model_bakery.recipe import Recipe
|
||||||
|
|
||||||
from core.baker_recipes import old_subscriber_user, subscriber_user
|
from core.baker_recipes import (
|
||||||
|
old_subscriber_user,
|
||||||
|
subscriber_user,
|
||||||
|
very_old_subscriber_user,
|
||||||
|
)
|
||||||
from core.models import User
|
from core.models import User
|
||||||
from counter.models import Counter, Refilling, Selling
|
from counter.models import Counter, Refilling, Selling
|
||||||
from subscription.models import Subscription
|
|
||||||
|
|
||||||
|
|
||||||
class TestSearchUsers(TestCase):
|
class TestSearchUsers(TestCase):
|
||||||
@ -121,9 +124,6 @@ class TestFilterInactive(TestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
time_active = now() - settings.SITH_ACCOUNT_INACTIVITY_DELTA + timedelta(days=1)
|
time_active = now() - settings.SITH_ACCOUNT_INACTIVITY_DELTA + timedelta(days=1)
|
||||||
time_inactive = time_active - timedelta(days=3)
|
time_inactive = time_active - timedelta(days=3)
|
||||||
very_old_subscriber = old_subscriber_user.extend(
|
|
||||||
subscriptions=related(Recipe(Subscription, subscription_end=time_inactive))
|
|
||||||
)
|
|
||||||
counter, seller = baker.make(Counter), baker.make(User)
|
counter, seller = baker.make(Counter), baker.make(User)
|
||||||
sale_recipe = Recipe(
|
sale_recipe = Recipe(
|
||||||
Selling,
|
Selling,
|
||||||
@ -137,7 +137,7 @@ class TestFilterInactive(TestCase):
|
|||||||
baker.make(User),
|
baker.make(User),
|
||||||
subscriber_user.make(),
|
subscriber_user.make(),
|
||||||
old_subscriber_user.make(),
|
old_subscriber_user.make(),
|
||||||
*very_old_subscriber.make(_quantity=3),
|
*very_old_subscriber_user.make(_quantity=3),
|
||||||
]
|
]
|
||||||
sale_recipe.make(customer=cls.users[3].customer, date=time_active)
|
sale_recipe.make(customer=cls.users[3].customer, date=time_active)
|
||||||
baker.make(
|
baker.make(
|
||||||
|
@ -4,7 +4,7 @@ from smtplib import SMTPException
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.db.models import Exists, OuterRef, Subquery
|
from django.db.models import Exists, OuterRef, QuerySet, Subquery
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.timezone import localdate, now
|
from django.utils.timezone import localdate, now
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
@ -26,23 +26,7 @@ class Command(BaseCommand):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
ongoing_dump_operation = AccountDump.objects.ongoing().filter(
|
users = list(self._get_users())
|
||||||
customer__user=OuterRef("pk")
|
|
||||||
)
|
|
||||||
users = list(
|
|
||||||
User.objects
|
|
||||||
.filter_inactive()
|
|
||||||
.filter(customer__amount__gt=0)
|
|
||||||
.exclude(Exists(ongoing_dump_operation))
|
|
||||||
.annotate(
|
|
||||||
last_subscription_date=Subquery(
|
|
||||||
Subscription.objects.filter(member=OuterRef("pk"))
|
|
||||||
.order_by("-subscription_end")
|
|
||||||
.values("subscription_end")[:1]
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.select_related("customer")
|
|
||||||
)
|
|
||||||
self.stdout.write(f"{len(users)} users will be warned of their account dump")
|
self.stdout.write(f"{len(users)} users will be warned of their account dump")
|
||||||
dumps = []
|
dumps = []
|
||||||
for user in users:
|
for user in users:
|
||||||
@ -57,6 +41,25 @@ class Command(BaseCommand):
|
|||||||
AccountDump.objects.bulk_create(dumps)
|
AccountDump.objects.bulk_create(dumps)
|
||||||
self.stdout.write("Finished !")
|
self.stdout.write("Finished !")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_users() -> QuerySet[User]:
|
||||||
|
ongoing_dump_operation = AccountDump.objects.ongoing().filter(
|
||||||
|
customer__user=OuterRef("pk")
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
User.objects.filter_inactive()
|
||||||
|
.filter(customer__amount__gt=0)
|
||||||
|
.exclude(Exists(ongoing_dump_operation))
|
||||||
|
.annotate(
|
||||||
|
last_subscription_date=Subquery(
|
||||||
|
Subscription.objects.filter(member=OuterRef("pk"))
|
||||||
|
.order_by("-subscription_end")
|
||||||
|
.values("subscription_end")[:1]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.select_related("customer")
|
||||||
|
)
|
||||||
|
|
||||||
def _send_mail(self, user: User) -> bool:
|
def _send_mail(self, user: User) -> bool:
|
||||||
"""Send the warning email to the given user.
|
"""Send the warning email to the given user.
|
||||||
|
|
||||||
|
@ -1,7 +1,65 @@
|
|||||||
import pytest
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core import mail
|
||||||
|
from django.core.management import call_command
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from model_bakery import baker
|
||||||
|
from model_bakery.recipe import Recipe
|
||||||
|
|
||||||
|
from core.baker_recipes import subscriber_user, very_old_subscriber_user
|
||||||
|
from counter.management.commands.dump_warning_mail import Command
|
||||||
|
from counter.models import AccountDump, Customer, Refilling
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
class TestAccountDumpWarningMailCommand(TestCase):
|
||||||
def test_account_dump():
|
@classmethod
|
||||||
# TODO write the fucking test
|
def setUpTestData(cls):
|
||||||
pass
|
# delete existing customers to avoid side effect
|
||||||
|
Customer.objects.all().delete()
|
||||||
|
refill_recipe = Recipe(Refilling, amount=10)
|
||||||
|
cls.notified_users = very_old_subscriber_user.make(_quantity=3)
|
||||||
|
inactive_date = (
|
||||||
|
now() - settings.SITH_ACCOUNT_INACTIVITY_DELTA - timedelta(days=1)
|
||||||
|
)
|
||||||
|
refill_recipe.make(
|
||||||
|
customer=(u.customer for u in cls.notified_users),
|
||||||
|
date=inactive_date,
|
||||||
|
_quantity=len(cls.notified_users),
|
||||||
|
)
|
||||||
|
cls.not_notified_users = [
|
||||||
|
subscriber_user.make(),
|
||||||
|
very_old_subscriber_user.make(), # inactive, but account already empty
|
||||||
|
very_old_subscriber_user.make(), # inactive, but with a recent transaction
|
||||||
|
very_old_subscriber_user.make(), # inactive, but already warned
|
||||||
|
]
|
||||||
|
refill_recipe.make(
|
||||||
|
customer=cls.not_notified_users[2].customer, date=now() - timedelta(days=1)
|
||||||
|
)
|
||||||
|
refill_recipe.make(
|
||||||
|
customer=cls.not_notified_users[3].customer, date=inactive_date
|
||||||
|
)
|
||||||
|
baker.make(
|
||||||
|
AccountDump,
|
||||||
|
customer=cls.not_notified_users[3].customer,
|
||||||
|
dump_operation=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_user_selection(self):
|
||||||
|
"""Test that the user to warn are well selected."""
|
||||||
|
users = list(Command._get_users())
|
||||||
|
assert len(users) == 3
|
||||||
|
assert set(users) == set(self.notified_users)
|
||||||
|
|
||||||
|
def test_command(self):
|
||||||
|
"""The actual command test."""
|
||||||
|
call_command("dump_warning_mail")
|
||||||
|
# 1 already existing + 3 new account dump objects
|
||||||
|
assert AccountDump.objects.count() == 4
|
||||||
|
sent_mails = list(mail.outbox)
|
||||||
|
assert len(sent_mails) == 3
|
||||||
|
target_emails = {u.email for u in self.notified_users}
|
||||||
|
for sent in sent_mails:
|
||||||
|
assert len(sent.to) == 1
|
||||||
|
assert sent.to[0] in target_emails
|
||||||
|
Loading…
Reference in New Issue
Block a user