mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Backend UX: Restructure payment settings
This commit is contained in:
@@ -411,7 +411,10 @@ class EventSettingsForm(SettingsForm):
|
||||
class PaymentSettingsForm(SettingsForm):
|
||||
payment_term_days = forms.IntegerField(
|
||||
label=_('Payment term in days'),
|
||||
help_text=_("The number of days after placing an order the user has to pay to preserve their reservation."),
|
||||
help_text=_("The number of days after placing an order the user has to pay to preserve their reservation. If "
|
||||
"you use slow payment methods like bank transfer, we recommend 14 days. If you only use real-time "
|
||||
"payment methods, we recommend still setting two or three days to allow people to retry failed "
|
||||
"payments."),
|
||||
)
|
||||
payment_term_last = RelativeDateField(
|
||||
label=_('Last date of payments'),
|
||||
|
||||
@@ -5,49 +5,53 @@
|
||||
<form action="" method="post" class="form-horizontal form-plugins">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>{% trans "Payment settings" %}</legend>
|
||||
{% bootstrap_field sform.payment_term_days layout="control" %}
|
||||
{% bootstrap_field sform.payment_term_last layout="control" %}
|
||||
{% bootstrap_field sform.payment_term_weekdays layout="control" %}
|
||||
{% bootstrap_field sform.payment_term_expire_automatically layout="control" %}
|
||||
{% bootstrap_field sform.payment_term_accept_late layout="control" %}
|
||||
{% bootstrap_field sform.tax_rate_default layout="control" %}
|
||||
<legend>{% trans "Payment providers" %}</legend>
|
||||
<table class="table table-payment-providers">
|
||||
<tbody>
|
||||
{% for provider in providers %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ provider.verbose_name }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
{% if provider.is_enabled %}
|
||||
<span class="text-success">
|
||||
<span class="fa fa-check"></span>
|
||||
{% trans "Enabled" %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-danger">
|
||||
<span class="fa fa-times"></span>
|
||||
{% trans "Disabled" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a href="{% url 'control:event.settings.payment.provider' event=request.event.slug organizer=request.organizer.slug provider=provider.identifier %}"
|
||||
class="btn btn-default">
|
||||
<span class="fa fa-cog"></span>
|
||||
{% trans "Settings" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
{% trans "There are no payment providers available. Please go to the plugin settings and activate one or more payment plugins." %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{% trans "Payment providers" %}</legend>
|
||||
<div class="alert alert-warning">
|
||||
<span class="fa fa-w fa-legal fa-4x pull-left"></span>
|
||||
<strong>{% trans "Warning:" %}</strong>
|
||||
{% blocktrans trimmed %}
|
||||
Please note that EU Directive 2015/2366 bans surcharging payment fees for most common payment
|
||||
methods within the European Union. Depending on the payment method, this might affect
|
||||
selling to consumers only or to business customers as well. Depending on your country, this
|
||||
legislation might already be in effect or become relevant from January 2018 at the latest. This
|
||||
is not legal advice. If in doubt, consult a lawyer or refrain from charging payment fees.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% for provider in providers %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<a class="collapsed" data-toggle="collapse" href="#{{ provider.identifier }}">
|
||||
{{ provider.verbose_name }}
|
||||
<i class="fa fa-angle-down collapse-indicator"></i>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div id="{{ provider.identifier }}" class="panel-collapse collapse">
|
||||
<div class="panel-body">
|
||||
{% bootstrap_form provider.form layout='control' %}
|
||||
{% with c=provider.settings_content %}
|
||||
{% if c %}{{ c|safe }}{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<em>{% trans "There are no payment providers available. Please go to the plugin settings and activate one or more payment plugins." %}</em>
|
||||
{% endfor %}
|
||||
<legend>{% trans "General payment settings" %}</legend>
|
||||
{% bootstrap_field form.payment_term_days layout="control" %}
|
||||
{% bootstrap_field form.payment_term_last layout="control" %}
|
||||
{% bootstrap_field form.payment_term_weekdays layout="control" %}
|
||||
{% bootstrap_field form.payment_term_expire_automatically layout="control" %}
|
||||
{% bootstrap_field form.payment_term_accept_late layout="control" %}
|
||||
{% bootstrap_field form.tax_rate_default layout="control" %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{% extends "pretixcontrol/event/settings_base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% block inside %}
|
||||
<form action="" method="post" class="form-horizontal form-plugins">
|
||||
{% csrf_token %}
|
||||
<fieldset>
|
||||
<legend>
|
||||
<a href="{% url 'control:event.settings.payment' event=request.event.slug organizer=request.organizer.slug %}"
|
||||
class="btn btn-default btn-sm btn-link">
|
||||
<span class="fa fa-caret-left"></span>
|
||||
{% trans "Back" %}
|
||||
</a>
|
||||
{% trans "Payment provider:" %} {{ provider.verbose_name }}
|
||||
</legend>
|
||||
<div class="alert alert-warning">
|
||||
<span class="fa fa-w fa-legal fa-2x pull-left"></span>
|
||||
<strong>{% trans "Warning:" %}</strong>
|
||||
{% blocktrans trimmed %}
|
||||
Please note that EU Directive 2015/2366 bans surcharging payment fees for most common payment
|
||||
methods within the European Union. If in doubt, consult a lawyer or refrain from charging payment
|
||||
fees.
|
||||
{% endblocktrans %}
|
||||
<br>
|
||||
{% blocktrans trimmed %}
|
||||
In simple terms, this means you need to pay any fees imposed by the payment providers and cannot
|
||||
pass it on to your customers.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% bootstrap_form form layout='control' %}
|
||||
{% if settings_content %}{{ settings_content|safe }}{% endif %}
|
||||
</fieldset>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -76,6 +76,8 @@ urlpatterns = [
|
||||
url(r'^settings/$', event.EventUpdate.as_view(), name='event.settings'),
|
||||
url(r'^settings/plugins$', event.EventPlugins.as_view(), name='event.settings.plugins'),
|
||||
url(r'^settings/permissions$', event.EventPermissions.as_view(), name='event.settings.permissions'),
|
||||
url(r'^settings/payment/(?P<provider>[^/]+)$', event.PaymentProviderSettings.as_view(),
|
||||
name='event.settings.payment.provider'),
|
||||
url(r'^settings/payment$', event.PaymentSettings.as_view(), name='event.settings.payment'),
|
||||
url(r'^settings/tickets$', event.TicketSettings.as_view(), name='event.settings.tickets'),
|
||||
url(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
|
||||
|
||||
@@ -237,83 +237,11 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
|
||||
})
|
||||
|
||||
|
||||
class PaymentSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
class PaymentProviderSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, TemplateView, SingleObjectMixin):
|
||||
model = Event
|
||||
context_object_name = 'event'
|
||||
permission = 'can_change_event_settings'
|
||||
template_name = 'pretixcontrol/event/payment.html'
|
||||
|
||||
def get_object(self, queryset=None) -> Event:
|
||||
return self.request.event
|
||||
|
||||
@cached_property
|
||||
def provider_forms(self) -> list:
|
||||
providers = []
|
||||
for provider in self.request.event.get_payment_providers().values():
|
||||
provider.form = ProviderForm(
|
||||
obj=self.request.event,
|
||||
settingspref=provider.settings.get_prefix(),
|
||||
data=(self.request.POST if self.request.method == 'POST' else None)
|
||||
)
|
||||
provider.form.fields = OrderedDict(
|
||||
[
|
||||
('%s%s' % (provider.settings.get_prefix(), k), v)
|
||||
for k, v in provider.settings_form_fields.items()
|
||||
]
|
||||
)
|
||||
provider.settings_content = provider.settings_content_render(self.request)
|
||||
provider.form.prepare_fields()
|
||||
if provider.settings_content or provider.form.fields:
|
||||
# Exclude providers which do not provide any settings
|
||||
providers.append(provider)
|
||||
return providers
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['sform'] = self.sform
|
||||
return context
|
||||
|
||||
@cached_property
|
||||
def sform(self):
|
||||
return PaymentSettingsForm(
|
||||
obj=self.object,
|
||||
prefix='settings',
|
||||
data=self.request.POST if self.request.method == 'POST' else None
|
||||
)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
context = self.get_context_data(object=self.object)
|
||||
context['providers'] = self.provider_forms
|
||||
return self.render_to_response(context)
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
success = self.sform.is_valid()
|
||||
if success:
|
||||
self.sform.save()
|
||||
if self.sform.has_changed():
|
||||
self.request.event.log_action('pretix.event.settings', user=self.request.user, data={
|
||||
k: self.request.event.settings.get(k) for k in self.sform.changed_data
|
||||
})
|
||||
for provider in self.provider_forms:
|
||||
if provider.form.is_valid():
|
||||
if provider.form.has_changed():
|
||||
self.request.event.log_action(
|
||||
'pretix.event.payment.provider.' + provider.identifier, user=self.request.user, data={
|
||||
k: provider.form.cleaned_data.get(k) for k in provider.form.changed_data
|
||||
}
|
||||
)
|
||||
provider.form.save()
|
||||
else:
|
||||
success = False
|
||||
if success:
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
return redirect(self.get_success_url())
|
||||
else:
|
||||
messages.error(self.request, _('We could not save your changes. See below for details.'))
|
||||
return self.get(request)
|
||||
template_name = 'pretixcontrol/event/payment_provider.html'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.payment', kwargs={
|
||||
@@ -321,6 +249,63 @@ class PaymentSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, Temp
|
||||
'event': self.get_object().slug,
|
||||
})
|
||||
|
||||
@cached_property
|
||||
def object(self):
|
||||
return self.request.event
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
return self.object
|
||||
|
||||
@cached_property
|
||||
def provider(self):
|
||||
provider = self.request.event.get_payment_providers()[self.kwargs['provider']]
|
||||
if not provider:
|
||||
raise Http404()
|
||||
return provider
|
||||
|
||||
@cached_property
|
||||
def form(self):
|
||||
form = ProviderForm(
|
||||
obj=self.request.event,
|
||||
settingspref=self.provider.settings.get_prefix(),
|
||||
data=(self.request.POST if self.request.method == 'POST' else None)
|
||||
)
|
||||
form.fields = OrderedDict(
|
||||
[
|
||||
('%s%s' % (self.provider.settings.get_prefix(), k), v)
|
||||
for k, v in self.provider.settings_form_fields.items()
|
||||
]
|
||||
)
|
||||
form.prepare_fields()
|
||||
return form
|
||||
|
||||
@cached_property
|
||||
def settings_content(self):
|
||||
return self.provider.settings_content_render(self.request)
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['form'] = self.form
|
||||
context['provider'] = self.provider
|
||||
context['settings_content'] = self.settings_content
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
def post(self, request, *args, **kwargs):
|
||||
if self.form.is_valid():
|
||||
if self.form.has_changed():
|
||||
self.request.event.log_action(
|
||||
'pretix.event.payment.provider.' + self.provider.identifier, user=self.request.user, data={
|
||||
k: self.form.cleaned_data.get(k) for k in self.form.changed_data
|
||||
}
|
||||
)
|
||||
self.form.save()
|
||||
messages.success(self.request, _('Your changes have been saved.'))
|
||||
return redirect(self.get_success_url())
|
||||
else:
|
||||
messages.error(self.request, _('We could not save your changes. See below for details.'))
|
||||
return self.get(request)
|
||||
|
||||
|
||||
class EventSettingsFormView(EventPermissionRequiredMixin, FormView):
|
||||
model = Event
|
||||
@@ -368,6 +353,27 @@ class EventSettingsFormView(EventPermissionRequiredMixin, FormView):
|
||||
return self.get(request)
|
||||
|
||||
|
||||
class PaymentSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
template_name = 'pretixcontrol/event/payment.html'
|
||||
form_class = PaymentSettingsForm
|
||||
permission = 'can_change_event_settings'
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.settings.payment', kwargs={
|
||||
'organizer': self.request.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
})
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['providers'] = sorted(
|
||||
[p for p in self.request.event.get_payment_providers().values()
|
||||
if not p.is_implicit and (p.settings_form_fields or p.settings_content_render(self.request))],
|
||||
key=lambda s: s.verbose_name
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class InvoiceSettings(EventSettingsViewMixin, EventSettingsFormView):
|
||||
model = Event
|
||||
form_class = InvoiceSettingsForm
|
||||
|
||||
Reference in New Issue
Block a user