mirror of
https://github.com/pretix/pretix.git
synced 2026-08-15 11:36:27 +00:00
Order creation API: Allow to send emails
This commit is contained in:
@@ -737,8 +737,6 @@ Creating orders
|
||||
* does not allow to pass data to plugins and will therefore cause issues with some plugins like the shipping
|
||||
module
|
||||
|
||||
* does not send order confirmations via email
|
||||
|
||||
* does not support reverse charge taxation
|
||||
|
||||
* does not support file upload questions
|
||||
@@ -809,6 +807,8 @@ Creating orders
|
||||
* ``tax_rule``
|
||||
|
||||
* ``force`` (optional). If set to ``true``, quotas will be ignored.
|
||||
* ``send_mail`` (optional). If set to ``true``, the same emails will be sent as for a regular order. Defaults to
|
||||
``false``.
|
||||
|
||||
If you want to use add-on products, you need to set the ``positionid`` fields of all positions manually
|
||||
to incrementing integers starting with ``1``. Then, you can reference one of these
|
||||
|
||||
@@ -552,11 +552,13 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
||||
consume_carts = serializers.ListField(child=serializers.CharField(), required=False)
|
||||
force = serializers.BooleanField(default=False, required=False)
|
||||
payment_date = serializers.DateTimeField(required=False, allow_null=True)
|
||||
send_mail = serializers.BooleanField(default=False, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = ('code', 'status', 'testmode', 'email', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
|
||||
'invoice_address', 'positions', 'checkin_attention', 'payment_info', 'payment_date', 'consume_carts', 'force')
|
||||
'invoice_address', 'positions', 'checkin_attention', 'payment_info', 'payment_date', 'consume_carts',
|
||||
'force', 'send_mail')
|
||||
|
||||
def validate_payment_provider(self, pp):
|
||||
if pp not in self.context['event'].get_payment_providers():
|
||||
@@ -632,6 +634,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
||||
payment_info = validated_data.pop('payment_info', '{}')
|
||||
payment_date = validated_data.pop('payment_date', now())
|
||||
force = validated_data.pop('force', False)
|
||||
self._send_mail = validated_data.pop('send_mail', False)
|
||||
|
||||
if 'invoice_address' in validated_data:
|
||||
iadata = validated_data.pop('invoice_address')
|
||||
|
||||
@@ -41,7 +41,8 @@ from pretix.base.services.invoices import (
|
||||
)
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, approve_order, cancel_order, deny_order,
|
||||
OrderChangeManager, OrderError, _order_placed_email,
|
||||
_order_placed_email_attendee, approve_order, cancel_order, deny_order,
|
||||
extend_order, mark_order_expired, mark_order_refunded,
|
||||
)
|
||||
from pretix.base.services.pricing import get_price
|
||||
@@ -431,6 +432,7 @@ class OrderViewSet(viewsets.ModelViewSet):
|
||||
serializer.is_valid(raise_exception=True)
|
||||
with transaction.atomic():
|
||||
self.perform_create(serializer)
|
||||
send_mail = serializer._send_mail
|
||||
order = serializer.instance
|
||||
serializer = OrderSerializer(order, context=serializer.context)
|
||||
|
||||
@@ -445,8 +447,42 @@ class OrderViewSet(viewsets.ModelViewSet):
|
||||
(order.event.settings.get('invoice_generate') == 'True') or
|
||||
(order.event.settings.get('invoice_generate') == 'paid' and order.status == Order.STATUS_PAID)
|
||||
) and not order.invoices.last()
|
||||
invoice = None
|
||||
if gen_invoice:
|
||||
generate_invoice(order, trigger_pdf=True)
|
||||
invoice = generate_invoice(order, trigger_pdf=True)
|
||||
|
||||
if send_mail:
|
||||
payment = order.payments.last()
|
||||
free_flow = (
|
||||
payment and order.total == Decimal('0.00') and order.status == Order.STATUS_PAID and
|
||||
not order.require_approval and payment.provider == "free"
|
||||
)
|
||||
if free_flow:
|
||||
email_template = request.event.settings.mail_text_order_free
|
||||
log_entry = 'pretix.event.order.email.order_free'
|
||||
email_attendees = request.event.settings.mail_send_order_free_attendee
|
||||
email_attendees_template = request.event.settings.mail_text_order_free_attendee
|
||||
else:
|
||||
email_template = request.event.settings.mail_text_order_placed
|
||||
log_entry = 'pretix.event.order.email.order_placed'
|
||||
email_attendees = request.event.settings.mail_send_order_placed_attendee
|
||||
email_attendees_template = request.event.settings.mail_text_order_placed_attendee
|
||||
|
||||
_order_placed_email(
|
||||
request.event, order, payment.payment_provider if payment else None, email_template,
|
||||
log_entry, invoice, payment
|
||||
)
|
||||
if email_attendees:
|
||||
for p in order.positions.all():
|
||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
|
||||
_order_placed_email_attendee(request.event, order, p, email_attendees_template, log_entry)
|
||||
|
||||
if not free_flow and order.status == Order.STATUS_PAID and payment:
|
||||
payment._send_paid_mail(invoice, None, '')
|
||||
if self.request.event.settings.mail_send_order_paid_attendee:
|
||||
for p in order.positions.all():
|
||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
|
||||
payment._send_paid_mail_attendee(p, None)
|
||||
|
||||
headers = self.get_success_headers(serializer.data)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
|
||||
|
||||
@@ -2753,6 +2753,78 @@ def test_order_create_with_seat_consumed_from_cart(token_client, organizer, even
|
||||
assert p.seat == seat
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_send_no_emails(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
djmail.outbox = []
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_send_emails(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['send_mail'] = True
|
||||
djmail.outbox = []
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Your order: {}".format(resp.data['code'])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_send_emails_free(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['price'] = '0.00'
|
||||
res['payment_provider'] = 'free'
|
||||
del res['fees']
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['send_mail'] = True
|
||||
djmail.outbox = []
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
print(resp.data)
|
||||
assert resp.status_code == 201
|
||||
assert len(djmail.outbox) == 1
|
||||
assert djmail.outbox[0].subject == "Your order: {}".format(resp.data['code'])
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_create_send_emails_paid(token_client, organizer, event, item, quota, question):
|
||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||
res['positions'][0]['item'] = item.pk
|
||||
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||
res['send_mail'] = True
|
||||
res['status'] = 'p'
|
||||
djmail.outbox = []
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
), format='json', data=res
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
assert len(djmail.outbox) == 2
|
||||
assert djmail.outbox[0].subject == "Your order: {}".format(resp.data['code'])
|
||||
assert djmail.outbox[1].subject == "Payment received for your order: {}".format(resp.data['code'])
|
||||
|
||||
|
||||
REFUND_CREATE_PAYLOAD = {
|
||||
"state": "created",
|
||||
"provider": "manual",
|
||||
|
||||
Reference in New Issue
Block a user