From 9842fcf7da886715b34794c84b2387c7d5bd4c68 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Thu, 19 Sep 2019 17:54:05 +0200 Subject: [PATCH] Allow order change --- src/pretix/base/models/giftcards.py | 3 + src/pretix/base/payment.py | 79 ++++++++++++++++--- src/pretix/base/services/orders.py | 7 +- .../giftcards/checkout_confirm.html | 8 ++ 4 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 src/pretix/control/templates/pretixcontrol/giftcards/checkout_confirm.html diff --git a/src/pretix/base/models/giftcards.py b/src/pretix/base/models/giftcards.py index 88839a62d..be255904a 100644 --- a/src/pretix/base/models/giftcards.py +++ b/src/pretix/base/models/giftcards.py @@ -61,6 +61,9 @@ class GiftCard(LoggedModel): def value(self): return self.transactions.aggregate(s=Sum('value'))['s'] or Decimal('0.00') + def accepted_by(self, organizer): + return self.issuer == organizer or GiftCardAcceptance.objects.filter(issuer=self.issuer, collector=organizer).exists() + class Meta: unique_together = (('secret', 'issuer'),) diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index 593bdbdab..28e68f007 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -899,26 +899,27 @@ class GiftCardPayment(BasePaymentProvider): return super().is_allowed(request, total) and self.event.organizer.has_gift_cards def order_change_allowed(self, order: Order) -> bool: - return False - - def execute_payment(self, request: HttpRequest, payment: OrderPayment) -> str: - raise PaymentException("Invalid state, should never occur.") + return super().order_change_allowed(order) and self.event.organizer.has_gift_cards def payment_form_render(self, request: HttpRequest, total: Decimal) -> str: return get_template('pretixcontrol/giftcards/checkout.html').render({}) + def checkout_confirm_render(self, request) -> str: + return get_template('pretixcontrol/giftcards/checkout_confirm.html').render({}) + def payment_control_render(self, request, payment) -> str: from .models import GiftCard - gc = GiftCard.objects.get(pk=payment.info_data.get('gift_card')) - template = get_template('pretixcontrol/giftcards/payment.html') + if 'gift_card' in payment.info_data: + gc = GiftCard.objects.get(pk=payment.info_data.get('gift_card')) + template = get_template('pretixcontrol/giftcards/payment.html') - ctx = { - 'request': request, - 'event': self.event, - 'gc': gc, - } - return template.render(ctx) + ctx = { + 'request': request, + 'event': self.event, + 'gc': gc, + } + return template.render(ctx) def api_payment_details(self, payment: OrderPayment): from .models import GiftCard @@ -977,6 +978,60 @@ class GiftCardPayment(BasePaymentProvider): 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.")) + def payment_prepare(self, request: HttpRequest, payment: OrderPayment) -> Union[bool, str, None]: + 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 + payment.info_data = { + 'gift_card': gc.pk, + 'retry': True + } + payment.amount = min(payment.amount, gc.value) + payment.save() + + return True + except GiftCard.DoesNotExist: + if self.event.vouchers.filter(code__iexact=request.POST.get("giftcard")).exists(): + messages.warning(request, _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below " + "the product selection.")) + else: + 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.")) + + def execute_payment(self, request: HttpRequest, payment: OrderPayment) -> str: + gcpk = payment.info_data.get('gift_card') + if not gcpk or not payment.info_data.get('retry'): + raise PaymentException("Invalid state, should never occur.") + with transaction.atomic(): + gc = GiftCard.objects.select_for_update().get(pk=gcpk) + if gc.currency != self.event.currency: + raise PaymentException(_("This gift card does not support this currency.")) + if not gc.accepted_by(self.event.organizer): + raise PaymentException(_("This gift card is not accepted by this event organizer.")) + if payment.amount > gc.value: + raise PaymentException(_("This gift card was used in the meantime. Please try again")) + trans = gc.transactions.create( + value=-1 * payment.amount, + order=payment.order, + payment=payment + ) + payment.info_data = { + 'gift_card': gc.pk, + 'transaction_id': trans.pk, + } + payment.confirm() + + def payment_is_valid_session(self, request: HttpRequest) -> bool: + return True + @transaction.atomic() def execute_refund(self, refund: OrderRefund): from .models import GiftCard diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 29a5dd780..63b94f9f8 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -595,9 +595,12 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d with transaction.atomic(): checked_gift_cards = [] if gift_cards: - gc_qs = GiftCard.objects.select_for_update().filter(pk__in=gift_cards) # TODO: Make sure to prevent race conditions + gc_qs = GiftCard.objects.select_for_update().filter(pk__in=gift_cards) for gc in gc_qs: - # TODO: Re-check acceptance + if gc.currency != event.currency: + raise OrderError(_("This gift card does not support this currency.")) + if not gc.accepted_by(event.organizer): + raise OrderError(_("This gift card is not accepted by this event organizer.")) checked_gift_cards.append(gc) fees, pf, gift_card_values = _get_fees(positions, payment_provider, address, meta_info, event, checked_gift_cards) diff --git a/src/pretix/control/templates/pretixcontrol/giftcards/checkout_confirm.html b/src/pretix/control/templates/pretixcontrol/giftcards/checkout_confirm.html new file mode 100644 index 000000000..49108cbb4 --- /dev/null +++ b/src/pretix/control/templates/pretixcontrol/giftcards/checkout_confirm.html @@ -0,0 +1,8 @@ +{% load i18n %} + +

+ {% blocktrans %} + Your gift card will be used to pay for this order. If the credit on the gift card is lower than the order total, you will be able to pay the + difference with a different payment method. If the credit is higher than the order total, you will be able to re-use the gift card in the future. + {% endblocktrans %} +