Compare commits

...
4 changed files with 201 additions and 50 deletions
+35 -10
View File
@@ -92,9 +92,9 @@ from pretix.base.services.invoices import (
regenerate_invoice, transmit_invoice,
)
from pretix.base.services.orders import (
OrderChangeManager, OrderError, _order_placed_email,
_order_placed_email_attendee, approve_order, cancel_order, deny_order,
extend_order, mark_order_expired, mark_order_refunded, reactivate_order,
OrderChangeManager, OrderError, _attendee_mail_send_helper,
_order_placed_email, approve_order, cancel_order, deny_order, extend_order,
mark_order_expired, mark_order_refunded, reactivate_order,
)
from pretix.base.services.pricing import get_price
from pretix.base.services.tickets import generate
@@ -805,17 +805,42 @@ class EventOrderViewSet(OrderViewSetMixin, viewsets.ModelViewSet):
log_entry, invoice, [payment] if payment else [], is_free=free_flow
)
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, subject_attendees_template,
log_entry, is_free=free_flow)
ev = request.event
# todo re note: order_placed_email for attendees (formerly services/orders _order_placed_email_attendee)
_attendee_mail_send_helper(
event=ev,
order=order,
positions=order.positions.all(),
template=email_attendees_template,
subject=subject_attendees_template,
log_entry_type=log_entry,
attach_tickets=True,
attach_ical=ev.settings.mail_attach_ical and (
not ev.settings.mail_attach_ical_paid_only or
free_flow or
order.valid_if_pending
),
attach_other_files=[a for a in [
ev.settings.get('mail_attachment_new_order', as_type=str, default='')[len('file://'):]
] if a],
)
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)
ev = request.event
# todo re note: paid_mail for attendees (formerly models/orders _send_paid_mail_attendee)
_attendee_mail_send_helper(
event=ev,
order=order,
positions=order.positions.all(),
template=ev.settings.mail_text_order_paid_attendee,
subject=ev.settings.mail_subject_order_paid_attendee,
log_entry_type='pretix.event.order.email.order_paid',
invoices=[],
attach_tickets=True,
attach_ical=ev.settings.mail_attach_ical
)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
+17 -3
View File
@@ -2021,9 +2021,23 @@ class OrderPayment(models.Model):
if send_mail and self.order.sales_channel.identifier in self.order.event.settings.mail_sales_channel_placed_paid:
self._send_paid_mail(invoice if transmit_invoice_mail else None, user, mail_text)
if self.order.event.settings.mail_send_order_paid_attendee:
for p in self.order.positions.all():
if p.addon_to_id is None and p.attendee_email and p.attendee_email != self.order.email:
self._send_paid_mail_attendee(p, user)
# todo re note: paid_mail for attendees (formerly models/orders _send_paid_mail_attendee)
from pretix.base.services.orders import (
_attendee_mail_send_helper,
)
_attendee_mail_send_helper(
event=self.order.event,
order=self.order,
positions=self.order.positions.all(),
template=self.order.event.settings.mail_text_order_paid_attendee,
subject=self.order.event.settings.mail_subject_order_paid_attendee,
log_entry_type='pretix.event.order.email.order_paid',
user=user,
invoices=[],
attach_tickets=True,
attach_ical=self.order.event.settings.mail_attach_ical,
)
if invoice and not transmit_invoice_mail:
transmit_invoice.apply_async(args=(self.order.event_id, invoice.pk, False))
+33 -16
View File
@@ -39,7 +39,8 @@ from pretix.base.models import (
from pretix.base.services.locking import LockTimeoutException
from pretix.base.services.mail import mail
from pretix.base.services.orders import (
OrderChangeManager, OrderError, _cancel_order, _try_auto_refund,
OrderChangeManager, OrderError, _attendee_mail_send_helper, _cancel_order,
_try_auto_refund,
)
from pretix.base.services.tasks import ProfiledEventTask
from pretix.base.services.tax import split_fee_for_taxes
@@ -79,22 +80,38 @@ def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, s
user,
)
for p in positions:
if subevent and p.subevent_id != subevent.id:
continue
# todo before pr ready: (aka note to myself)
# check if we use a checkbox in the form here
# (because before, we didn't check for it and maybe we don't want to here)
# also: do we really want to inform attendees about the refund_amount
# or do we need to because else the template does not work?
_attendee_mail_send_helper(
event=order.event,
order=order,
positions=positions,
template=message,
subject=subject,
log_entry_type='pretix.event.order.email.event_canceled',
user=user,
subevent=subevent,
)
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
email_context = get_email_context(event_or_subevent=p.subevent or order.event,
event=order.event,
refund_amount=refund_amount,
position_or_address=p,
order=order, position=p)
order.send_mail(
subject, message, email_context,
'pretix.event.order.email.event_canceled',
position=p,
user=user
)
# for p in positions:
# if subevent and p.subevent_id != subevent.id:
# continue
#
# if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
# email_context = get_email_context(event_or_subevent=p.subevent or order.event,
# event=order.event,
# refund_amount=refund_amount,
# position_or_address=p,
# order=order, position=p)
# order.send_mail(
# subject, message, email_context,
# 'pretix.event.order.email.event_canceled',
# position=p,
# user=user
# )
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,))
+116 -21
View File
@@ -114,6 +114,76 @@ from pretix.presale.productlist import prepare_item_list_for_shop
from pretix.testutils.middleware import debugflags_var
# todo before pr ready: (aka note to myself)
# think about placing this helper function somewhere better
# also: check those mail send functions, instead of replacing
# maybe we still want to use them here instead of generic send_mail
# and/or maybe we want to generalize this thing to also include order mails
# (let's maybe not rewrite the whole mail logic?!)
# but also, remember to write tests - a whole bunch of tests
def _attendee_mail_send_helper(
event: Event,
order: Order,
positions: list,
template,
subject,
user,
invoices: list = None,
log_entry_type: str = 'pretix.event.order.email.sent',
attach_tickets: bool = False,
attach_ical: bool = False,
attach_other_files: list = None,
subevent: SubEvent = None,
):
parent_op = None
sent_to_positions = set()
for p in positions:
if subevent and p.subevent_id != subevent.id:
continue
if p.addon_to_id is None:
# this op might have matching add-ons, so save for later
parent_op = p
elif not parent_op or p.addon_to_id != parent_op.id:
# this op is an add-on, but not to the current parent_op
# something got mixed up as add-ons should always come directly after their parent
logger.warning(f"Add-ons are mixed up for position #{p.positionid} in order {order.full_code}")
continue
if p.addon_to_id and (
not p.attendee_email or p.attendee_email == parent_op.attendee_email
):
# if op is addon and either has no mail or the same as parent => send to parent
p = parent_op
if p.pk in sent_to_positions:
# this position already got an email
continue
if not p.attendee_email or p.attendee_email == order.email:
# no email or same as order
continue
email_ctx = get_email_context(event=order.event, order=order, position=p)
p.send_mail(
subject=subject,
template=template,
context=email_ctx,
log_entry_type=log_entry_type,
user=user if user else None,
invoices=invoices,
attach_tickets=attach_tickets,
attach_ical=attach_ical,
attach_other_files=attach_other_files,
# possible, as of yet unused here, parameters:
# headers: dict=None,
# sender: str=None,
# auth=None,
)
sent_to_positions.add(p.pk)
class OrderError(Exception):
def __init__(self, *args):
msg = args[0]
@@ -461,14 +531,21 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False
)
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:
email_attendee_context = get_email_context(event=order.event, order=order, position=p)
p.send_mail(
email_attendee_subject, email_attendee_template, email_attendee_context,
'pretix.event.order.email.order_approved', user,
attach_tickets=True,
)
_attendee_mail_send_helper(
event=order.event,
order=order,
positions=order.positions.all(),
template=email_attendee_template,
subject=email_attendee_subject,
log_entry_type='pretix.event.order.email.order_approved',
user=user,
attach_tickets=True,
attach_ical=order.event.settings.mail_attach_ical and (
not order.event.settings.mail_attach_ical_paid_only or
order.total == Decimal('0.00') or
order.valid_if_pending
),
)
return order.pk
@@ -1399,10 +1476,20 @@ def _perform_order(event: Event, payment_requests: List[dict], position_ids: Lis
is_free=free_order_flow
)
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(event, order, p, email_attendees_template, subject_attendees_template, log_entry,
is_free=free_order_flow)
# todo re note: order_placed_email for attendees (formerly services/orders _order_placed_email_attendee)
_attendee_mail_send_helper(
event=event,
order=order,
positions=order.positions.all(),
template=email_attendees_template,
subject=subject_attendees_template,
log_entry_type=log_entry,
attach_ical=event.settings.mail_attach_ical and (
not event.settings.mail_attach_ical_paid_only or
free_order_flow or
order.valid_if_pending
),
)
if not any_payment_failed:
for p in payment_objs:
@@ -1601,6 +1688,7 @@ def send_download_reminders(sender, **kwargs):
)
if event.settings.mail_send_download_reminder_attendee:
send_to_positions = []
for p in positions:
if p.subevent_id:
reminder_date = (p.subevent.date_from - timedelta(days=event.reminder_days)).replace(
@@ -1608,15 +1696,22 @@ def send_download_reminders(sender, **kwargs):
)
if now() < reminder_date:
continue
if p.addon_to_id is None and p.attendee_email and p.attendee_email != o.email:
email_template = event.settings.mail_text_download_reminder_attendee
email_subject = event.settings.mail_subject_download_reminder_attendee
email_context = get_email_context(event=event, order=o, position=p)
o.send_mail(
email_subject, email_template, email_context,
'pretix.event.order.email.download_reminder_sent',
attach_tickets=True, position=p
)
else:
send_to_positions.append(p)
# todo before pr ready (aka note to myself):
# order's send_mail used before, check if there was a good reason to not
# use postion's send_mail
# if not, look for a way to not use double iteration over positions (see above)
# otherwise: rewrite this without this helper function anyway
_attendee_mail_send_helper(
event=event,
order=o,
positions=send_to_positions,
email_template=event.settings.mail_text_download_reminder_attendee,
email_subject=event.settings.mail_subject_download_reminder_attendee,
log_entry_type='pretix.event.order.email.download_reminder_sent',
attach_tickets=True,
)
def notify_user_changed_order(order, user=None, auth=None, invoices=[]):