forked from CGM_Public/pretix_original
Refator payment provider, deal with cancellations
This commit is contained in:
@@ -458,11 +458,15 @@ class Order(LockModel, LoggedModel):
|
||||
positions = list(
|
||||
self.positions.all().annotate(
|
||||
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk')))
|
||||
).select_related('item')
|
||||
).select_related('item').prefetch_related('issued_gift_cards')
|
||||
)
|
||||
cancelable = all([op.item.allow_cancel and not op.has_checkin for op in positions])
|
||||
if not cancelable or not positions:
|
||||
return False
|
||||
for op in positions:
|
||||
for gc in op.issued_gift_cards.all():
|
||||
if gc.value != op.price:
|
||||
return False
|
||||
if self.user_cancel_deadline and now() > self.user_cancel_deadline:
|
||||
return False
|
||||
if self.status == Order.STATUS_PENDING:
|
||||
|
||||
@@ -7,6 +7,7 @@ from typing import Any, Dict, Union
|
||||
import pytz
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db import transaction
|
||||
from django.dispatch import receiver
|
||||
@@ -21,8 +22,8 @@ from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.forms import PlaceholderValidator
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, InvoiceAddress, Order, OrderPayment, OrderRefund,
|
||||
Quota,
|
||||
CartPosition, Event, GiftCard, InvoiceAddress, Order, OrderPayment,
|
||||
OrderRefund, Quota,
|
||||
)
|
||||
from pretix.base.reldate import RelativeDateField, RelativeDateWrapper
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
@@ -30,6 +31,7 @@ from pretix.base.signals import register_payment_providers
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.helpers.money import DecimalTextInput
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
from pretix.presale.views import get_cart_total
|
||||
from pretix.presale.views.cart import cart_session, get_or_create_cart_id
|
||||
|
||||
@@ -890,12 +892,11 @@ class OffsettingProvider(BasePaymentProvider):
|
||||
|
||||
|
||||
class GiftCardPayment(BasePaymentProvider):
|
||||
is_enabled = True
|
||||
identifier = "giftcard"
|
||||
verbose_name = _("Gift card")
|
||||
|
||||
def is_allowed(self, request: HttpRequest, total: Decimal=None) -> bool:
|
||||
return False
|
||||
return super().is_allowed(request, total) and self.event.organizer.has_gift_cards
|
||||
|
||||
def order_change_allowed(self, order: Order) -> bool:
|
||||
return False
|
||||
@@ -903,6 +904,9 @@ class GiftCardPayment(BasePaymentProvider):
|
||||
def execute_payment(self, request: HttpRequest, payment: OrderPayment) -> str:
|
||||
raise PaymentException("Invalid state, should never occur.")
|
||||
|
||||
def payment_form_render(self, request: HttpRequest, total: Decimal) -> str:
|
||||
return get_template('pretixcontrol/giftcards/checkout.html').render({})
|
||||
|
||||
def payment_control_render(self, request, payment) -> str:
|
||||
from .models import GiftCard
|
||||
|
||||
@@ -933,6 +937,42 @@ class GiftCardPayment(BasePaymentProvider):
|
||||
def payment_refund_supported(self, payment: OrderPayment) -> bool:
|
||||
return True
|
||||
|
||||
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]:
|
||||
cs = cart_session(request)
|
||||
try:
|
||||
gc = self.event.organizer.accepted_gift_cards.get(
|
||||
secret=request.POST.get("giftcard")
|
||||
)
|
||||
if gc.currency != self.event.currency:
|
||||
messages.error(request, _("This gift card does not support this currency."))
|
||||
return
|
||||
if gc.value <= Decimal("0.00"):
|
||||
messages.error(request, _("All credit on this gift card has been used."))
|
||||
return
|
||||
if 'gift_cards' not in cs:
|
||||
cs['gift_cards'] = []
|
||||
elif gc.pk in cs['gift_cards']:
|
||||
messages.error(request, _("This gift card is already used for your payment."))
|
||||
return
|
||||
cs['gift_cards'] = cs['gift_cards'] + [gc.pk]
|
||||
|
||||
remainder = cart['total'] - gc.value
|
||||
if remainder >= Decimal('0.00'):
|
||||
messages.success(request, _("Your gift card has been applied, but {} still need to be paid. Please select a payment method.").format(
|
||||
money_filter(remainder, self.event.currency)
|
||||
))
|
||||
else:
|
||||
messages.success(request, _("Your gift card has been applied."))
|
||||
|
||||
kwargs = {'step': 'payment'}
|
||||
if request.resolver_match and 'cart_namespace' in request.resolver_match.kwargs:
|
||||
kwargs['cart_namespace'] = request.resolver_match.kwargs['cart_namespace']
|
||||
return eventreverse(self.event, 'presale:event.checkout', kwargs=kwargs)
|
||||
except GiftCard.DoesNotExist:
|
||||
messages.error(request, _("This gift card is not known."))
|
||||
except GiftCard.MultipleObjectsReturned:
|
||||
messages.error(request, _("This gift card can not be redeemed since its code is not unique. Please contact the organizer of this event."))
|
||||
|
||||
@transaction.atomic()
|
||||
def execute_refund(self, refund: OrderRefund):
|
||||
from .models import GiftCard
|
||||
|
||||
@@ -329,6 +329,15 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
|
||||
if position.voucher:
|
||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1))
|
||||
|
||||
for position in order.positions.all():
|
||||
for gc in position.issued_gift_cards.all():
|
||||
if gc.value < position.price:
|
||||
raise OrderError(_('This order can not be canceled since the gift card {card} purchased in this order has already been redeemed.').format(
|
||||
card=gc.secret
|
||||
))
|
||||
else:
|
||||
gc.transactions.create(value=-position.price, order=order)
|
||||
|
||||
order.log_action('pretix.event.order.canceled', user=user, auth=api_token or oauth_application or device,
|
||||
data={'cancellation_fee': cancellation_fee})
|
||||
|
||||
@@ -1659,9 +1668,16 @@ def change_payment_provider(order: Order, payment_provider, amount=None, new_pay
|
||||
@receiver(order_paid, dispatch_uid="pretixbase_order_paid_giftcards")
|
||||
@transaction.atomic()
|
||||
def signal_listener_issue_giftcards(sender: Event, order: Order, **kwargs):
|
||||
any_giftcards = False
|
||||
for p in order.positions.all():
|
||||
if p.item.issue_giftcard:
|
||||
gc = sender.organizer.issued_gift_cards.create(
|
||||
currency=sender.currency, issued_in=p
|
||||
)
|
||||
gc.transactions.create(value=p.price, order=order)
|
||||
any_giftcards = True
|
||||
p.secret = gc.secret
|
||||
p.save(update_fields=['secret'])
|
||||
|
||||
if any_giftcards:
|
||||
tickets.invalidate_cache.apply_async(kwargs={'event': sender.pk, 'order': order.pk})
|
||||
|
||||
@@ -133,6 +133,10 @@ DEFAULTS = {
|
||||
'default': 'True',
|
||||
'type': bool
|
||||
},
|
||||
'payment_giftcard__enabled': {
|
||||
'default': 'True',
|
||||
'type': bool
|
||||
},
|
||||
'payment_term_accept_late': {
|
||||
'default': 'True',
|
||||
'type': bool
|
||||
|
||||
Reference in New Issue
Block a user