forked from CGM_Public/pretix_original
Added a payment provider for free products
This commit is contained in:
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-06-21 19:18+0000\n"
|
||||
"PO-Revision-Date: 2015-06-21 21:19+0100\n"
|
||||
"PO-Revision-Date: 2015-06-23 09:51+0100\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: Raphael Michel <michel@rami.io>\n"
|
||||
"Language: de\n"
|
||||
@@ -1483,7 +1483,7 @@ msgstr "Als nicht bezahlt markieren"
|
||||
#: pretix/control/templates/pretixcontrol/order/refund.html:4
|
||||
#: pretix/control/templates/pretixcontrol/order/refund.html:8
|
||||
msgid "Refund order"
|
||||
msgstr "Bestellung erstatteten"
|
||||
msgstr "Bestellung erstatten"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html:42
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:65
|
||||
|
||||
@@ -2,15 +2,19 @@ from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.db.models import Sum, Q
|
||||
from django.dispatch import receiver
|
||||
|
||||
from django.forms import Form
|
||||
from django.http import HttpRequest
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from pretix.base.forms import SettingsForm
|
||||
from pretix.base.models import Order
|
||||
from pretix.base.models import Order, CartPosition
|
||||
from pretix.base.services.orders import mark_order_paid
|
||||
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
from pretix.base.signals import register_payment_providers
|
||||
|
||||
|
||||
class BasePaymentProvider:
|
||||
@@ -154,6 +158,16 @@ class BasePaymentProvider:
|
||||
form.fields = self.checkout_form_fields
|
||||
return form
|
||||
|
||||
def is_allowed(self, request: HttpRequest) -> bool:
|
||||
"""
|
||||
You can use this method to disable this payment provider for certain groups
|
||||
of users, products or other criteria. If this method returns ``False``, the
|
||||
user will not be able to select this payment method.
|
||||
|
||||
The default implementation always returns ``True``.
|
||||
"""
|
||||
return True
|
||||
|
||||
def checkout_form_render(self, request: HttpRequest) -> str:
|
||||
"""
|
||||
When the user selects this provider as his prefered payment method,
|
||||
@@ -243,7 +257,7 @@ class BasePaymentProvider:
|
||||
containing an URL the user will be redirected to. If you are done with your process
|
||||
you should return the user to the order's detail page.
|
||||
|
||||
If the payment is completed, you should call ``pretix.bsae.services.orders.mark_order_paid(order, provider, info)``
|
||||
If the payment is completed, you should call ``pretix.base.services.orders.mark_order_paid(order, provider, info)``
|
||||
with ``provider`` being your :py:attr:`identifier` and ``info`` being any string
|
||||
you might want to store for later usage. Please note, that if you want to store
|
||||
something inside ``order.payment_info``, please do it after the ``mark_order_paid`` call,
|
||||
@@ -345,3 +359,67 @@ class BasePaymentProvider:
|
||||
order.mark_refunded()
|
||||
messages.success(request, _('The order has been marked as refunded. Please transfer the money '
|
||||
'back to the buyer manually.'))
|
||||
|
||||
|
||||
class FreeOrderProvider(BasePaymentProvider):
|
||||
|
||||
@property
|
||||
def is_enabled(self) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def identifier(self) -> str:
|
||||
return "free"
|
||||
|
||||
def checkout_confirm_render(self, request) -> str:
|
||||
return _("No payment is required as this order only includes products which are free of charge.")
|
||||
|
||||
def order_pending_render(self, request: HttpRequest, order: Order) -> str:
|
||||
pass
|
||||
|
||||
def checkout_is_valid_session(self, request: HttpRequest) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def verbose_name(self) -> str:
|
||||
return _("Free of charge")
|
||||
|
||||
def checkout_perform(self, request: HttpRequest, order: Order):
|
||||
mark_order_paid(order, 'free')
|
||||
|
||||
@property
|
||||
def settings_form_fields(self) -> dict:
|
||||
return {}
|
||||
|
||||
def order_control_refund_render(self, order: Order) -> str:
|
||||
return ''
|
||||
|
||||
def order_control_refund_perform(self, request: HttpRequest, order: Order) -> "bool|str":
|
||||
"""
|
||||
Will be called if the event administrator confirms the refund.
|
||||
|
||||
This should transfer the money back (if possible). You can return an URL the
|
||||
user should be redirected to if you need special behaviour or None to continue
|
||||
with default behaviour.
|
||||
|
||||
On failure, you should use Django's message framework to display an error message
|
||||
to the user.
|
||||
|
||||
The default implementation sets the Orders state to refunded and shows a success
|
||||
message.
|
||||
|
||||
:param request: The HTTP request
|
||||
:param order: The order object
|
||||
"""
|
||||
order.mark_refunded()
|
||||
messages.success(request, _('The order has been marked as refunded.'))
|
||||
|
||||
def is_allowed(self, request: HttpRequest) -> bool:
|
||||
return CartPosition.objects.current.filter(
|
||||
Q(user=request.user) & Q(event=request.event)
|
||||
).aggregate(sum=Sum('price'))['sum'] == 0
|
||||
|
||||
|
||||
@receiver(register_payment_providers)
|
||||
def register_payment_provider(sender, **kwargs):
|
||||
return FreeOrderProvider
|
||||
|
||||
@@ -29,6 +29,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
# Find the Django application this belongs to
|
||||
searchpath = receiver.__module__
|
||||
app = None
|
||||
mod = None
|
||||
while "." in searchpath:
|
||||
try:
|
||||
if apps.is_installed(searchpath):
|
||||
@@ -37,8 +38,8 @@ class EventPluginSignal(django.dispatch.Signal):
|
||||
pass
|
||||
searchpath, mod = searchpath.rsplit(".", 1)
|
||||
|
||||
# Only fire receivers from active plugins
|
||||
if app.name in sender.get_plugins():
|
||||
# Only fire receivers from active plugins and core modules
|
||||
if (searchpath, mod) == ("pretix", "base") or (app and app.name in sender.get_plugins()):
|
||||
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
|
||||
response = receiver(signal=self, sender=sender, **named)
|
||||
responses.append((receiver, response))
|
||||
|
||||
@@ -136,7 +136,9 @@ class PaymentSettings(EventPermissionRequiredMixin, TemplateView, SingleObjectMi
|
||||
)
|
||||
provider.settings_content = provider.settings_content_render(self.request)
|
||||
provider.form.prepare_fields()
|
||||
providers.append(provider)
|
||||
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:
|
||||
|
||||
@@ -35,16 +35,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{# TODO: Question answers #}
|
||||
<div class="row-fluid">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
{% if payment_provider.identifier != "free" %}
|
||||
<div class="pull-right">
|
||||
<a href="{% url "presale:event.checkout.payment" organizer=request.event.organizer.slug event=request.event.slug %}">
|
||||
<span class="fa fa-edit"></span>
|
||||
{% trans "Modify" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h3 class="panel-title">
|
||||
{% trans "Payment" %}
|
||||
</h3>
|
||||
@@ -57,7 +58,7 @@
|
||||
<div class="row checkout-button-row">
|
||||
<div class="col-md-4">
|
||||
<a class="btn btn-block btn-default btn-lg"
|
||||
href="{{ view.get_payment_url }}">
|
||||
href="{{ view.get_previous_url }}">
|
||||
{% trans "Go back" %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -153,7 +153,7 @@ class PaymentDetails(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin,
|
||||
responses = register_payment_providers.send(self.request.event)
|
||||
for receiver, response in responses:
|
||||
provider = response(self.request.event)
|
||||
if not provider.is_enabled:
|
||||
if not provider.is_enabled or not provider.is_allowed(self.request):
|
||||
continue
|
||||
fee = provider.calculate_fee(self._total_order_value)
|
||||
providers.append({
|
||||
@@ -178,6 +178,12 @@ class PaymentDetails(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin,
|
||||
messages.error(self.request, _("Please select a payment method."))
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if self._total_order_value == 0:
|
||||
request.session['payment'] = 'free'
|
||||
return redirect(self.get_confirm_url())
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['providers'] = self.provider_forms
|
||||
@@ -208,6 +214,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['cart'] = self.get_cart(answers=True)
|
||||
ctx['payment'] = self.payment_provider.checkout_confirm_render(self.request)
|
||||
ctx['payment_provider'] = self.payment_provider
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
@@ -225,7 +232,9 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
|
||||
if 'payment' not in request.session or not self.payment_provider:
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_payment_url())
|
||||
if not self.payment_provider.checkout_is_valid_session(request):
|
||||
if not self.payment_provider.checkout_is_valid_session(request) or \
|
||||
not self.payment_provider.is_enabled or \
|
||||
not self.payment_provider.is_allowed(request):
|
||||
messages.error(request, _('The payment information you entered was incomplete.'))
|
||||
return redirect(self.get_payment_url())
|
||||
for cp in self.positions:
|
||||
@@ -348,3 +357,7 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
|
||||
)
|
||||
OrderPosition.transform_cart_positions(cartpos, order)
|
||||
return order
|
||||
|
||||
def get_previous_url(self):
|
||||
if self.payment_provider != "free":
|
||||
return self.get_payment_url()
|
||||
|
||||
Reference in New Issue
Block a user