Compare commits

..

9 Commits

Author SHA1 Message Date
Raphael Michel
2e01887e79 Invoice address: Special validation for Belgium (Z#23224796) (#5970)
* Invoice address: Special validation for Belgium (Z#23224796)

* Update src/pretix/base/invoicing/peppol.py

Co-authored-by: pajowu <engelhardt@pretix.eu>

---------

Co-authored-by: pajowu <engelhardt@pretix.eu>
2026-03-10 09:57:44 +01:00
Raphael Michel
5a7e7fbde3 Event lists: Show sales channels (Z#23225483) (#5967) 2026-03-10 09:56:29 +01:00
Raphael Michel
7b296107c5 Invoice address: Fix broken autofill for Peppol ID (Z#23224796) (#5971)
* Invoice address: Fix broken autofill for Peppol ID (Z#23224796)

* Fix wrong prefix
2026-03-10 09:54:54 +01:00
Raphael Michel
4f449ce6b4 Mail: Handle all rendering in mail.py, return values for log (#5895)
* Mail: Handle all rendering in mail.py, return values for log

* Apply suggestions from code review
2026-03-10 09:53:09 +01:00
Raphael Michel
e6ea8fb5bf Error pages: Load event theme if available (Z#23224853) (#5972) 2026-03-09 20:11:01 +01:00
Raphael Michel
547910beec Voucher CSV download: Do not output "any product" (Z#23224795) (#5969) 2026-03-09 18:26:54 +01:00
Raphael Michel
eef1560ede Order modification: Remove warning when invoice is not yet generated (Z#23226423) (#5966) 2026-03-09 18:16:37 +01:00
Raphael Michel
3d68bbb619 Order change manager: Recalculate tax of zero-valued positions (Z#23223874) (#5938) 2026-03-09 18:13:14 +01:00
Raphael Michel
dc4556d428 PDF editor: add file size to label (Z#23226663) (#5965) 2026-03-09 18:10:57 +01:00
24 changed files with 185 additions and 147 deletions

View File

@@ -33,8 +33,7 @@ from pretix.base.invoicing.transmission import (
transmission_types,
)
from pretix.base.models import Invoice, InvoiceAddress
from pretix.base.services.mail import mail, render_mail
from pretix.helpers.format import format_map
from pretix.base.services.mail import mail
@transmission_types.new()
@@ -134,9 +133,7 @@ class EmailTransmissionProvider(TransmissionProvider):
subject = invoice.order.event.settings.get('mail_subject_order_invoice', as_type=LazyI18nString)
# Do not set to completed because that is done by the email sending task
subject = format_map(subject, context)
email_content = render_mail(template, context)
mail(
outgoing_mail = mail(
[recipient],
subject,
template,
@@ -151,19 +148,10 @@ class EmailTransmissionProvider(TransmissionProvider):
plain_text_only=True,
no_order_links=True,
)
invoice.order.log_action(
'pretix.event.order.email.invoice',
user=None,
auth=None,
data={
'subject': subject,
'message': email_content,
'position': None,
'recipient': recipient,
'invoices': [invoice.pk],
'attach_tickets': False,
'attach_ical': False,
'attach_other_files': [],
'attach_cached_files': [],
}
)
if outgoing_mail:
invoice.order.log_action(
'pretix.event.order.email.invoice',
user=None,
auth=None,
data=outgoing_mail.log_data()
)

View File

@@ -220,3 +220,20 @@ class OutgoingMail(models.Model):
error_log_action_type = 'pretix.email.error'
log_target = None
return log_target, error_log_action_type
def log_data(self):
return {
"subject": self.subject,
"message": self.body_plain,
"to": self.to,
"cc": self.cc,
"bcc": self.bcc,
"invoices": [i.pk for i in self.should_attach_invoices.all()],
"attach_tickets": self.should_attach_tickets,
"attach_ical": self.should_attach_ical,
"attach_other_files": self.should_attach_other_files,
"attach_cached_files": [cf.filename for cf in self.should_attach_cached_files.all()],
"position": self.orderposition.positionid if self.orderposition else None,
}

View File

@@ -87,7 +87,6 @@ from pretix.base.timemachine import time_machine_now
from ...helpers import OF_SELF
from ...helpers.countries import CachedCountries, FastCountryField
from ...helpers.format import FormattedString, format_map
from ...helpers.names import build_name
from ...testutils.middleware import debugflags_var
from ._transactions import (
@@ -1167,7 +1166,7 @@ class Order(LockModel, LoggedModel):
only be attached for this position and child positions, the link will only point to the
position and the attendee email will be used if available.
"""
from pretix.base.services.mail import mail, render_mail
from pretix.base.services.mail import mail
if not self.email and not (position and position.attendee_email):
return
@@ -1177,32 +1176,20 @@ class Order(LockModel, LoggedModel):
if position and position.attendee_email:
recipient = position.attendee_email
email_content = render_mail(template, context)
if not isinstance(subject, FormattedString):
subject = format_map(subject, context)
mail(
outgoing_mail = mail(
recipient, subject, template, context,
self.event, self.locale, self, headers=headers, sender=sender,
invoices=invoices, attach_tickets=attach_tickets,
position=position, auto_email=auto_email, attach_ical=attach_ical,
attach_other_files=attach_other_files, attach_cached_files=attach_cached_files,
)
self.log_action(
log_entry_type,
user=user,
auth=auth,
data={
'subject': subject,
'message': email_content,
'position': position.positionid if position else None,
'recipient': recipient,
'invoices': [i.pk for i in invoices] if invoices else [],
'attach_tickets': attach_tickets,
'attach_ical': attach_ical,
'attach_other_files': attach_other_files,
'attach_cached_files': [cf.filename for cf in attach_cached_files] if attach_cached_files else [],
}
)
if outgoing_mail:
self.log_action(
log_entry_type,
user=user,
auth=auth,
data=outgoing_mail.log_data(),
)
def resend_link(self, user=None, auth=None):
with language(self.locale, self.event.settings.region):
@@ -2900,17 +2887,14 @@ class OrderPosition(AbstractPosition):
:param attach_tickets: Attach tickets of this order, if they are existing and ready to download
:param attach_ical: Attach relevant ICS files
"""
from pretix.base.services.mail import mail, render_mail
from pretix.base.services.mail import mail
if not self.attendee_email:
return
with language(self.order.locale, self.order.event.settings.region):
recipient = self.attendee_email
email_content = render_mail(template, context)
if not isinstance(subject, FormattedString):
subject = format_map(subject, context)
mail(
outgoing_mail = mail(
recipient, subject, template, context,
self.event, self.order.locale, order=self.order, headers=headers, sender=sender,
position=self,
@@ -2919,21 +2903,13 @@ class OrderPosition(AbstractPosition):
attach_ical=attach_ical,
attach_other_files=attach_other_files,
)
self.order.log_action(
log_entry_type,
user=user,
auth=auth,
data={
'subject': subject,
'message': email_content,
'recipient': recipient,
'invoices': [i.pk for i in invoices] if invoices else [],
'attach_tickets': attach_tickets,
'attach_ical': attach_ical,
'attach_other_files': attach_other_files,
'attach_cached_files': [],
}
)
if outgoing_mail:
self.order.log_action(
log_entry_type,
user=user,
auth=auth,
data=outgoing_mail.log_data(),
)
def resend_link(self, user=None, auth=None):

View File

@@ -34,10 +34,9 @@ from phonenumber_field.modelfields import PhoneNumberField
from pretix.base.email import get_email_context
from pretix.base.i18n import language
from pretix.base.models import User, Voucher
from pretix.base.services.mail import mail, render_mail
from pretix.base.services.mail import mail
from pretix.helpers import OF_SELF
from ...helpers.format import format_map
from ...helpers.names import build_name
from .base import LoggedModel
from .event import Event, SubEvent
@@ -273,9 +272,7 @@ class WaitingListEntry(LoggedModel):
with language(self.locale, self.event.settings.region):
recipient = self.email
email_content = render_mail(template, context)
subject = format_map(subject, context)
mail(
outgoing_mail = mail(
recipient, subject, template, context,
self.event,
self.locale,
@@ -285,18 +282,13 @@ class WaitingListEntry(LoggedModel):
attach_other_files=attach_other_files,
attach_cached_files=attach_cached_files,
)
self.log_action(
log_entry_type,
user=user,
auth=auth,
data={
'subject': subject,
'message': email_content,
'recipient': recipient,
'attach_other_files': attach_other_files,
'attach_cached_files': [cf.filename for cf in attach_cached_files] if attach_cached_files else [],
}
)
if outgoing_mail:
self.log_action(
log_entry_type,
user=user,
auth=auth,
data=outgoing_mail.log_data(),
)
@staticmethod
def clean_itemvar(event, item, variation):

View File

@@ -1295,6 +1295,7 @@ class ManualPayment(BasePaymentProvider):
def format_map(self, order, payment):
return {
# Possible placeholder injection, we should make sure to never include user-controlled variables here
'order': order.code,
'amount': payment.amount,
'currency': self.event.currency,

View File

@@ -45,7 +45,6 @@ from pretix.base.services.tax import split_fee_for_taxes
from pretix.base.templatetags.money import money_filter
from pretix.celery_app import app
from pretix.helpers import OF_SELF
from pretix.helpers.format import format_map
logger = logging.getLogger(__name__)
@@ -55,7 +54,7 @@ def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: Lazy
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
mail(
wle.email,
format_map(subject, email_context),
str(subject),
message,
email_context,
wle.event,
@@ -73,9 +72,8 @@ def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, s
email_context = get_email_context(event_or_subevent=subevent or order.event, refund_amount=refund_amount,
order=order, position_or_address=ia, event=order.event)
real_subject = format_map(subject, email_context)
order.send_mail(
real_subject, message, email_context,
subject, message, email_context,
'pretix.event.order.email.event_canceled',
user,
)
@@ -85,14 +83,13 @@ def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, s
continue
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
real_subject = format_map(subject, email_context)
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(
real_subject, message, email_context,
subject, message, email_context,
'pretix.event.order.email.event_canceled',
position=p,
user=user

View File

@@ -149,13 +149,13 @@ def prefix_subject(settings_holder, subject, highlight=False):
return subject
def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, LazyI18nString],
def mail(email: Union[str, Sequence[str]], subject: Union[str, FormattedString], template: Union[str, LazyI18nString],
context: Dict[str, Any] = None, event: Event = None, locale: str = None, order: Order = None,
position: OrderPosition = None, *, headers: dict = None, sender: str = None, organizer: Organizer = None,
customer: Customer = None, invoices: Sequence = None, attach_tickets=False, auto_email=True, user=None,
attach_ical=False, attach_cached_files: Sequence = None, attach_other_files: list=None,
plain_text_only=False, no_order_links=False, cc: Sequence[str]=None, bcc: Sequence[str]=None,
sensitive: bool=False):
sensitive: bool=False) -> Optional[OutgoingMail]:
"""
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
@@ -335,14 +335,26 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
should_attach_other_files=attach_other_files or [],
sensitive=sensitive,
)
m._prefetched_objects_cache = {}
if invoices and not position:
m.should_attach_invoices.add(*invoices)
# Hack: For logging, we'll later make a `should_attach_invoices.all()` call. We can prevent a useless
# DB query by filling the cache
m._prefetched_objects_cache[m.should_attach_invoices.prefetch_cache_name] = invoices
else:
m._prefetched_objects_cache[m.should_attach_invoices.prefetch_cache_name] = Invoice.objects.none()
if attach_cached_files:
cf_list = []
for cf in attach_cached_files:
if not isinstance(cf, CachedFile):
m.should_attach_cached_files.add(CachedFile.objects.get(pk=cf))
else:
m.should_attach_cached_files.add(cf)
cf = CachedFile.objects.get(pk=cf)
m.should_attach_cached_files.add(cf)
cf_list.append(cf)
# Hack: For logging, we'll later make a `should_attach_cached_files.all()` call. We can prevent a useless
# DB query by filling the cache
m._prefetched_objects_cache[m.should_attach_cached_files.prefetch_cache_name] = cf_list
else:
m._prefetched_objects_cache[m.should_attach_cached_files.prefetch_cache_name] = CachedFile.objects.none()
send_task = mail_send_task.si(
outgoing_mail=m.id
@@ -364,6 +376,8 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
lambda: chain(*task_chain).apply_async()
)
return m
class CustomEmail(EmailMultiAlternatives):
def _create_mime_attachment(self, content, mimetype):

View File

@@ -1799,8 +1799,6 @@ class OrderChangeManager:
tax_rule = tax_rules.get(pos.pk, pos.tax_rule)
if not tax_rule:
continue
if not pos.price:
continue
try:
new_rate = tax_rule.tax_rate_for(ia)
@@ -1817,7 +1815,9 @@ class OrderChangeManager:
override_tax_rate=new_rate, override_tax_code=new_code)
self._totaldiff_guesstimate += new_tax.gross - pos.price
self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price))
self._invoice_dirty = True
if pos.price:
# We do not consider the invoice dirty if only 0€-valued taxes are changed
self._invoice_dirty = True
def cancel_fee(self, fee: OrderFee):
self._totaldiff_guesstimate -= fee.value

View File

@@ -39,7 +39,7 @@ def vouchers_send(event: Event, vouchers: list, subject: str, message: str, reci
with language(event.settings.locale):
email_context = get_email_context(event=event, name=r.get('name') or '',
voucher_list=[v.code for v in voucher_list])
mail(
outgoing_mail = mail(
r['email'],
subject,
LazyI18nString(message),
@@ -60,8 +60,8 @@ def vouchers_send(event: Event, vouchers: list, subject: str, message: str, reci
data={
'recipient': r['email'],
'name': r.get('name'),
'subject': subject,
'message': message,
'subject': outgoing_mail.subject,
'message': outgoing_mail.body_plain,
},
save=False
))

View File

@@ -363,7 +363,7 @@ class EmailAddressShredder(BaseDataShredder):
le.save(update_fields=['data', 'shredded'])
else:
shred_log_fields(le, banlist=[
'recipient', 'message', 'subject', 'full_mail', 'old_email', 'new_email'
'recipient', 'message', 'subject', 'full_mail', 'old_email', 'new_email', 'bcc', 'cc',
])

View File

@@ -12,6 +12,9 @@
<meta charset="utf-8">
<link rel="icon" href="{% static "pretixbase/img/favicon.ico" %}">
{% block custom_header %}{% endblock %}
{% if css_theme %}
<link rel="stylesheet" type="text/css" href="{{ css_theme }}" />
{% endif %}
</head>
<body>
<div class="container">

View File

@@ -2,6 +2,7 @@
{% load i18n %}
{% load urlreplace %}
{% load bootstrap3 %}
{% load static %}
{% block title %}{% trans "Events" %}{% endblock %}
{% block content %}
<h1>{% trans "Events" %}</h1>
@@ -74,6 +75,7 @@
<a href="?{% url_replace request 'ordering' 'organizer' %}"><i class="fa fa-caret-up"></i></a>
</th>
{% endif %}
<th>{% trans "Sales channels" %}</th>
<th>
{% trans "Start date" %}
<a href="?{% url_replace request 'ordering' '-date_from' %}"><i class="fa fa-caret-down"></i></a>
@@ -108,6 +110,21 @@
{% endfor %}
</td>
{% if not hide_orga %}<td>{{ e.organizer }}</td>{% endif %}
<td>
{% for c in e.organizer.sales_channels.all %}
{% if e.all_sales_channels or c in e.limit_sales_channels.all %}
{% if "." in c.icon %}
<img src="{% static c.icon %}" class="fa-like-image"
data-toggle="tooltip" title="{{ c.label }}">
{% else %}
<span class="fa fa-fw fa-{{ c.icon }} text-muted"
data-toggle="tooltip" title="{{ c.label }}"></span>
{% endif %}
{% else %}
<span class="fa fa-fw"></span>
{% endif %}
{% endfor %}
</td>
<td class="event-date-col">
{% if e.has_subevents %}
<span class="fa fa-fw- fa-calendar"></span>

View File

@@ -24,7 +24,9 @@
{% if log.display %}
<br/><span class="fa fa-fw fa-comment-o"></span> {{ log.display }}
{% endif %}
{% if log.parsed_data.recipient %}
{% if log.parsed_data.to %}
<br/><span class="fa fa-fw fa-envelope-o"></span> {{ log.parsed_data.to|join:", " }}
{% elif log.parsed_data.recipient %} {# legacy #}
<br/><span class="fa fa-fw fa-envelope-o"></span> {{ log.parsed_data.recipient }}
{% endif %}
</p>

View File

@@ -1,6 +1,7 @@
{% extends "pretixcontrol/organizers/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load static %}
{% block inner %}
<h1>
{% blocktrans with name=request.organizer.name %}Organizer: {{ name }}{% endblocktrans %}
@@ -62,6 +63,7 @@
<thead>
<tr>
<th>{% trans "Event name" %}</th>
<th>{% trans "Sales channels" %}</th>
<th>
{% trans "Start date" %}
/
@@ -77,10 +79,30 @@
<td>
<strong><a
href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
<br><small>{{ e.slug }}</small>
{% for k, v in e.meta_data.items %}
{% if v %}
<small class="text-muted">&middot; {{ k }}: {{ v }}</small>
<br>
<small>
{{ e.slug }}
</small>
<small class="text-muted">
{% for k, v in e.meta_data.items %}
{% if v %}
&middot; {{ k }}: {{ v }}
{% endif %}
{% endfor %}
</small>
</td>
<td>
{% for c in sales_channels %}
{% if e.all_sales_channels or c in e.limit_sales_channels.all %}
{% if "." in c.icon %}
<img src="{% static c.icon %}" class="fa-like-image"
data-toggle="tooltip" title="{{ c.label }}">
{% else %}
<span class="fa fa-fw fa-{{ c.icon }} text-muted"
data-toggle="tooltip" title="{{ c.label }}"></span>
{% endif %}
{% else %}
<span class="fa fa-fw"></span>
{% endif %}
{% endfor %}
</td>

View File

@@ -264,12 +264,17 @@
The paper size will match the PDF.
{% endblocktrans %}
</p>
<p>
<p class="text-center">
<span class="btn btn-default fileinput-button background-button btn-block">
<i class="fa fa-upload"></i>
<span>{% trans "Upload PDF as background" %}</span>
<input id="fileupload" type="file" name="background" accept="application/pdf">
</span>
<small class="text-muted">
{% blocktrans trimmed with size=maxfilesize|filesizeformat %}
max. {{ size }}, smaller is better
{% endblocktrans %}
</small>
</p>
<p class="text-center">
<a class="btn btn-link background-download-button" href="{{ pdf }}" target="_blank">

View File

@@ -67,7 +67,12 @@ class EventList(PaginationMixin, ListView):
def get_queryset(self):
qs = self.request.user.get_events_with_any_permission(self.request).prefetch_related(
'organizer', '_settings_objects', 'organizer___settings_objects', 'organizer__meta_properties',
'organizer',
'organizer__sales_channels',
'_settings_objects',
'organizer___settings_objects',
'organizer__meta_properties',
'limit_sales_channels',
Prefetch(
'meta_values',
EventMetaValue.objects.select_related('property'),

View File

@@ -2421,9 +2421,9 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
with language(order.locale, self.request.event.settings.region):
email_context = get_email_context(event=order.event, order=order)
email_template = LazyI18nString(form.cleaned_data['message'])
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
email_content = render_mail(email_template, email_context)
if self.request.POST.get('action') == 'preview':
email_subject = format_map(form.cleaned_data['subject'], email_context)
email_content = render_mail(email_template, email_context)
self.preview_output = {
'subject': mark_safe(_('Subject: {subject}').format(
subject=prefix_subject(order.event, escape(email_subject), highlight=True)
@@ -2485,9 +2485,9 @@ class OrderPositionSendMail(OrderSendMail):
with language(position.order.locale, self.request.event.settings.region):
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
email_template = LazyI18nString(form.cleaned_data['message'])
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
email_content = render_mail(email_template, email_context)
if self.request.POST.get('action') == 'preview':
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
email_content = render_mail(email_template, email_context)
self.preview_output = {
'subject': mark_safe(_('Subject: {subject}').format(
subject=prefix_subject(position.order.event, escape(email_subject), highlight=True))

View File

@@ -207,6 +207,7 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
'organizer').prefetch_related(
'organizer', '_settings_objects', 'organizer___settings_objects',
'organizer__meta_properties',
'limit_sales_channels',
Prefetch(
'meta_values',
EventMetaValue.objects.select_related('property'),
@@ -237,6 +238,7 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
self.filter_form['meta_{}'.format(p.name)] for p in
self.organizer.meta_properties.filter(filter_allowed=True)
]
ctx['sales_channels'] = self.request.organizer.sales_channels.all()
return ctx

View File

@@ -292,6 +292,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
ctx['layout'] = json.dumps(self.get_current_layout())
ctx['title'] = self.title
ctx['locales'] = [p for p in settings.LANGUAGES if p[0] in self.request.event.settings.locales]
ctx['maxfilesize'] = self.maxfilesize
return ctx

View File

@@ -131,7 +131,7 @@ class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView):
elif v.quota:
prod = _('Any product in quota "{quota}"').format(quota=str(v.quota.name))
else:
prod = _('Any product')
prod = ""
row = [
v.code,
v.valid_until.isoformat() if v.valid_until else "",

View File

@@ -38,13 +38,10 @@ from i18nfield.strings import LazyI18nString
from pretix.base.email import get_email_context
from pretix.base.i18n import language
from pretix.base.models import (
CachedFile, Checkin, Event, InvoiceAddress, Order, User,
)
from pretix.base.models import Checkin, Event, InvoiceAddress, Order, User
from pretix.base.services.mail import mail
from pretix.base.services.tasks import ProfiledEventTask
from pretix.celery_app import app
from pretix.helpers.format import format_map
def _chunks(lst, n):
@@ -64,7 +61,6 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
user = User.objects.get(pk=user) if user else None
subject = LazyI18nString(subject)
message = LazyI18nString(message)
attachments_for_log = [cf.filename for cf in CachedFile.objects.filter(pk__in=attachments)] if attachments else []
def _send_to_order(o):
send_to_order = recipients in ('both', 'orders')
@@ -122,7 +118,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
with language(o.locale, event.settings.region):
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
mail(
outgoing_mail = mail(
p.attendee_email,
subject,
message,
@@ -135,25 +131,17 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
attach_ical=attach_ical,
attach_cached_files=attachments
)
o.log_action(
'pretix.plugins.sendmail.order.email.sent.attendee',
user=user,
data={
'position': p.positionid,
'subject': format_map(subject.localize(o.locale), email_context),
'message': format_map(message.localize(o.locale), email_context),
'recipient': p.attendee_email,
'attach_tickets': attach_tickets,
'attach_ical': attach_ical,
'attach_other_files': [],
'attach_cached_files': attachments_for_log,
}
)
if outgoing_mail:
o.log_action(
'pretix.plugins.sendmail.order.email.sent.attendee',
user=user,
data=outgoing_mail.log_data(),
)
if send_to_order and o.email:
with language(o.locale, event.settings.region):
email_context = get_email_context(event=event, order=o, invoice_address=ia)
mail(
outgoing_mail = mail(
o.email,
subject,
message,
@@ -165,19 +153,12 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
attach_ical=attach_ical,
attach_cached_files=attachments,
)
o.log_action(
'pretix.plugins.sendmail.order.email.sent',
user=user,
data={
'subject': format_map(subject.localize(o.locale), email_context),
'message': format_map(message.localize(o.locale), email_context),
'recipient': o.email,
'attach_tickets': attach_tickets,
'attach_ical': attach_ical,
'attach_other_files': [],
'attach_cached_files': attachments_for_log,
}
)
if outgoing_mail:
o.log_action(
'pretix.plugins.sendmail.order.email.sent',
user=user,
data=outgoing_mail.log_data(),
)
for chunk in _chunks(objects, 1000):
orders = Order.objects.filter(pk__in=chunk, event=event)

View File

@@ -13,7 +13,7 @@
{% csrf_token %}
<div class="panel-group" id="questions_accordion">
{% if invoice_address_asked or event.settings.invoice_name_required %}
{% if invoice_address_asked and not request.GET.generate_invoice == "true" and not event.settings.invoice_reissue_after_modify %}
{% if invoice_address_asked and not request.GET.generate_invoice == "true" and not invoice_generation_selfservice %}
<div class="alert alert-info">
{% blocktrans trimmed %}
Modifying your invoice address will not automatically generate a new invoice.

View File

@@ -909,6 +909,21 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(
**kwargs,
)
ctx['invoice_generation_selfservice'] = (
self.request.event.settings.invoice_reissue_after_modify or
(
can_generate_invoice(self.request.event, self.order, ignore_payments=True) and
not self.order.invoices.exists()
)
)
return ctx
def dispatch(self, request, *args, **kwargs):
self.request = request
self.kwargs = kwargs

View File

@@ -173,8 +173,8 @@ $(function () {
if (!dependents.transmission_peppol_participant_id.val()) {
const fill_peppol_id = function () {
const vatId = dependents.vat_id.val();
if (vatId && vatId.startsWith("BE") && dependents.transmission_type.val() === "peppol" && autofill_peppol_id) {
dependents.transmission_peppol_participant_id.val("0201:" + vatId.substring(2))
if (vatId && vatId.startsWith("BE") && dependents.transmission_type.val() === "peppol") {
dependents.transmission_peppol_participant_id.val("0208:" + vatId.substring(2))
}
}
dependents.vat_id.add(dependents.transmission_type).on("change", fill_peppol_id);