mirror of
https://github.com/pretix/pretix.git
synced 2026-08-11 10:57:00 +00:00
refactor payment qr codes
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import text_unidecode
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
def dotdecimal(value):
|
||||
return str(value).replace(",", ".")
|
||||
|
||||
|
||||
def commadecimal(value):
|
||||
return str(value).replace(".", ",")
|
||||
|
||||
|
||||
def generate_payment_qr_codes(
|
||||
event,
|
||||
code,
|
||||
amount,
|
||||
bank_details_sepa_bic,
|
||||
bank_details_sepa_name,
|
||||
bank_details_sepa_iban
|
||||
):
|
||||
out = []
|
||||
qr_data = swiss_qrbill(
|
||||
event,
|
||||
code,
|
||||
amount,
|
||||
bank_details_sepa_bic,
|
||||
bank_details_sepa_name,
|
||||
bank_details_sepa_iban
|
||||
)
|
||||
if qr_data:
|
||||
out.append({
|
||||
"id": "qrbill",
|
||||
"label": "QR-bill",
|
||||
"html_prefix": mark_safe('<svg class="banktransfer-swiss-cross" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.8 19.8"><path stroke="#fff" stroke-width="1.436" d="M.7.7h18.4v18.4H.7z"/><path fill="#fff" d="M8.3 4h3.3v11H8.3z"/><path fill="#fff" d="M4.4 7.9h11v3.3h-11z"/></svg>'),
|
||||
"qr_data": qr_data,
|
||||
"css_class": "banktransfer-swiss-cross-overlay",
|
||||
})
|
||||
|
||||
if event.currency == 'EUR' and bank_details_sepa_iban:
|
||||
out.append({
|
||||
"id": "girocode",
|
||||
"label": "EPC-QR",
|
||||
"qr_data": "\n".join(text_unidecode.unidecode(str(d or '')) for d in [
|
||||
"BCD", # Service Tag: ‘BCD’
|
||||
"002", # Version: V2
|
||||
"2", # Character set: ISO 8859-1
|
||||
"SCT", # Identification code: ‘SCT‘
|
||||
bank_details_sepa_bic, # AT-23 BIC of the Beneficiary Bank
|
||||
bank_details_sepa_name, # AT-21 Name of the Beneficiary
|
||||
bank_details_sepa_iban, # AT-20 Account number of the Beneficiary
|
||||
f"{event.currency}{dotdecimal(amount)}", # AT-04 Amount of the Credit Transfer in Euro
|
||||
"", # AT-44 Purpose of the Credit Transfer
|
||||
"", # AT-05 Remittance Information (Structured)
|
||||
code, # AT-05 Remittance Information (Unstructured)
|
||||
"", # Beneficiary to originator information
|
||||
"",
|
||||
]),
|
||||
})
|
||||
|
||||
qr_data = f"bank://singlepaymentsepa?" + urlencode({
|
||||
"name": bank_details_sepa_name,
|
||||
"iban":bank_details_sepa_iban,
|
||||
"bic": bank_details_sepa_bic,
|
||||
"amount": commadecimal(amount),
|
||||
"reason": code,
|
||||
"currency": event.currency,
|
||||
})
|
||||
out.append({
|
||||
"id": "bezahlcode",
|
||||
"label": "BezahlCode",
|
||||
"qr_data": mark_safe(qr_data),
|
||||
"link": qr_data,
|
||||
"link_aria_label": _("Open BezahlCode in your banking app to start the payment process."),
|
||||
})
|
||||
return out
|
||||
|
||||
def swiss_qrbill(
|
||||
event,
|
||||
code,
|
||||
amount,
|
||||
bank_details_sepa_bic,
|
||||
bank_details_sepa_name,
|
||||
bank_details_sepa_iban
|
||||
):
|
||||
if not bank_details_sepa_iban or not bank_details_sepa_iban[:2] in ('CH', 'LI'):
|
||||
return
|
||||
if event.currency not in ('EUR', 'CHF'):
|
||||
return
|
||||
if not event.settings.invoice_address_from or not event.settings.invoice_address_from_country:
|
||||
return
|
||||
|
||||
data_fields = [
|
||||
'SPC',
|
||||
'0200',
|
||||
'1',
|
||||
bank_details_sepa_iban,
|
||||
'K',
|
||||
bank_details_sepa_name[:70],
|
||||
event.settings.invoice_address_from.replace('\n', ', ')[:70],
|
||||
(event.settings.invoice_address_from_zipcode + ' ' + event.settings.invoice_address_from_city)[:70],
|
||||
'',
|
||||
'',
|
||||
str(event.settings.invoice_address_from_country),
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
str(amount),
|
||||
event.currency,
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'NON',
|
||||
'', # structured reference
|
||||
code,
|
||||
'EPD',
|
||||
]
|
||||
|
||||
data_fields = [text_unidecode.unidecode(d or '') for d in data_fields]
|
||||
return '\r\n'.join(data_fields)
|
||||
@@ -46,12 +46,12 @@ from i18nfield.forms import I18nTextInput
|
||||
from i18nfield.strings import LazyI18nString
|
||||
from localflavor.generic.forms import BICFormField, IBANFormField
|
||||
from localflavor.generic.validators import IBANValidator
|
||||
from text_unidecode import unidecode
|
||||
|
||||
from pretix.base.forms import I18nMarkdownTextarea
|
||||
from pretix.base.models import InvoiceAddress, Order, OrderPayment, OrderRefund
|
||||
from pretix.base.payment import BasePaymentProvider
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.helpers.payment import generate_payment_qr_codes
|
||||
from pretix.plugins.banktransfer.templatetags.ibanformat import ibanformat
|
||||
from pretix.presale.views.cart import cart_session
|
||||
|
||||
@@ -313,51 +313,6 @@ class BankTransfer(BasePaymentProvider):
|
||||
t += str(self.settings.get('bank_details', as_type=LazyI18nString))
|
||||
return t
|
||||
|
||||
def swiss_qrbill(self, payment):
|
||||
if not self.settings.get('bank_details_sepa_iban') or not self.settings.get('bank_details_sepa_iban')[:2] in ('CH', 'LI'):
|
||||
return
|
||||
if self.event.currency not in ('EUR', 'CHF'):
|
||||
return
|
||||
if not self.event.settings.invoice_address_from or not self.event.settings.invoice_address_from_country:
|
||||
return
|
||||
|
||||
data_fields = [
|
||||
'SPC',
|
||||
'0200',
|
||||
'1',
|
||||
self.settings.get('bank_details_sepa_iban'),
|
||||
'K',
|
||||
self.settings.get('bank_details_sepa_name')[:70],
|
||||
self.event.settings.invoice_address_from.replace('\n', ', ')[:70],
|
||||
(self.event.settings.invoice_address_from_zipcode + ' ' + self.event.settings.invoice_address_from_city)[:70],
|
||||
'',
|
||||
'',
|
||||
str(self.event.settings.invoice_address_from_country),
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
'', # rfu
|
||||
str(payment.amount),
|
||||
self.event.currency,
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'', # debtor address
|
||||
'NON',
|
||||
'', # structured reference
|
||||
self._code(payment.order),
|
||||
'EPD',
|
||||
]
|
||||
|
||||
data_fields = [unidecode(d or '') for d in data_fields]
|
||||
return '\r\n'.join(data_fields)
|
||||
|
||||
def payment_pending_render(self, request: HttpRequest, payment: OrderPayment):
|
||||
template = get_template('pretixplugins/banktransfer/pending.html')
|
||||
ctx = {
|
||||
@@ -367,13 +322,18 @@ class BankTransfer(BasePaymentProvider):
|
||||
'amount': payment.amount,
|
||||
'payment_info': payment.info_data,
|
||||
'settings': self.settings,
|
||||
'swiss_qrbill': self.swiss_qrbill(payment),
|
||||
'eu_barcodes': self.event.currency == 'EUR',
|
||||
'payment_qr_codes': generate_payment_qr_codes(
|
||||
event=self.event,
|
||||
code=self._code(payment.order),
|
||||
amount=payment.amount,
|
||||
bank_details_sepa_bic=self.settings.get('bank_details_sepa_bic'),
|
||||
bank_details_sepa_name=self.settings.get('bank_details_sepa_name'),
|
||||
bank_details_sepa_iban=self.settings.get('bank_details_sepa_iban'),
|
||||
) if self.settings.bank_details_type == "sepa" else None,
|
||||
'pending_description': self.settings.get('pending_description', as_type=LazyI18nString),
|
||||
'details': self.settings.get('bank_details', as_type=LazyI18nString),
|
||||
'has_invoices': payment.order.invoices.exists(),
|
||||
}
|
||||
ctx['any_barcodes'] = ctx['swiss_qrbill'] or ctx['eu_barcodes']
|
||||
return template.render(ctx, request=request)
|
||||
|
||||
def payment_control_render(self, request: HttpRequest, payment: OrderPayment) -> str:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load commadecimal %}
|
||||
{% load static %}
|
||||
{% load dotdecimal %}
|
||||
{% load ibanformat %}
|
||||
{% load money %}
|
||||
@@ -17,7 +16,7 @@
|
||||
{% endblocktrans %}</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="{% if settings.bank_details_type == "sepa" %}col-md-6{% else %}col-md-12{% endif %} col-xs-12">
|
||||
<div class="{% if payment_qr_codes %}col-md-6{% else %}col-md-12{% endif %} col-xs-12">
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Reference code (important):" %}</dt><dd><b>{{ code }}</b></dd>
|
||||
<dt>{% trans "Amount:" %}</dt><dd>{{ amount|money:event.currency }}</dd>
|
||||
@@ -36,94 +35,7 @@
|
||||
{% trans "We will send you an email as soon as we received your payment." %}
|
||||
</p>
|
||||
</div>
|
||||
{% if settings.bank_details_type == "sepa" and any_barcodes %}
|
||||
<div class="tabcontainer col-md-6 col-sm-6 hidden-xs text-center js-only blank-after">
|
||||
<div id="banktransfer_qrcodes_tabs_content" class="tabpanels blank-after">
|
||||
{% if swiss_qrbill %}
|
||||
<div id="banktransfer_qrcodes_qrbill"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
aria-labelledby="banktransfer_qrcodes_qrbill_tab"
|
||||
>
|
||||
<div class="banktransfer-swiss-cross-overlay" role="figure" aria-labelledby="banktransfer_qrcodes_qrbill_tab banktransfer_qrcodes_label">
|
||||
<svg class="banktransfer-swiss-cross" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.8 19.8"><path stroke="#fff" stroke-width="1.436" d="M.7.7h18.4v18.4H.7z"/><path fill="#fff" d="M8.3 4h3.3v11H8.3z"/><path fill="#fff" d="M4.4 7.9h11v3.3h-11z"/></svg>
|
||||
<script type="text/plain" data-size="150" data-replace-with-qr data-desc="{% trans 'Scan this image with your banking app’s QR-Reader to start the payment process.' %}">{{swiss_qrbill}}</script>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if eu_barcodes %}
|
||||
<div id="banktransfer_qrcodes_girocode"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
{{ swiss_qrbill|yesno:'hidden,' }}
|
||||
aria-labelledby="banktransfer_qrcodes_girocode_tab"
|
||||
>
|
||||
<div role="figure" aria-labelledby="banktransfer_qrcodes_girocode_tab banktransfer_qrcodes_label">
|
||||
<script type="text/plain" data-size="150" data-replace-with-qr data-desc="{% trans 'Scan this image with your banking app’s QR-Reader to start the payment process.' %}">BCD
|
||||
002
|
||||
2
|
||||
SCT
|
||||
{{ settings.bank_details_sepa_bic }}
|
||||
{{ settings.bank_details_sepa_name|unidecode }}
|
||||
{{ settings.bank_details_sepa_iban }}
|
||||
{{ event.currency }}{{ amount|dotdecimal }}
|
||||
|
||||
|
||||
{{ code }}
|
||||
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div id="banktransfer_qrcodes_bezahlcode"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
hidden
|
||||
aria-labelledby="banktransfer_qrcodes_bezahlcode_tab"
|
||||
>
|
||||
<a aria-label="{% trans "Open BezahlCode in your banking app to start the payment process." %}" href="bank://singlepaymentsepa?name={{ settings.bank_details_sepa_name|urlencode }}&iban={{ settings.bank_details_sepa_iban }}&bic={{ settings.bank_details_sepa_bic }}&amount={{ amount|commadecimal }}&reason={{ code }}¤cy={{ event.currency }}">
|
||||
<div role="figure" aria-labelledby="banktransfer_qrcodes_bezahlcode_tab banktransfer_qrcodes_label">
|
||||
<script type="text/plain" data-size="150" data-replace-with-qr data-desc="{% trans 'Scan this image with your banking app’s QR-Reader to start the payment process.' %}">bank://singlepaymentsepa?name={{ settings.bank_details_sepa_name|urlencode }}&iban={{ settings.bank_details_sepa_iban }}&bic={{ settings.bank_details_sepa_bic }}&amount={{ amount|commadecimal }}&reason={{ code }}¤cy={{ event.currency }}</script>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="banktransfer_qrcodes_tabs" role="tablist" aria-labelledby="banktransfer_qrcodes_label" class="blank-after btn-group">
|
||||
{% if swiss_qrbill %}
|
||||
<button
|
||||
class="btn btn-default"
|
||||
id="banktransfer_qrcodes_qrbill_tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="banktransfer_qrcodes_qrbill"
|
||||
aria-selected="true"
|
||||
tabindex="-1">QR-bill</button>
|
||||
{% endif %}
|
||||
{% if eu_barcodes %}
|
||||
<button
|
||||
class="btn btn-default"
|
||||
id="banktransfer_qrcodes_girocode_tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="banktransfer_qrcodes_girocode"
|
||||
aria-selected="{{ swiss_qrbill|yesno:"false,true" }}"
|
||||
tabindex="-1">EPC-QR</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
id="banktransfer_qrcodes_bezahlcode_tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="banktransfer_qrcodes_bezahlcode"
|
||||
aria-selected="false"
|
||||
tabindex="-1">BezahlCode</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-muted" id="banktransfer_qrcodes_label">
|
||||
{% trans "Scan the QR code with your banking app" %}
|
||||
</p>
|
||||
</div>
|
||||
{% if payment_qr_codes %}
|
||||
{% include "pretixpresale/event/payment_qr_codes.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if swiss_qrbill %}
|
||||
<link rel="stylesheet" href="{% static "pretixplugins/banktransfer/swisscross.css" %}">
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% if payment_qr_codes %}
|
||||
<div class="tabcontainer col-md-6 col-sm-6 hidden-xs text-center js-only blank-after">
|
||||
<div id="banktransfer_qrcodes_tabs_content" class="tabpanels blank-after">
|
||||
{% for code_info in payment_qr_codes %}
|
||||
<div id="banktransfer_qrcodes_{{ code_info.id }}"
|
||||
role="tabpanel"
|
||||
tabindex="0"
|
||||
{% if not forloop.first %}hidden{% endif %}
|
||||
aria-labelledby="banktransfer_qrcodes_{{ code_info.id }}_tab"
|
||||
>
|
||||
{% if code_info.link %}<a aria-label="{{ code_info.link_aria_label }}" href="{{ code_info.link }}">{% endif %}
|
||||
<div class="{{ code_info.css_class }}" role="figure" aria-labelledby="banktransfer_qrcodes_{{ code_info.id }}_tab banktransfer_qrcodes_label">
|
||||
{{ code_info.html_prefix }}
|
||||
<script type="text/plain" data-size="150" data-replace-with-qr data-desc="{% trans 'Scan this image with your banking app’s QR-Reader to start the payment process.' %}">{{ code_info.qr_data }}</script>
|
||||
</div>
|
||||
{% if code_info.link %}</a>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div id="banktransfer_qrcodes_tabs" role="tablist" aria-labelledby="banktransfer_qrcodes_label" class="blank-after btn-group">
|
||||
{% for code_info in payment_qr_codes %}
|
||||
<button
|
||||
class="btn btn-default"
|
||||
id="banktransfer_qrcodes_{{ code_info.id }}_tab"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="banktransfer_qrcodes_{{ code_info.id }}"
|
||||
aria-selected="{{ forloop.first|yesno:"true,false" }}"
|
||||
tabindex="-1">{{ code_info.label }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="text-muted" id="banktransfer_qrcodes_label">
|
||||
{% trans "Scan the QR code with your banking app" %}
|
||||
</p>
|
||||
</div>
|
||||
{% for code_info in payment_qr_codes %}
|
||||
{% if code_info.id == "qrbill" %}
|
||||
<link rel="stylesheet" href="{% static "pretixplugins/banktransfer/swisscross.css" %}">
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user