diff --git a/pythonpro/core/facade.py b/pythonpro/core/facade.py index 49e40402..4838d259 100644 --- a/pythonpro/core/facade.py +++ b/pythonpro/core/facade.py @@ -1,3 +1,5 @@ +from datetime import datetime + from rolepermissions.checkers import has_role from rolepermissions.roles import assign_role, remove_role @@ -79,6 +81,11 @@ def promote_to_client(user: User) -> None: remove_role(user, 'lead') +def find_leads_by_date_joined_interval(begin: datetime, end: datetime): + return list(user for user in User.objects.filter(date_joined__gte=begin, date_joined__lte=end).all() if + not has_role(user, ['client', 'member'])) + + def find_user_by_email(email: str): return User.objects.filter(email=email).get() diff --git a/pythonpro/facade.py b/pythonpro/facade.py index d1d98fb8..c597424c 100644 --- a/pythonpro/facade.py +++ b/pythonpro/facade.py @@ -9,6 +9,7 @@ from pythonpro.core import facade as _core_facade from pythonpro.core.models import User as _User from pythonpro.mailchimp import facade as _mailchimp_facade +from pythonpro.payments import facade as _payments_facade UserCreationException = _core_facade.UserCreationException # exposing exception on Facade @@ -110,3 +111,18 @@ def find_user_by_id(user_id: int) -> _User: :return: """ return _core_facade.find_user_by_id(user_id) + + +def run_pytools_promotion_campaign() -> int: + """ + Run pytools campaign for users registered 7 weeks ago + :return: number of user's marked for promotion + """ + begin, end = _payments_facade.calculate_7th_week_before_promotion() + promotion_users = _core_facade.find_leads_by_date_joined_interval(begin, end) + for user in promotion_users: + try: + _mailchimp_facade.tag_as(user.email, 'pytools-promotion') + except _MailChimpError: + pass + return len(promotion_users) diff --git a/pythonpro/payments/facade.py b/pythonpro/payments/facade.py index a86f0de1..12d5048d 100644 --- a/pythonpro/payments/facade.py +++ b/pythonpro/payments/facade.py @@ -59,7 +59,16 @@ def is_on_pytools_promotion_season(creation: datetime) -> bool: :param creation: datetime of creation :return: boolean indication if its os promotion period or not """ + creation_begin, creation_end = calculate_7th_week_before_promotion() + return creation_begin <= creation <= creation_end + + +def calculate_7th_week_before_promotion() -> Tuple[datetime, datetime]: + """ + Calculate 7th week before promotion. Useful to know user created on that period + :return: Tuple where first item is the interval's begin and second is the interval's end + """ promotion_begin, _ = calculate_pytools_promotion_interval() creation_begin = promotion_begin + relativedelta(weekday=MO(-8)) creation_end = creation_begin + relativedelta(days=6, hour=23, minute=59, second=59) - return creation_begin <= creation <= creation_end + return creation_begin, creation_end diff --git a/pythonpro/payments/management/__init__.py b/pythonpro/payments/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pythonpro/payments/management/commands/__init__.py b/pythonpro/payments/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pythonpro/payments/management/commands/pytools_promotion.py b/pythonpro/payments/management/commands/pytools_promotion.py new file mode 100644 index 00000000..1de72287 --- /dev/null +++ b/pythonpro/payments/management/commands/pytools_promotion.py @@ -0,0 +1,14 @@ +from django.core.management import BaseCommand + +from pythonpro import facade + + +class Command(BaseCommand): + help = 'Mark users for pytools 4 day promotion' + + def add_arguments(self, parser): + pass + + def handle(self, *args, **options): + promotion_users = facade.run_pytools_promotion_campaign() + self.stdout.write(self.style.SUCCESS(f'Successfully marked {promotion_users} users for promotions')) diff --git a/pythonpro/payments/tests/test_pytools_promotion_cli.py b/pythonpro/payments/tests/test_pytools_promotion_cli.py new file mode 100644 index 00000000..57f006c7 --- /dev/null +++ b/pythonpro/payments/tests/test_pytools_promotion_cli.py @@ -0,0 +1,8 @@ +from django.core.management import call_command + + +def test_pytools_command(mocker): + mock = mocker.patch( + 'pythonpro.payments.management.commands.pytools_promotion.facade.run_pytools_promotion_campaign') + call_command('pytools_promotion') + mock.assert_called_once_with() diff --git a/pythonpro/tests/test_pytools_promotion.py b/pythonpro/tests/test_pytools_promotion.py new file mode 100644 index 00000000..2f7e37a2 --- /dev/null +++ b/pythonpro/tests/test_pytools_promotion.py @@ -0,0 +1,62 @@ +from datetime import datetime + +import pytz +from freezegun import freeze_time +from model_mommy import mommy +from rolepermissions.roles import assign_role + +from pythonpro import facade + + +def test_leads_in_promotion_period(db, django_user_model, mocker): + dts = (datetime(2019, 6, day, tzinfo=pytz.utc) for day in range(3, 10)) + tag_as_mock = mocker.patch('pythonpro.facade._mailchimp_facade.tag_as') + users_created_seven_weeks_ago = [mommy.make(django_user_model, date_joined=d) for d in dts] + for user in users_created_seven_weeks_ago: + assign_role(user, 'lead') + with freeze_time('2019-07-22'): + assert len(users_created_seven_weeks_ago) == facade.run_pytools_promotion_campaign() + for user in users_created_seven_weeks_ago: + tag_as_mock.assert_any_call(user.email, 'pytools-promotion') + + +def test_clients_not_marked_in_promotion_period(db, django_user_model, mocker): + dts = (datetime(2019, 6, day, tzinfo=pytz.utc) for day in range(3, 10)) + tag_as_mock = mocker.patch('pythonpro.facade._mailchimp_facade.tag_as') + users_created_seven_weeks_ago = [mommy.make(django_user_model, date_joined=d) for d in dts] + for user in users_created_seven_weeks_ago: + assign_role(user, 'client') + with freeze_time('2019-07-22'): + assert 0 == facade.run_pytools_promotion_campaign() + assert tag_as_mock.call_count == 0 + + +def test_members_not_marked_in_promotion_period(db, django_user_model, mocker): + dts = (datetime(2019, 6, day, tzinfo=pytz.utc) for day in range(3, 10)) + tag_as_mock = mocker.patch('pythonpro.facade._mailchimp_facade.tag_as') + users_created_seven_weeks_ago = [mommy.make(django_user_model, date_joined=d) for d in dts] + for user in users_created_seven_weeks_ago: + assign_role(user, 'client') + with freeze_time('2019-07-22'): + assert 0 == facade.run_pytools_promotion_campaign() + assert tag_as_mock.call_count == 0 + + +def test_before_promotion_period(db, django_user_model, mocker): + dts = (datetime(2019, 6, day, tzinfo=pytz.utc) for day in range(1, 3)) + tag_as_mock = mocker.patch('pythonpro.facade._mailchimp_facade.tag_as') + for d in dts: + mommy.make(django_user_model, date_joined=d) + with freeze_time('2019-07-22'): + assert 0 == facade.run_pytools_promotion_campaign() + assert tag_as_mock.call_count == 0 + + +def test_after_promotion_period(db, django_user_model, mocker): + dts = (datetime(2019, 6, day, tzinfo=pytz.utc) for day in range(10, 13)) + tag_as_mock = mocker.patch('pythonpro.facade._mailchimp_facade.tag_as') + for d in dts: + mommy.make(django_user_model, date_joined=d) + with freeze_time('2019-07-22'): + assert 0 == facade.run_pytools_promotion_campaign() + assert tag_as_mock.call_count == 0