mirror of
https://github.com/pretix/pretix.git
synced 2026-08-24 13:02:00 +00:00
Bank transfer: Allow to send the invoice direclty to the accounting department (#2975)
This commit is contained in:
@@ -381,6 +381,14 @@ def base_placeholders(sender, **kwargs):
|
|||||||
SimpleFunctionalMailTextPlaceholder(
|
SimpleFunctionalMailTextPlaceholder(
|
||||||
'currency', ['event'], lambda event: event.currency, lambda event: event.currency
|
'currency', ['event'], lambda event: event.currency, lambda event: event.currency
|
||||||
),
|
),
|
||||||
|
SimpleFunctionalMailTextPlaceholder(
|
||||||
|
'order_email', ['order'], lambda order: order.email, 'john@example.org'
|
||||||
|
),
|
||||||
|
SimpleFunctionalMailTextPlaceholder(
|
||||||
|
'invoice_number', ['invoice'],
|
||||||
|
lambda invoice: invoice.full_invoice_no,
|
||||||
|
f'{sender.settings.invoice_numbers_prefix or (sender.slug.upper() + "-")}00000'
|
||||||
|
),
|
||||||
SimpleFunctionalMailTextPlaceholder(
|
SimpleFunctionalMailTextPlaceholder(
|
||||||
'refund_amount', ['event_or_subevent', 'refund_amount'],
|
'refund_amount', ['event_or_subevent', 'refund_amount'],
|
||||||
lambda event_or_subevent, refund_amount: LazyCurrencyNumber(refund_amount, event_or_subevent.currency),
|
lambda event_or_subevent, refund_amount: LazyCurrencyNumber(refund_amount, event_or_subevent.currency),
|
||||||
|
|||||||
+10
-10
@@ -325,16 +325,6 @@ class BasePaymentProvider:
|
|||||||
help_text=_('Users will not be able to choose this payment provider after the given date.'),
|
help_text=_('Users will not be able to choose this payment provider after the given date.'),
|
||||||
required=False,
|
required=False,
|
||||||
)),
|
)),
|
||||||
('_invoice_text',
|
|
||||||
I18nFormField(
|
|
||||||
label=_('Text on invoices'),
|
|
||||||
help_text=_('Will be printed just below the payment figures and above the closing text on invoices. '
|
|
||||||
'This will only be used if the invoice is generated before the order is paid. If the '
|
|
||||||
'invoice is generated later, it will show a text stating that it has already been paid.'),
|
|
||||||
required=False,
|
|
||||||
widget=I18nTextarea,
|
|
||||||
widget_kwargs={'attrs': {'rows': '2'}}
|
|
||||||
)),
|
|
||||||
('_total_min',
|
('_total_min',
|
||||||
forms.DecimalField(
|
forms.DecimalField(
|
||||||
label=_('Minimum order total'),
|
label=_('Minimum order total'),
|
||||||
@@ -382,6 +372,16 @@ class BasePaymentProvider:
|
|||||||
'above!').format(docs_url='https://docs.pretix.eu/en/latest/user/payments/fees.html'),
|
'above!').format(docs_url='https://docs.pretix.eu/en/latest/user/payments/fees.html'),
|
||||||
required=False
|
required=False
|
||||||
)),
|
)),
|
||||||
|
('_invoice_text',
|
||||||
|
I18nFormField(
|
||||||
|
label=_('Text on invoices'),
|
||||||
|
help_text=_('Will be printed just below the payment figures and above the closing text on invoices. '
|
||||||
|
'This will only be used if the invoice is generated before the order is paid. If the '
|
||||||
|
'invoice is generated later, it will show a text stating that it has already been paid.'),
|
||||||
|
required=False,
|
||||||
|
widget=I18nTextarea,
|
||||||
|
widget_kwargs={'attrs': {'rows': '2'}}
|
||||||
|
)),
|
||||||
('_restricted_countries',
|
('_restricted_countries',
|
||||||
forms.MultipleChoiceField(
|
forms.MultipleChoiceField(
|
||||||
label=_('Restrict to countries'),
|
label=_('Restrict to countries'),
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ INVALID_ADDRESS = 'invalid-pretix-mail-address'
|
|||||||
|
|
||||||
|
|
||||||
class TolerantDict(dict):
|
class TolerantDict(dict):
|
||||||
# kept for backwards compatibility with plugins
|
|
||||||
|
|
||||||
def __missing__(self, key):
|
def __missing__(self, key):
|
||||||
return key
|
return key
|
||||||
@@ -100,7 +99,8 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
context: Dict[str, Any] = None, event: Event = None, locale: str = None, order: Order = None,
|
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,
|
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,
|
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):
|
attach_ical=False, attach_cached_files: Sequence = None, attach_other_files: list=None,
|
||||||
|
plain_text_only=False, no_order_links=False):
|
||||||
"""
|
"""
|
||||||
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
||||||
|
|
||||||
@@ -150,12 +150,21 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
|
|
||||||
:param attach_other_files: A list of file paths on our storage to attach.
|
:param attach_other_files: A list of file paths on our storage to attach.
|
||||||
|
|
||||||
|
:param plain_text_only: If set to ``True``, rendering a HTML version will be skipped.
|
||||||
|
|
||||||
|
:param no_order_links: If set to ``True``, no link to the order confirmation page will be auto-appended. Currently
|
||||||
|
only allowed to use together with ``plain_text_only`` since HTML renderers add their own
|
||||||
|
links.
|
||||||
|
|
||||||
:raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean
|
:raises MailOrderException: on obvious, immediate failures. Not raising an exception does not necessarily mean
|
||||||
that the email has been sent, just that it has been queued by the email backend.
|
that the email has been sent, just that it has been queued by the email backend.
|
||||||
"""
|
"""
|
||||||
if email == INVALID_ADDRESS:
|
if email == INVALID_ADDRESS:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if no_order_links and not plain_text_only:
|
||||||
|
raise ValueError('If you set no_order_links, you also need to set plain_text_only.')
|
||||||
|
|
||||||
headers = headers or {}
|
headers = headers or {}
|
||||||
if auto_email:
|
if auto_email:
|
||||||
headers['X-Auto-Response-Suppress'] = 'OOF, NRN, AutoReply, RN'
|
headers['X-Auto-Response-Suppress'] = 'OOF, NRN, AutoReply, RN'
|
||||||
@@ -179,7 +188,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
})
|
})
|
||||||
renderer = ClassicMailRenderer(None, organizer)
|
renderer = ClassicMailRenderer(None, organizer)
|
||||||
content_plain = body_plain = render_mail(template, context)
|
content_plain = body_plain = render_mail(template, context)
|
||||||
subject = format_map(str(subject), context)
|
subject = str(subject).format_map(TolerantDict(context))
|
||||||
sender = (
|
sender = (
|
||||||
sender or
|
sender or
|
||||||
(event.settings.get('mail_from') if event else None) or
|
(event.settings.get('mail_from') if event else None) or
|
||||||
@@ -244,7 +253,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
if order and order.testmode:
|
if order and order.testmode:
|
||||||
subject = "[TESTMODE] " + subject
|
subject = "[TESTMODE] " + subject
|
||||||
|
|
||||||
if order and position:
|
if order and position and not no_order_links:
|
||||||
body_plain += _(
|
body_plain += _(
|
||||||
"You are receiving this email because someone placed an order for {event} for you."
|
"You are receiving this email because someone placed an order for {event} for you."
|
||||||
).format(event=event.name)
|
).format(event=event.name)
|
||||||
@@ -260,7 +269,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif order:
|
elif order and not no_order_links:
|
||||||
body_plain += _(
|
body_plain += _(
|
||||||
"You are receiving this email because you placed an order for {event}."
|
"You are receiving this email because you placed an order for {event}."
|
||||||
).format(event=event.name)
|
).format(event=event.name)
|
||||||
@@ -280,7 +289,9 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
|
|
||||||
with override(timezone):
|
with override(timezone):
|
||||||
try:
|
try:
|
||||||
if 'position' in inspect.signature(renderer.render).parameters:
|
if plain_text_only:
|
||||||
|
body_html = None
|
||||||
|
elif 'position' in inspect.signature(renderer.render).parameters:
|
||||||
body_html = renderer.render(content_plain, signature, raw_subject, order, position)
|
body_html = renderer.render(content_plain, signature, raw_subject, order, position)
|
||||||
else:
|
else:
|
||||||
# Backwards compatibility
|
# Backwards compatibility
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ from django import forms
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import gettext, gettext_lazy as _
|
from django.utils.translation import gettext, gettext_lazy as _
|
||||||
from i18nfield.fields import I18nFormField, I18nTextarea
|
from i18nfield.fields import I18nFormField, I18nTextarea
|
||||||
from i18nfield.forms import I18nTextInput
|
from i18nfield.forms import I18nTextInput
|
||||||
@@ -49,8 +50,13 @@ from localflavor.generic.forms import BICFormField, IBANFormField
|
|||||||
from localflavor.generic.validators import IBANValidator
|
from localflavor.generic.validators import IBANValidator
|
||||||
from text_unidecode import unidecode
|
from text_unidecode import unidecode
|
||||||
|
|
||||||
|
from pretix.base.email import get_available_placeholders, get_email_context
|
||||||
|
from pretix.base.forms import PlaceholderValidator
|
||||||
|
from pretix.base.i18n import language
|
||||||
from pretix.base.models import Order, OrderPayment, OrderRefund
|
from pretix.base.models import Order, OrderPayment, OrderRefund
|
||||||
from pretix.base.payment import BasePaymentProvider
|
from pretix.base.payment import BasePaymentProvider
|
||||||
|
from pretix.base.services.mail import SendMailException, mail, render_mail
|
||||||
|
from pretix.helpers.format import format_map
|
||||||
from pretix.plugins.banktransfer.templatetags.ibanformat import ibanformat
|
from pretix.plugins.banktransfer.templatetags.ibanformat import ibanformat
|
||||||
|
|
||||||
|
|
||||||
@@ -81,7 +87,8 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
)),
|
)),
|
||||||
('bank_details_sepa_name', forms.CharField(
|
('bank_details_sepa_name', forms.CharField(
|
||||||
label=_('Name of account holder'),
|
label=_('Name of account holder'),
|
||||||
help_text=_('Please note: special characters other than letters, numbers, and some punctuation can cause problems with some banks.'),
|
help_text=_(
|
||||||
|
'Please note: special characters other than letters, numbers, and some punctuation can cause problems with some banks.'),
|
||||||
widget=forms.TextInput(
|
widget=forms.TextInput(
|
||||||
attrs={
|
attrs={
|
||||||
'data-display-dependency': '#id_payment_banktransfer_bank_details_type_0',
|
'data-display-dependency': '#id_payment_banktransfer_bank_details_type_0',
|
||||||
@@ -166,12 +173,15 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
help_text=_('This text will be shown on the order confirmation page for pending orders in addition to '
|
help_text=_('This text will be shown on the order confirmation page for pending orders in addition to '
|
||||||
'the standard text.'),
|
'the standard text.'),
|
||||||
widget=I18nTextarea,
|
widget=I18nTextarea,
|
||||||
|
widget_kwargs={'attrs': {
|
||||||
|
'rows': '2',
|
||||||
|
}},
|
||||||
required=False,
|
required=False,
|
||||||
)),
|
)),
|
||||||
('refund_iban_blocklist', forms.CharField(
|
('refund_iban_blocklist', forms.CharField(
|
||||||
label=_('IBAN blocklist for refunds'),
|
label=_('IBAN blocklist for refunds'),
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.Textarea,
|
widget=forms.Textarea(attrs={'rows': 4}),
|
||||||
help_text=_('Put one IBAN or IBAN prefix per line. The system will not attempt to send refunds to any '
|
help_text=_('Put one IBAN or IBAN prefix per line. The system will not attempt to send refunds to any '
|
||||||
'of these IBANs. Useful e.g. if you receive a lot of "forwarded payments" by a third-party payment '
|
'of these IBANs. Useful e.g. if you receive a lot of "forwarded payments" by a third-party payment '
|
||||||
'provider. You can also list country codes such as "GB" if you never want to send refunds to '
|
'provider. You can also list country codes such as "GB" if you never want to send refunds to '
|
||||||
@@ -194,7 +204,54 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def settings_form_fields(self):
|
def settings_form_fields(self):
|
||||||
d = OrderedDict(list(super().settings_form_fields.items()) + list(BankTransfer.form_fields().items()))
|
phs = [
|
||||||
|
'{%s}' % p
|
||||||
|
for p in sorted(get_available_placeholders(self.event, ['event', 'order', 'invoice']).keys())
|
||||||
|
]
|
||||||
|
phs_ht = _('Available placeholders: {list}').format(
|
||||||
|
list=', '.join(phs)
|
||||||
|
)
|
||||||
|
more_fields = OrderedDict([
|
||||||
|
('invoice_email',
|
||||||
|
forms.BooleanField(
|
||||||
|
label=_('Allow users to enter an additional email address that the invoice will be sent to.'),
|
||||||
|
help_text=_(
|
||||||
|
'This requires that the invoice creation settings allow the invoice to be created right after '
|
||||||
|
'the payment method was chosen. Only the invoice will be sent to this email address, subsequent '
|
||||||
|
'invoice corrections will not be sent automatically. Only the invoice will be sent, no additional '
|
||||||
|
'information.'
|
||||||
|
),
|
||||||
|
required=False,
|
||||||
|
)),
|
||||||
|
('invoice_email_subject',
|
||||||
|
I18nFormField(
|
||||||
|
label=_('Invoice email subject'),
|
||||||
|
widget=I18nTextInput,
|
||||||
|
widget_kwargs={'attrs': {
|
||||||
|
'data-display-dependency': '#id_payment_banktransfer_invoice_email',
|
||||||
|
'data-required-if': '#id_payment_banktransfer_invoice_email',
|
||||||
|
}},
|
||||||
|
validators=[PlaceholderValidator(phs)],
|
||||||
|
help_text=phs_ht,
|
||||||
|
required=False
|
||||||
|
)),
|
||||||
|
('invoice_email_text',
|
||||||
|
I18nFormField(
|
||||||
|
label=_('Invoice email text'),
|
||||||
|
widget=I18nTextarea,
|
||||||
|
widget_kwargs={'attrs': {
|
||||||
|
'rows': '8',
|
||||||
|
'data-display-dependency': '#id_payment_banktransfer_invoice_email',
|
||||||
|
'data-required-if': '#id_payment_banktransfer_invoice_email',
|
||||||
|
}},
|
||||||
|
validators=[PlaceholderValidator(phs)],
|
||||||
|
help_text=phs_ht,
|
||||||
|
required=False
|
||||||
|
)),
|
||||||
|
])
|
||||||
|
|
||||||
|
d = OrderedDict(list(super().settings_form_fields.items()) + list(BankTransfer.form_fields().items()) + list(more_fields.items()))
|
||||||
|
d.move_to_end('invoice_immediately', last=False)
|
||||||
d.move_to_end('bank_details', last=False)
|
d.move_to_end('bank_details', last=False)
|
||||||
d.move_to_end('bank_details_sepa_bank', last=False)
|
d.move_to_end('bank_details_sepa_bank', last=False)
|
||||||
d.move_to_end('bank_details_sepa_bic', last=False)
|
d.move_to_end('bank_details_sepa_bic', last=False)
|
||||||
@@ -207,7 +264,10 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
|
|
||||||
def settings_form_clean(self, cleaned_data):
|
def settings_form_clean(self, cleaned_data):
|
||||||
if cleaned_data.get('payment_banktransfer_bank_details_type') == 'sepa':
|
if cleaned_data.get('payment_banktransfer_bank_details_type') == 'sepa':
|
||||||
for f in ('bank_details_sepa_name', 'bank_details_sepa_bank', 'bank_details_sepa_bic', 'bank_details_sepa_iban'):
|
for f in (
|
||||||
|
'bank_details_sepa_name', 'bank_details_sepa_bank', 'bank_details_sepa_bic',
|
||||||
|
'bank_details_sepa_iban'
|
||||||
|
):
|
||||||
if not cleaned_data.get('payment_banktransfer_%s' % f):
|
if not cleaned_data.get('payment_banktransfer_%s' % f):
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
{'payment_banktransfer_%s' % f: _('Please fill out your bank account details.')})
|
{'payment_banktransfer_%s' % f: _('Please fill out your bank account details.')})
|
||||||
@@ -217,10 +277,45 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
{'payment_banktransfer_bank_details': _('Please enter your bank account details.')})
|
{'payment_banktransfer_bank_details': _('Please enter your bank account details.')})
|
||||||
return cleaned_data
|
return cleaned_data
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def _invoice_email_asked(self):
|
||||||
|
return (
|
||||||
|
self.settings.get('invoice_email', as_type=bool) and
|
||||||
|
(self.event.settings.invoice_generate == 'True' or (
|
||||||
|
self.event.settings.invoice_generate == 'paid' and
|
||||||
|
self.settings.get('invoice_immediately', as_type=bool)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def payment_form_fields(self) -> dict:
|
||||||
|
if self._invoice_email_asked:
|
||||||
|
return {
|
||||||
|
'send_invoice': forms.BooleanField(
|
||||||
|
label=_('Please send my invoice directly to our accounting department'),
|
||||||
|
required=False,
|
||||||
|
),
|
||||||
|
'send_invoice_to': forms.EmailField(
|
||||||
|
label=_('Invoice recipient e-mail'),
|
||||||
|
required=False,
|
||||||
|
help_text=_('The invoice recipient will receive an email which includes the invoice and your email '
|
||||||
|
'address so they know who placed this order.'),
|
||||||
|
widget=forms.EmailInput(
|
||||||
|
attrs={
|
||||||
|
'data-display-dependency': '#id_payment_banktransfer-send_invoice',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
def payment_form_render(self, request, total=None, order=None) -> str:
|
def payment_form_render(self, request, total=None, order=None) -> str:
|
||||||
template = get_template('pretixplugins/banktransfer/checkout_payment_form.html')
|
template = get_template('pretixplugins/banktransfer/checkout_payment_form.html')
|
||||||
|
form = self.payment_form(request)
|
||||||
ctx = {
|
ctx = {
|
||||||
'request': request,
|
'request': request,
|
||||||
|
'form': form,
|
||||||
'event': self.event,
|
'event': self.event,
|
||||||
'settings': self.settings,
|
'settings': self.settings,
|
||||||
'code': self._code(order) if order else None,
|
'code': self._code(order) if order else None,
|
||||||
@@ -229,16 +324,97 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
return template.render(ctx)
|
return template.render(ctx)
|
||||||
|
|
||||||
def checkout_prepare(self, request, total):
|
def checkout_prepare(self, request, total):
|
||||||
return True
|
form = self.payment_form(request)
|
||||||
|
if form.is_valid():
|
||||||
|
for k, v in form.cleaned_data.items():
|
||||||
|
request.session['payment_%s_%s' % (self.identifier, k)] = v
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def send_invoice_to_alternate_email(self, order, invoice, email):
|
||||||
|
"""
|
||||||
|
Sends an email to the alternate invoice address.
|
||||||
|
"""
|
||||||
|
with language(order.locale, self.event.settings.region):
|
||||||
|
context = get_email_context(event=self.event,
|
||||||
|
order=order,
|
||||||
|
invoice=invoice,
|
||||||
|
event_or_subevent=self.event,
|
||||||
|
invoice_address=order.invoice_address)
|
||||||
|
template = self.settings.get('invoice_email_text', as_type=LazyI18nString)
|
||||||
|
subject = self.settings.get('invoice_email_subject', as_type=LazyI18nString)
|
||||||
|
|
||||||
|
try:
|
||||||
|
email_content = render_mail(template, context)
|
||||||
|
subject = format_map(subject, context)
|
||||||
|
mail(
|
||||||
|
email,
|
||||||
|
subject,
|
||||||
|
template,
|
||||||
|
context=context,
|
||||||
|
event=self.event,
|
||||||
|
locale=order.locale,
|
||||||
|
order=order,
|
||||||
|
invoices=[invoice],
|
||||||
|
attach_tickets=False,
|
||||||
|
auto_email=True,
|
||||||
|
attach_ical=False,
|
||||||
|
plain_text_only=True,
|
||||||
|
no_order_links=True,
|
||||||
|
)
|
||||||
|
except SendMailException:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
order.log_action(
|
||||||
|
'pretix.plugins.banktransfer.order.email.invoice',
|
||||||
|
data={
|
||||||
|
'subject': subject,
|
||||||
|
'message': email_content,
|
||||||
|
'position': None,
|
||||||
|
'recipient': email,
|
||||||
|
'invoices': invoice.pk,
|
||||||
|
'attach_tickets': False,
|
||||||
|
'attach_ical': False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def execute_payment(self, request: HttpRequest, payment: OrderPayment) -> str:
|
||||||
|
send_invoice = (
|
||||||
|
self._invoice_email_asked and
|
||||||
|
request and
|
||||||
|
request.session.get('payment_%s_%s' % (self.identifier, 'send_invoice')) and
|
||||||
|
request.session.get('payment_%s_%s' % (self.identifier, 'send_invoice_to'))
|
||||||
|
)
|
||||||
|
if send_invoice:
|
||||||
|
recipient = request.session.get('payment_%s_%s' % (self.identifier, 'send_invoice_to'))
|
||||||
|
payment.info_data = {
|
||||||
|
'send_invoice_to': recipient,
|
||||||
|
}
|
||||||
|
payment.save(update_fields=['info'])
|
||||||
|
i = payment.order.invoices.filter(is_cancellation=False).last()
|
||||||
|
if i:
|
||||||
|
self.send_invoice_to_alternate_email(payment.order, i, recipient)
|
||||||
|
if request:
|
||||||
|
request.session.pop('payment_%s_%s' % (self.identifier, 'send_invoice'), None)
|
||||||
|
request.session.pop('payment_%s_%s' % (self.identifier, 'send_invoice_to'), None)
|
||||||
|
|
||||||
def payment_prepare(self, request: HttpRequest, payment: OrderPayment):
|
def payment_prepare(self, request: HttpRequest, payment: OrderPayment):
|
||||||
return True
|
return self.checkout_prepare(request, payment.amount)
|
||||||
|
|
||||||
def payment_is_valid_session(self, request):
|
def payment_is_valid_session(self, request):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def checkout_confirm_render(self, request, order=None):
|
def checkout_confirm_render(self, request, order=None):
|
||||||
return self.payment_form_render(request, order=order)
|
template = get_template('pretixplugins/banktransfer/checkout_confirm.html')
|
||||||
|
ctx = {
|
||||||
|
'request': request,
|
||||||
|
'event': self.event,
|
||||||
|
'settings': self.settings,
|
||||||
|
'code': self._code(order) if order else None,
|
||||||
|
'details': self.settings.get('bank_details', as_type=LazyI18nString),
|
||||||
|
}
|
||||||
|
return template.render(ctx)
|
||||||
|
|
||||||
def order_pending_mail_render(self, order, payment) -> str:
|
def order_pending_mail_render(self, order, payment) -> str:
|
||||||
template = get_template('pretixplugins/banktransfer/email/order_pending.txt')
|
template = get_template('pretixplugins/banktransfer/email/order_pending.txt')
|
||||||
@@ -355,6 +531,8 @@ class BankTransfer(BasePaymentProvider):
|
|||||||
d = obj.info_data
|
d = obj.info_data
|
||||||
d['reference'] = '█'
|
d['reference'] = '█'
|
||||||
d['payer'] = '█'
|
d['payer'] = '█'
|
||||||
|
if 'send_invoice_to' in d:
|
||||||
|
d['send_invoice_to'] = '█'
|
||||||
d['_shredded'] = True
|
d['_shredded'] = True
|
||||||
obj.info = json.dumps(d)
|
obj.info = json.dumps(d)
|
||||||
obj.save(update_fields=['info'])
|
obj.save(update_fields=['info'])
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.urls import resolve, reverse
|
from django.urls import resolve, reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _, gettext_noop
|
||||||
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
from pretix.base.signals import register_payment_providers
|
from pretix.base.signals import logentry_display, register_payment_providers
|
||||||
from pretix.control.signals import html_head, nav_event, nav_organizer
|
from pretix.control.signals import html_head, nav_event, nav_organizer
|
||||||
|
|
||||||
|
from ...base.settings import settings_hierarkey
|
||||||
from .payment import BankTransfer
|
from .payment import BankTransfer
|
||||||
|
|
||||||
|
|
||||||
@@ -113,3 +115,30 @@ def html_head_presale(sender, request=None, **kwargs):
|
|||||||
return template.render({})
|
return template.render({})
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(signal=logentry_display)
|
||||||
|
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
||||||
|
plains = {
|
||||||
|
'pretix.plugins.banktransfer.order.email.invoice': _('The invoice was sent to the designated email address.'),
|
||||||
|
}
|
||||||
|
if logentry.action_type in plains:
|
||||||
|
return plains[logentry.action_type]
|
||||||
|
|
||||||
|
|
||||||
|
settings_hierarkey.add_default(
|
||||||
|
'payment_banktransfer_invoice_email_subject',
|
||||||
|
default_type=LazyI18nString,
|
||||||
|
value=LazyI18nString.from_gettext(gettext_noop("Invoice {invoice_number}"))
|
||||||
|
)
|
||||||
|
settings_hierarkey.add_default(
|
||||||
|
'payment_banktransfer_invoice_email_text',
|
||||||
|
default_type=LazyI18nString,
|
||||||
|
value=LazyI18nString.from_gettext(gettext_noop("""Hello,
|
||||||
|
|
||||||
|
you receive this message because an order for {event} was placed by {order_email} and we have been asked to forward the invoice to you.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
|
||||||
|
Your {event} team"""))
|
||||||
|
)
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = N
|
|||||||
).last()
|
).last()
|
||||||
|
|
||||||
p.info_data = {
|
p.info_data = {
|
||||||
|
**p.info_data,
|
||||||
'reference': trans.reference,
|
'reference': trans.reference,
|
||||||
'date': trans.date_parsed.isoformat() if trans.date_parsed else trans.date,
|
'date': trans.date_parsed.isoformat() if trans.date_parsed else trans.date,
|
||||||
'payer': trans.payer,
|
'payer': trans.payer,
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load ibanformat %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
<p>{% blocktrans trimmed %}
|
||||||
|
After completing your purchase, we will ask you to transfer the money to the following
|
||||||
|
bank account, using a personal reference code:
|
||||||
|
{% endblocktrans %}</p>
|
||||||
|
|
||||||
|
{% if settings.bank_details_type == "sepa" %}
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Account holder" %}: </dt><dd>{{ settings.bank_details_sepa_name }}</dd>
|
||||||
|
<dt>{% trans "IBAN" %}: </dt><dd>{{ settings.bank_details_sepa_iban|ibanformat }}</dd>
|
||||||
|
<dt>{% trans "BIC" %}: </dt><dd>{{ settings.bank_details_sepa_bic }}</dd>
|
||||||
|
<dt>{% trans "Bank" %}: </dt><dd>{{ settings.bank_details_sepa_bank }}</dd>
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if details %}
|
||||||
|
{{ details|linebreaks }}
|
||||||
|
{% endif %}
|
||||||
|
{% if code %}
|
||||||
|
<dl class="dl-horizontal">
|
||||||
|
<dt>{% trans "Reference code (important):" %} </dt><dd><strong>{{ code }}</strong></dd>
|
||||||
|
</dl>
|
||||||
|
{% else %}
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if request.session.payment_banktransfer_send_invoice and request.session.payment_banktransfer_send_invoice_to %}
|
||||||
|
<p>
|
||||||
|
{% blocktrans trimmed with recipient=request.session.payment_banktransfer_send_invoice_to %}
|
||||||
|
We will send a copy of your invoice directly to {{ recipient }}.
|
||||||
|
{% endblocktrans %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
+6
@@ -1,5 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load ibanformat %}
|
{% load ibanformat %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
<p>{% blocktrans trimmed %}
|
<p>{% blocktrans trimmed %}
|
||||||
After completing your purchase, we will ask you to transfer the money to the following
|
After completing your purchase, we will ask you to transfer the money to the following
|
||||||
@@ -29,3 +30,8 @@
|
|||||||
</strong>
|
</strong>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if form.fields %}
|
||||||
|
<div class="col-md-12">
|
||||||
|
{% bootstrap_form form layout='inline' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|||||||
@@ -2,8 +2,14 @@
|
|||||||
|
|
||||||
{% if payment_info %}
|
{% if payment_info %}
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>{% trans "Payer" %}</dt>
|
{% if payment_info.send_invoice_to %}
|
||||||
<dd>{{ payment_info.payer }}</dd>
|
<dt>{% trans "Send invoice to" %}</dt>
|
||||||
|
<dd>{{ payment_info.send_invoice_to }}</dd>
|
||||||
|
{% endif %}
|
||||||
|
{% if payment_info.payer %}
|
||||||
|
<dt>{% trans "Payer" %}</dt>
|
||||||
|
<dd>{{ payment_info.payer }}</dd>
|
||||||
|
{% endif %}
|
||||||
{% if payment_info.iban %}
|
{% if payment_info.iban %}
|
||||||
<dt>{% trans "Account" %}
|
<dt>{% trans "Account" %}
|
||||||
<dd>
|
<dd>
|
||||||
|
|||||||
Reference in New Issue
Block a user