mirror of
https://github.com/pretix/pretix.git
synced 2026-05-03 14:54:04 +00:00
Enhance payment method validation
This commit is contained in:
@@ -78,7 +78,12 @@ class BasePaymentProvider:
|
||||
"""
|
||||
form = Form(
|
||||
data=(request.POST if request.method == 'POST' else None),
|
||||
prefix='payment_%s' % self.identifier
|
||||
prefix='payment_%s' % self.identifier,
|
||||
initial={
|
||||
k.replace('payment_%s_' % self.identifier, ''): v
|
||||
for k, v in request.session.items()
|
||||
if k.startswith('payment_%s_' % self.identifier)
|
||||
}
|
||||
)
|
||||
form.fields = self.checkout_form_fields
|
||||
return form
|
||||
@@ -115,3 +120,11 @@ class BasePaymentProvider:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
"""
|
||||
This is called at the time the user tries to place the order. It should return
|
||||
True, if the user's session is valid and all data your payment provider requires
|
||||
in future steps is present.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -26,3 +26,6 @@ class BankTransfer(BasePaymentProvider):
|
||||
|
||||
def checkout_prepare(self, request, total):
|
||||
return True
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
return True
|
||||
|
||||
@@ -17,3 +17,6 @@ class Stripe(BasePaymentProvider):
|
||||
required=False
|
||||
))
|
||||
])
|
||||
|
||||
def checkout_is_valid_session(self, request):
|
||||
return False
|
||||
|
||||
@@ -33,7 +33,21 @@
|
||||
</div>
|
||||
</div>
|
||||
{# TODO: Question answers #}
|
||||
{# TODO: Payment method #}
|
||||
<div class="row-fluid">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right">
|
||||
<a href="{% url "presale:event.checkout.payment" organizer=request.event.organizer.slug event=request.event.slug %}">{% trans "Modify" %}</a>
|
||||
</div>
|
||||
<h3 class="panel-title">
|
||||
{% trans "Payment" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{{ payment }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row checkout-button-row">
|
||||
<div class="col-md-4 col-md-offset-8">
|
||||
<button class="btn btn-block btn-primary btn-lg" type="submit">
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
<strong class="pull-right">+ {{ p.fee|floatformat:2 }} {{ event.currency }}</strong>
|
||||
<input type="radio" name="payment" value="{{ p.provider.identifier }}"
|
||||
data-parent="#payment_accordion"
|
||||
{% if selected == p.provider.identifier %}checked="checked"{% endif %}
|
||||
data-toggle="radiocollapse" data-target="#payment_{{ p.provider.identifier }}" />
|
||||
<strong>{{ p.provider.verbose_name }}</strong>
|
||||
</label>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="payment_{{ p.provider.identifier }}"
|
||||
class="panel-collapse collapse {% if request.POST.payment == p.provider.identifier %}in{% endif %}">
|
||||
class="panel-collapse collapse {% if selected == p.provider.identifier %}in{% endif %}">
|
||||
<div class="panel-body form-horizontal">
|
||||
{{ p.form }}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ from django.contrib.auth.views import redirect_to_login
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from django.db.models import Q
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import CartPosition
|
||||
@@ -35,6 +36,22 @@ class EventLoginRequiredMixin:
|
||||
|
||||
class CartDisplayMixin:
|
||||
|
||||
@cached_property
|
||||
def cartpos(self):
|
||||
"""
|
||||
A list of this users cart position
|
||||
"""
|
||||
return list(CartPosition.objects.current.filter(
|
||||
Q(user=self.request.user) & Q(event=self.request.event)
|
||||
).order_by(
|
||||
'item', 'variation'
|
||||
).select_related(
|
||||
'item', 'variation'
|
||||
).prefetch_related(
|
||||
'variation__values', 'variation__values__prop',
|
||||
'item__questions', 'answers'
|
||||
))
|
||||
|
||||
def get_cart(self):
|
||||
cartpos = CartPosition.objects.current.filter(
|
||||
Q(user=self.request.user) & Q(event=self.request.event)
|
||||
|
||||
@@ -76,7 +76,7 @@ class QuestionsForm(forms.Form):
|
||||
self.fields['question_%s' % q.identity] = field
|
||||
|
||||
|
||||
class CheckoutStart(EventViewMixin, EventLoginRequiredMixin, TemplateView):
|
||||
class CheckoutStart(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/checkout_questions.html"
|
||||
|
||||
def get_success_url(self):
|
||||
@@ -115,22 +115,6 @@ class CheckoutStart(EventViewMixin, EventLoginRequiredMixin, TemplateView):
|
||||
formlist.append(form)
|
||||
return formlist
|
||||
|
||||
@cached_property
|
||||
def cartpos(self):
|
||||
"""
|
||||
A list of this users cart position
|
||||
"""
|
||||
return list(CartPosition.objects.current.filter(
|
||||
Q(user=self.request.user) & Q(event=self.request.event)
|
||||
).order_by(
|
||||
'item', 'variation'
|
||||
).select_related(
|
||||
'item', 'variation'
|
||||
).prefetch_related(
|
||||
'variation__values', 'variation__values__prop',
|
||||
'item__questions', 'answers'
|
||||
))
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
failed = False
|
||||
for form in self.forms:
|
||||
@@ -242,13 +226,79 @@ class PaymentDetails(EventViewMixin, EventLoginRequiredMixin, TemplateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['providers'] = self.provider_forms
|
||||
ctx['selected'] = self.request.POST.get('payment', self.request.session.get('payment', ''))
|
||||
return ctx
|
||||
|
||||
|
||||
class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, TemplateView):
|
||||
template_name = "pretixpresale/event/checkout_confirm.html"
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('presale:event.checkout.success', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
})
|
||||
|
||||
def get_url(self):
|
||||
return reverse('presale:event.checkout.confirm', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
})
|
||||
|
||||
def get_previous_url(self):
|
||||
return reverse('presale:event.checkout.payment', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['cart'] = self.get_cart()
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
def payment_provider(self):
|
||||
responses = register_payment_providers.send(self.request.event)
|
||||
for receiver, response in responses:
|
||||
provider = response(self.request.event)
|
||||
if provider.identifier == self.request.session['payment']:
|
||||
return provider
|
||||
|
||||
def check_process(self, request):
|
||||
if not self.payment_provider:
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_previous_url())
|
||||
if not self.payment_provider.checkout_is_valid_session(request):
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_previous_url())
|
||||
if len(self.cart_items) == 0:
|
||||
messages.warning(request, _('Your cart is empty.'))
|
||||
return redirect(reverse('presale:event.index', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
}))
|
||||
for cp in self.cart_items:
|
||||
answ = {
|
||||
aw.question_id: aw.answer for aw in cp.answers.all()
|
||||
}
|
||||
for q in cp.item.questions.all():
|
||||
if q.required and q.identity not in answ:
|
||||
messages.warning(request, _('Please fill in answers to all required questions.'))
|
||||
return redirect(reverse('presale:event.checkout.start', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
}))
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
check = self.check_process(request)
|
||||
if check:
|
||||
return check
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
check = self.check_process(request)
|
||||
if check:
|
||||
return check
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user