diff --git a/doc/api/resources/sendmail_rules.rst b/doc/api/resources/sendmail_rules.rst index d90d1a28df..40597be9c2 100644 --- a/doc/api/resources/sendmail_rules.rst +++ b/doc/api/resources/sendmail_rules.rst @@ -18,8 +18,15 @@ subject multi-lingual string The subject of template multi-lingual string The body of the email all_products boolean If ``true``, the email is sent to buyers of all products limit_products list of integers List of product IDs, if ``all_products`` is not set -include_pending boolean If ``true``, the email is sent to pending orders. If ``false``, +[**DEPRECATED**] include_pending boolean If ``true``, the email is sent to pending orders. If ``false``, only paid orders are considered. +restrict_to_status list List of order states to restrict recipients to. Valid + entries are ``p`` for paid, ``e`` for expired, ``c`` for canceled, + ``n__pending_approval`` for pending approval, + ``n__not_pending_approval_and_not_valid_if_pending`` for payment pending, + ``n__valid_if_pending`` for payment pending but already confirmed, + and ``n__pending_overdue`` for pending with payment overdue. + The default is ``["p", "n__valid_if_pending"]``. date_is_absolute boolean If ``true``, the email is set at a specific point in time. send_date datetime If ``date_is_absolute`` is set: Date and time to send the email. send_offset_days integer If ``date_is_absolute`` is not set, this is the number of days @@ -37,7 +44,10 @@ send_to string Can be ``"order or ``"both"``. date. Otherwise it is relative to the event start date. ===================================== ========================== ======================================================= +.. versionchanged:: 2023.7 + The ``include_pending`` field has been deprecated. + The ``restrict_to_status`` field has been added. Endpoints --------- @@ -74,7 +84,11 @@ Endpoints "template": {"en": "Don't forget your tickets, download them at {url}"}, "all_products": true, "limit_products": [], - "include_pending": false, + "restrict_to_status": [ + "p", + "n__not_pending_approval_and_not_valid_if_pending", + "n__valid_if_pending" + ], "send_date": null, "send_offset_days": 1, "send_offset_time": "18:00", @@ -120,7 +134,11 @@ Endpoints "template": {"en": "Don't forget your tickets, download them at {url}"}, "all_products": true, "limit_products": [], - "include_pending": false, + "restrict_to_status": [ + "p", + "n__not_pending_approval_and_not_valid_if_pending", + "n__valid_if_pending" + ], "send_date": null, "send_offset_days": 1, "send_offset_time": "18:00", @@ -157,7 +175,11 @@ Endpoints "template": {"en": "Don't forget your tickets, download them at {url}"}, "all_products": true, "limit_products": [], - "include_pending": false, + "restrict_to_status": [ + "p", + "n__not_pending_approval_and_not_valid_if_pending", + "n__valid_if_pending" + ], "send_date": null, "send_offset_days": 1, "send_offset_time": "18:00", @@ -182,7 +204,11 @@ Endpoints "template": {"en": "Don't forget your tickets, download them at {url}"}, "all_products": true, "limit_products": [], - "include_pending": false, + "restrict_to_status": [ + "p", + "n__not_pending_approval_and_not_valid_if_pending", + "n__valid_if_pending" + ], "send_date": null, "send_offset_days": 1, "send_offset_time": "18:00", @@ -235,7 +261,11 @@ Endpoints "template": {"en": "Don't forget your tickets, download them at {url}"}, "all_products": true, "limit_products": [], - "include_pending": false, + "restrict_to_status": [ + "p", + "n__not_pending_approval_and_not_valid_if_pending", + "n__valid_if_pending" + ], "send_date": null, "send_offset_days": 1, "send_offset_time": "18:00", diff --git a/src/pretix/plugins/sendmail/api.py b/src/pretix/plugins/sendmail/api.py index 825e9d620c..f3a31bab39 100644 --- a/src/pretix/plugins/sendmail/api.py +++ b/src/pretix/plugins/sendmail/api.py @@ -26,17 +26,33 @@ from rest_framework import viewsets from pretix.api.pagination import TotalOrderingFilter from pretix.api.serializers.i18n import I18nAwareModelSerializer +from pretix.base.models import Order from pretix.plugins.sendmail.models import Rule class RuleSerializer(I18nAwareModelSerializer): class Meta: model = Rule - fields = ['id', 'subject', 'template', 'all_products', 'limit_products', 'include_pending', + fields = ['id', 'subject', 'template', 'all_products', 'limit_products', 'restrict_to_status', 'send_date', 'send_offset_days', 'send_offset_time', 'date_is_absolute', 'offset_to_event_end', 'offset_is_after', 'send_to', 'enabled'] read_only_fields = ['id'] + def to_internal_value(self, data): + if "restrict_to_status" not in data: + if "include_pending" in data: + if data["include_pending"]: + data['restrict_to_status'] = [ + Order.STATUS_PAID, + 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending' + ] + else: + data['restrict_to_status'] = [Order.STATUS_PAID, 'n__valid_if_pending'] + else: + data['restrict_to_status'] = [Order.STATUS_PAID, 'n__valid_if_pending'] + return super().to_internal_value(data) + def validate(self, data): data = super().validate(data) @@ -56,6 +72,22 @@ class RuleSerializer(I18nAwareModelSerializer): if not full_data.get('limit_products'): raise ValidationError('limit_products is required when all_products=False') + rts = full_data.get('restrict_to_status') + if not rts or rts == []: + raise ValidationError('restrict_to_status needs at least one value') + elif rts: + for s in rts: + if s not in [ + Order.STATUS_PAID, + Order.STATUS_EXPIRED, + Order.STATUS_CANCELED, + 'n__valid_if_pending', + 'n__pending_overdue', + 'n__pending_approval', + 'n__not_pending_approval_and_not_valid_if_pending', + ]: + raise ValidationError(f'status {s} not allowed: restrict_to_status may only include valid states') + return full_data def save(self, **kwargs): @@ -66,7 +98,7 @@ with scopes_disabled(): class RuleFilter(FilterSet): class Meta: model = Rule - fields = ['id', 'all_products', 'include_pending', 'date_is_absolute', + fields = ['id', 'all_products', 'date_is_absolute', 'offset_to_event_end', 'offset_is_after', 'send_to', 'enabled'] diff --git a/src/pretix/plugins/sendmail/forms.py b/src/pretix/plugins/sendmail/forms.py index 500be2e800..8fc3b78382 100644 --- a/src/pretix/plugins/sendmail/forms.py +++ b/src/pretix/plugins/sendmail/forms.py @@ -167,7 +167,7 @@ class WaitinglistMailForm(BaseMailForm): class OrderMailForm(BaseMailForm): recipients = forms.ChoiceField( - label=pgettext_lazy('sendmail_from', 'Send to'), + label=pgettext_lazy('sendmail_form', 'Send to'), widget=forms.RadioSelect, initial='orders', choices=[] @@ -186,7 +186,7 @@ class OrderMailForm(BaseMailForm): required=False ) checkin_lists = SafeModelMultipleChoiceField(queryset=CheckinList.objects.none(), required=False) # overridden later - not_checked_in = forms.BooleanField(label=pgettext_lazy('sendmail_from', 'Restrict to recipients without check-in'), required=False) + not_checked_in = forms.BooleanField(label=pgettext_lazy('sendmail_form', 'Restrict to recipients without check-in'), required=False) subevent = forms.ModelChoiceField( SubEvent.objects.none(), label=pgettext_lazy('sendmail_form', 'Restrict to a specific event date'), @@ -255,14 +255,14 @@ class OrderMailForm(BaseMailForm): ('overdue', _('pending with payment overdue')) ) self.fields['sendto'] = forms.MultipleChoiceField( - label=pgettext_lazy('sendmail_from', 'Restrict to orders with status'), + label=pgettext_lazy('sendmail_form', 'Restrict to orders with status'), widget=forms.CheckboxSelectMultiple( attrs={'class': 'scrolling-multiple-choice no-search'} ), choices=choices ) if not self.initial.get('sendto'): - self.initial['sendto'] = ['p', 'na', 'valid_if_pending'] + self.initial['sendto'] = ['p', 'valid_if_pending'] elif 'n' in self.initial['sendto']: self.initial['sendto'].append('pa') self.initial['sendto'].append('na') @@ -280,11 +280,11 @@ class OrderMailForm(BaseMailForm): 'event': event.slug, 'organizer': event.organizer.slug, }), - 'data-placeholder': pgettext_lazy('sendmail_from', 'Restrict to recipients with check-in on list') + 'data-placeholder': pgettext_lazy('sendmail_form', 'Restrict to recipients with check-in on list') } ) self.fields['checkin_lists'].widget.choices = self.fields['checkin_lists'].choices - self.fields['checkin_lists'].label = pgettext_lazy('sendmail_from', 'Restrict to recipients with check-in on list') + self.fields['checkin_lists'].label = pgettext_lazy('sendmail_form', 'Restrict to recipients with check-in on list') if event.has_subevents: self.fields['subevent'].queryset = event.subevents.all() @@ -311,7 +311,7 @@ class RuleForm(FormPlaceholderMixin, I18nModelForm): fields = ['subject', 'template', 'attach_ical', 'send_date', 'send_offset_days', 'send_offset_time', - 'include_pending', 'all_products', 'limit_products', + 'all_products', 'limit_products', 'restrict_to_status', 'send_to', 'enabled'] field_classes = { @@ -375,6 +375,25 @@ class RuleForm(FormPlaceholderMixin, I18nModelForm): self._set_field_placeholders('subject', ['event', 'order']) self._set_field_placeholders('template', ['event', 'order']) + choices = [(e, l) for e, l in Order.STATUS_CHOICE if e != 'n'] + choices.insert(0, ('n__valid_if_pending', _('payment pending but already confirmed'))) + choices.insert(0, ('n__not_pending_approval_and_not_valid_if_pending', + _('payment pending (except unapproved or already confirmed)'))) + choices.insert(0, ('n__pending_approval', _('approval pending'))) + if not self.event.settings.get('payment_term_expire_automatically', as_type=bool): + choices.append( + ('p__overdue', _('pending with payment overdue')) + ) + self.fields['restrict_to_status'] = forms.MultipleChoiceField( + label=pgettext_lazy('sendmail_from', 'Restrict to orders with status'), + widget=forms.CheckboxSelectMultiple( + attrs={'class': 'scrolling-multiple-choice no-search'} + ), + choices=choices + ) + if not self.initial.get('restrict_to_status'): + self.initial['restrict_to_status'] = ['p', 'n__valid_if_pending'] + def clean(self): d = super().clean() diff --git a/src/pretix/plugins/sendmail/migrations/0004_rule_restrict_to_status.py b/src/pretix/plugins/sendmail/migrations/0004_rule_restrict_to_status.py new file mode 100644 index 0000000000..0b0fc187a7 --- /dev/null +++ b/src/pretix/plugins/sendmail/migrations/0004_rule_restrict_to_status.py @@ -0,0 +1,33 @@ +from django.db import migrations + +import pretix.base.models.fields + + +def migrate_status_rules(apps, schema_editor): + rule_model = apps.get_model("sendmail", "Rule") + for r in rule_model.objects.all(): + r.restrict_to_status = ['p', 'n__valid_if_pending'] + if r.include_pending: + r.restrict_to_status.append('n__not_pending_approval_and_not_valid_if_pending') + r.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('sendmail', '0003_rule_attach_ical'), + ('pretixbase', '0241_itemmetaproperties_required_values'), + ] + + operations = [ + migrations.AddField( + model_name='rule', + name='restrict_to_status', + field=pretix.base.models.fields.MultiStringField(default=['p', 'n__valid_if_pending']), + ), + migrations.RunPython(migrate_status_rules), + migrations.RemoveField( + model_name='rule', + name='include_pending', + ), + ] diff --git a/src/pretix/plugins/sendmail/models.py b/src/pretix/plugins/sendmail/models.py index 920420de7b..2c250ed108 100644 --- a/src/pretix/plugins/sendmail/models.py +++ b/src/pretix/plugins/sendmail/models.py @@ -26,7 +26,7 @@ from django.db import models from django.db.models import Exists, OuterRef, Q from django.utils import timezone from django.utils.formats import date_format -from django.utils.timezone import make_aware +from django.utils.timezone import make_aware, now from django.utils.translation import gettext_lazy as _, ngettext from django_scopes import ScopedManager from i18nfield.fields import I18nCharField, I18nTextField @@ -34,7 +34,7 @@ from i18nfield.fields import I18nCharField, I18nTextField from pretix.base.email import get_email_context from pretix.base.i18n import language from pretix.base.models import ( - Event, InvoiceAddress, Item, Order, OrderPosition, SubEvent, + Event, InvoiceAddress, Item, Order, OrderPosition, SubEvent, fields, ) from pretix.base.models.base import LoggingMixin from pretix.base.services.mail import SendMailException @@ -126,13 +126,16 @@ class ScheduledMail(models.Model): Exists(OrderPosition.objects.filter(order=OuterRef('pk'), item_id__in=limit_products)) ) - if self.rule.include_pending: - status_q = Q(status__in=[Order.STATUS_PAID, Order.STATUS_PENDING]) - else: - status_q = Q( - Q(status=Order.STATUS_PAID) | - Q(status=Order.STATUS_PENDING, valid_if_pending=True) - ) + status_q = Q(status__in=self.rule.restrict_to_status) + if 'n__pending_approval' in self.rule.restrict_to_status: + status_q |= Q(status=Order.STATUS_PENDING, require_approval=True) + if 'n__not_pending_approval_and_not_valid_if_pending' in self.rule.restrict_to_status: + status_q |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=False) + if 'n__valid_if_pending' in self.rule.restrict_to_status: + status_q |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=True) + if 'n__pending_overdue' in self.rule.restrict_to_status: + status_q |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=False, + expires__lt=now()) if self.last_successful_order_id: orders = orders.filter( @@ -141,7 +144,6 @@ class ScheduledMail(models.Model): orders = orders.filter( status_q, - require_approval=False, ).order_by('pk').select_related('invoice_address').prefetch_related('positions') send_to_orders = self.rule.send_to in (Rule.CUSTOMERS, Rule.BOTH) @@ -212,10 +214,9 @@ class Rule(models.Model, LoggingMixin): all_products = models.BooleanField(default=True, verbose_name=_('All products')) limit_products = models.ManyToManyField(Item, blank=True, verbose_name=_('Limit products')) - include_pending = models.BooleanField( - default=False, - verbose_name=_('Include pending orders'), - help_text=_('By default, only paid orders will receive the email') + restrict_to_status = fields.MultiStringField( + verbose_name=_("Restrict to orders with status"), + default=['p', 'n__valid_if_pending'], ) attach_ical = models.BooleanField( diff --git a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html index ca510197af..b9c13b042e 100644 --- a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html +++ b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html @@ -27,7 +27,7 @@
diff --git a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html index 14f33bdb90..3a4f779c78 100644 --- a/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html +++ b/src/pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html @@ -41,7 +41,7 @@ diff --git a/src/pretix/plugins/sendmail/views.py b/src/pretix/plugins/sendmail/views.py index 7d42e8dbac..594292fe93 100644 --- a/src/pretix/plugins/sendmail/views.py +++ b/src/pretix/plugins/sendmail/views.py @@ -345,7 +345,7 @@ class OrderSendView(BaseSenderView): qs = Order.objects.filter(event=self.request.event) statusq = Q(status__in=form.cleaned_data['sendto']) if 'overdue' in form.cleaned_data['sendto']: - statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now()) + statusq |= Q(status=Order.STATUS_PENDING, require_approval=False, valid_if_pending=False, expires__lt=now()) if 'pa' in form.cleaned_data['sendto']: statusq |= Q(status=Order.STATUS_PENDING, require_approval=True) if 'na' in form.cleaned_data['sendto']: diff --git a/src/tests/api/test_sendmail.py b/src/tests/api/test_sendmail.py index 974441d58c..fdcf97f6ec 100644 --- a/src/tests/api/test_sendmail.py +++ b/src/tests/api/test_sendmail.py @@ -39,7 +39,7 @@ TEST_RULE_RES = { 'template': {'en': 'foo'}, 'all_products': True, 'limit_products': [], - 'include_pending': False, + "restrict_to_status": ['p', 'n__valid_if_pending'], 'send_date': '2021-07-08T00:00:00Z', 'send_offset_days': None, 'send_offset_time': None, @@ -63,11 +63,11 @@ def test_sendmail_rule_list(token_client, organizer, event, rule): assert res in results assert len(results) == 1 - produces_result = [f'id={rule.id}', 'all_products=true', 'include_pending=false', 'date_is_absolute=true', + produces_result = [f'id={rule.id}', 'all_products=true', 'date_is_absolute=true', 'offset_to_event_end=false', 'offset_is_after=false', 'send_to=orders', 'enabled=true', f'id={rule.id}&enabled=true'] - no_produce_result = ['id=12345', 'all_products=false', 'include_pending=true', 'date_is_absolute=false', + no_produce_result = ['id=12345', 'all_products=false', 'date_is_absolute=false', 'offset_to_event_end=true', 'offset_is_after=true', 'send_to=both', 'send_to=attendees', 'enabled=false', f'id={rule.id}&enabled=false'] @@ -144,7 +144,7 @@ def test_sendmail_rule_create_minimal(token_client, organizer, event): data={ 'subject': {'en': 'meow'}, 'template': {'en': 'creative text here'}, - 'send_date': '2018-03-17T13:31Z', + 'send_date': '2018-03-17T13:31Z' } ) assert r.send_date == datetime.datetime(2018, 3, 17, 13, 31, tzinfo=datetime.timezone.utc) @@ -160,7 +160,7 @@ def test_sendmail_rule_create_full(token_client, organizer, event, item): 'template': {'en': 'foobar'}, 'all_products': False, 'limit_products': [event.items.first().pk], - 'include_pending': True, + "restrict_to_status": ['p', 'n__not_pending_approval_and_not_valid_if_pending', 'n__valid_if_pending'], 'send_offset_days': 3, 'send_offset_time': '09:30', 'date_is_absolute': False, @@ -173,7 +173,7 @@ def test_sendmail_rule_create_full(token_client, organizer, event, item): assert r.all_products is False assert [i.pk for i in r.limit_products.all()] == [event.items.first().pk] - assert r.include_pending is True + assert r.restrict_to_status == ['p', 'n__not_pending_approval_and_not_valid_if_pending', 'n__valid_if_pending'] assert r.send_offset_days == 3 assert r.send_offset_time == datetime.time(9, 30) assert r.date_is_absolute is False @@ -269,6 +269,85 @@ def test_sendmail_rule_create_invalid(token_client, organizer, event): create_rule(token_client, organizer, event, data, expected_failure=True, expected_failure_text=failure) +@scopes_disabled() +@pytest.mark.django_db +def test_sendmail_rule_legacy_field(token_client, organizer, event, rule): + r = create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + 'include_pending': True + } + ) + assert r.restrict_to_status == ['p', 'n__not_pending_approval_and_not_valid_if_pending', 'n__valid_if_pending'] + + r = create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + 'include_pending': False + } + ) + assert r.restrict_to_status == ['p', 'n__valid_if_pending'] + + +@scopes_disabled() +@pytest.mark.django_db +def test_sendmail_rule_restrict_recipients(token_client, organizer, event, rule): + restrictions = ['p', 'e', 'c', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__pending_approval', 'n__valid_if_pending', 'n__pending_overdue'] + for r in restrictions: + result = create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + "restrict_to_status": [r], + }, + expected_failure=False + ) + assert result.restrict_to_status == [r] + + create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + "restrict_to_status": ["foo"], + }, + expected_failure=True, + expected_failure_text="restrict_to_status may only include valid states" + ) + + create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + "restrict_to_status": [], + }, + expected_failure=True, + expected_failure_text="restrict_to_status needs at least one value" + ) + + create_rule( + token_client, organizer, event, + data={ + 'subject': {'en': 'meow'}, + 'template': {'en': 'creative text here'}, + 'send_date': '2018-03-17T13:31Z', + }, + expected_failure=False + ) + + @scopes_disabled() @pytest.mark.django_db def test_sendmail_rule_change(token_client, organizer, event, rule): diff --git a/src/tests/plugins/sendmail/test_rules.py b/src/tests/plugins/sendmail/test_rules.py index c20f0b1a38..8ff6c99870 100644 --- a/src/tests/plugins/sendmail/test_rules.py +++ b/src/tests/plugins/sendmail/test_rules.py @@ -276,12 +276,127 @@ def test_sendmail_rule_send_correct_products(event, order, item, item2): assert djmail.outbox[0].to[0] == p1.attendee_email +@pytest.mark.django_db +@scopes_disabled() +def run_restriction_test(event, order, restrictions_pass=[], restrictions_fail=[]): + for r in restrictions_pass: + djmail.outbox = [] + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), restrict_to_status=[r], + subject='meow', template='meow meow meow') + sendmail_run_rules(None) + + assert len(djmail.outbox) == 1, f"email not sent for {r}" + + for r in restrictions_fail: + djmail.outbox = [] + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), restrict_to_status=[r], + subject='meow', template='meow meow meow') + sendmail_run_rules(None) + + assert len(djmail.outbox) == 0, f"email sent for {r} unexpectedly" + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_paid(event, order): + order.status = Order.STATUS_PAID + order.save() + order.valid_if_pending = False + restrictions_pass = ['p'] + restrictions_fail = ['e', 'c', 'n__not_pending_approval_and_not_valid_if_pending', 'n__pending_approval', + 'n__valid_if_pending', 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_pending(event, order): + order.status = Order.STATUS_PENDING + order.require_approval = False + order.valid_if_pending = False + order.save() + restrictions_pass = ['n__not_pending_approval_and_not_valid_if_pending'] + restrictions_fail = ['p', 'e', 'c', 'n__pending_approval', "n__valid_if_pending", 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_valid_pending(event, order): + order.status = Order.STATUS_PENDING + order.require_approval = False + order.valid_if_pending = True + order.save() + restrictions_pass = ["n__valid_if_pending"] + restrictions_fail = ['p', 'e', 'c', 'n__not_pending_approval_and_not_valid_if_pending', 'n__pending_approval', + 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_approval_pending(event, order): + order.status = Order.STATUS_PENDING + order.require_approval = True + order.valid_if_pending = False + order.save() + restrictions_pass = ['n__pending_approval'] + restrictions_fail = ['p', 'e', 'c', 'n__not_pending_approval_and_not_valid_if_pending', "n__valid_if_pending", + 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_overdue_pending(event, order): + event.settings.payment_term_expire_automatically = False + order.status = Order.STATUS_PENDING + order.require_approval = False + order.valid_if_pending = False + order.expires = order.expires - datetime.timedelta(days=15) + order.save() + restrictions_pass = ['n__pending_overdue', 'n__not_pending_approval_and_not_valid_if_pending'] + restrictions_fail = ['p', 'e', 'c', 'n__pending_approval', "n__valid_if_pending"] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_expired(event, order): + order.status = Order.STATUS_EXPIRED + order.save() + restrictions_pass = ['e'] + restrictions_fail = ['p', 'c', 'n__not_pending_approval_and_not_valid_if_pending', 'n__pending_approval', + 'n__valid_if_pending', 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + +@pytest.mark.django_db +@scopes_disabled() +def test_sendmail_rule_restrictions_status_canceled(event, order): + order.status = Order.STATUS_CANCELED + order.save() + restrictions_pass = ['c'] + restrictions_fail = ['p', 'e', 'n__not_pending_approval_and_not_valid_if_pending', 'n__pending_approval', + 'n__valid_if_pending', 'n__pending_overdue'] + + run_restriction_test(event, order, restrictions_pass, restrictions_fail) + + @pytest.mark.django_db @scopes_disabled() def test_sendmail_rule_send_order_pending(event, order): djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -294,7 +409,8 @@ def test_sendmail_rule_send_order_pending(event, order): def test_sendmail_rule_send_order_pending_excluded(event, order): djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=False, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', "n__valid_if_pending"], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -310,7 +426,8 @@ def test_sendmail_rule_send_order_valid_if_pending(event, order): order.save() djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=False, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', "n__valid_if_pending"], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -330,7 +447,8 @@ def test_sendmail_rule_send_order_status(status, event, order): order.status = status order.save() - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', "n__valid_if_pending"], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -346,7 +464,9 @@ def test_sendmail_rule_send_order_approval(event, order): order.require_approval = True order.save() - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -359,7 +479,9 @@ def test_sendmail_rule_send_order_approval(event, order): def test_sendmail_rule_only_send_once(event, order): djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -375,7 +497,9 @@ def test_sendmail_rule_only_live(event, order): event.live = False event.save() - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='meow meow meow') sendmail_run_rules(None) @@ -386,7 +510,9 @@ def test_sendmail_rule_only_live(event, order): @scopes_disabled() def test_sendmail_rule_disabled(event, order): djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='meow meow meow', enabled=False) sendmail_run_rules(None) @@ -405,7 +531,9 @@ def test_sendmail_context_localization(event, order, pos): ) djmail.outbox = [] - event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), include_pending=True, + event.sendmail_rules.create(send_date=dt_now - datetime.timedelta(hours=1), + restrict_to_status=['p', 'n__not_pending_approval_and_not_valid_if_pending', + 'n__valid_if_pending'], subject='meow', template='Hallo {name_for_salutation}') sendmail_run_rules(None)