diff --git a/doc/api/resources/giftcards.rst b/doc/api/resources/giftcards.rst index 99b0bed1d..0d441a3af 100644 --- a/doc/api/resources/giftcards.rst +++ b/doc/api/resources/giftcards.rst @@ -17,6 +17,7 @@ id integer Internal ID of secret string Gift card code (can not be modified later) value money (string) Current gift card value currency string Currency of the value (can not be modified later) +testmode boolean Whether this is a test gift card ===================================== ========================== ======================================================= Endpoints @@ -51,6 +52,7 @@ Endpoints "id": 1, "secret": "HLBYVELFRC77NCQY", "currency": "EUR", + "testmode": false, "value": "13.37" } ] @@ -86,6 +88,7 @@ Endpoints "id": 1, "secret": "HLBYVELFRC77NCQY", "currency": "EUR", + "testmode": false, "value": "13.37" } @@ -125,6 +128,7 @@ Endpoints { "id": 1, "secret": "HLBYVELFRC77NCQY", + "testmode": false, "currency": "EUR", "value": "13.37" } @@ -141,8 +145,9 @@ Endpoints the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you want to change. - You can change all fields of the resource except the ``id``, ``secret``, and ``currency`` fields. Be careful when - modifying the ``value`` field to avoid race conditions. We recommend to use the ``transact`` method described below. + You can change all fields of the resource except the ``id``, ``secret``, ``testmode``, and ``currency`` fields. Be + careful when modifying the ``value`` field to avoid race conditions. We recommend to use the ``transact`` method + described below. **Example request**: @@ -169,6 +174,7 @@ Endpoints { "id": 1, "secret": "HLBYVELFRC77NCQY", + "testmode": false, "currency": "EUR", "value": "14.00" } @@ -211,6 +217,7 @@ Endpoints "id": 1, "secret": "HLBYVELFRC77NCQY", "currency": "EUR", + "testmode": false, "value": "15.37" } diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py index a7980d5f4..622179d60 100644 --- a/src/pretix/api/serializers/organizer.py +++ b/src/pretix/api/serializers/organizer.py @@ -46,4 +46,4 @@ class GiftCardSerializer(I18nAwareModelSerializer): class Meta: model = GiftCard - fields = ('id', 'secret', 'issuance', 'value', 'currency') + fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode') diff --git a/src/pretix/api/views/organizer.py b/src/pretix/api/views/organizer.py index f3a5508bf..4f3f676e4 100644 --- a/src/pretix/api/views/organizer.py +++ b/src/pretix/api/views/organizer.py @@ -117,7 +117,8 @@ class GiftCardViewSet(viewsets.ModelViewSet): GiftCard.objects.select_for_update().get(pk=self.get_object().pk) old_value = serializer.instance.value value = serializer.validated_data.pop('value') - inst = serializer.save(secret=serializer.instance.secret, currency=serializer.instance.currency) + inst = serializer.save(secret=serializer.instance.secret, currency=serializer.instance.currency, + testmode=serializer.instance.testmode) diff = value - old_value inst.transactions.create(value=diff) inst.log_action( diff --git a/src/pretix/base/migrations/0138_auto_20191017_1151.py b/src/pretix/base/migrations/0138_auto_20191017_1151.py index dfc79d512..09c365faf 100644 --- a/src/pretix/base/migrations/0138_auto_20191017_1151.py +++ b/src/pretix/base/migrations/0138_auto_20191017_1151.py @@ -32,6 +32,7 @@ class Migration(migrations.Migration): ('issuer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='issued_gift_cards', to='pretixbase.Organizer')), + ('testmode', django.db.models.BooleanField(default=False)), ], options={ 'unique_together': {('secret', 'issuer')}, diff --git a/src/pretix/base/models/giftcards.py b/src/pretix/base/models/giftcards.py index d5b6702da..424167a72 100644 --- a/src/pretix/base/models/giftcards.py +++ b/src/pretix/base/models/giftcards.py @@ -52,6 +52,10 @@ class GiftCard(LoggedModel): db_index=True, verbose_name=_('Gift card code'), ) + testmode = models.BooleanField( + verbose_name=_('Test mode card'), + default=False + ) CURRENCY_CHOICES = [(c.alpha_3, c.alpha_3 + " - " + c.name) for c in settings.CURRENCIES] currency = models.CharField(max_length=10, choices=CURRENCY_CHOICES) diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 617cf815b..1b147182a 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -201,7 +201,7 @@ class Order(LockModel, LoggedModel): return self.full_code def gracefully_delete(self, user=None, auth=None): - from . import Voucher + from . import Voucher, GiftCard, GiftCardTransaction if not self.testmode: raise TypeError("Only test mode orders can be deleted.") @@ -217,6 +217,10 @@ class Order(LockModel, LoggedModel): if position.voucher: Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=Greatest(0, F('redeemed') - 1)) + GiftCardTransaction.objects.filter(payment__in=self.payments.all()).update(payment=None) + GiftCardTransaction.objects.filter(refund__in=self.refunds.all()).update(refund=None) + GiftCardTransaction.objects.filter(order=self).update(order=None) + GiftCard.objects.filter(issued_in__in=self.positions.all()).update(issued_in=None) OrderPosition.all.filter(order=self, addon_to__isnull=False).delete() OrderPosition.all.filter(order=self).delete() OrderFee.all.filter(order=self).delete() diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index 3a2f41d63..fbdbdc4d1 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -906,6 +906,10 @@ class GiftCardPayment(BasePaymentProvider): del f['_invoice_text'] return f + @property + def test_mode_message(self) -> str: + return _("In test mode, only test cards will work.") + def is_allowed(self, request: HttpRequest, total: Decimal=None) -> bool: return super().is_allowed(request, total) and self.event.organizer.has_gift_cards @@ -958,6 +962,12 @@ class GiftCardPayment(BasePaymentProvider): if gc.currency != self.event.currency: messages.error(request, _("This gift card does not support this currency.")) return + if gc.testmode and not self.event.testmode: + messages.error(request, _("This gift card can only be used in test mode.")) + return + if not gc.testmode and self.event.testmode: + messages.error(request, _("Only test gifts cards can be used in test mode.")) + return if gc.value <= Decimal("0.00"): messages.error(request, _("All credit on this gift card has been used.")) return @@ -997,6 +1007,12 @@ class GiftCardPayment(BasePaymentProvider): if gc.currency != self.event.currency: messages.error(request, _("This gift card does not support this currency.")) return + if gc.testmode and not self.event.testmode: + messages.error(request, _("This gift card can only be used in test mode.")) + return + if not gc.testmode and self.event.testmode: + messages.error(request, _("Only test gift cards can be used in test mode.")) + return if gc.value <= Decimal("0.00"): messages.error(request, _("All credit on this gift card has been used.")) return @@ -1027,6 +1043,8 @@ class GiftCardPayment(BasePaymentProvider): 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 gc.testmode != payment.order.testmode: + raise PaymentException(_("Only the gift card or only the order are created in test mode.")) if payment.amount > gc.value: raise PaymentException(_("This gift card was used in the meantime. Please try again")) trans = gc.transactions.create( diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index 6431f9eb6..a8146e570 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -971,9 +971,13 @@ def get_fees(event, request, total, invoice_address, provider): cs = cart_session(request) if cs.get('gift_cards'): + gcs = cs['gift_cards'] gc_qs = event.organizer.accepted_gift_cards.filter(pk__in=cs.get('gift_cards'), currency=event.currency) summed = 0 for gc in gc_qs: + if gc.testmode != event.testmode: + gcs.remove(gc.pk) + continue fval = Decimal(gc.value) # TODO: don't require an extra query fval = min(fval, total - summed) if fval > 0: @@ -988,6 +992,7 @@ def get_fees(event, request, total, invoice_address, provider): tax_value=Decimal('0.00'), tax_rule=TaxRule.zero() )) + cs['gift_cards'] = gcs if provider and total != 0: provider = event.get_payment_providers().get(provider) diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 641774903..d8e433e9e 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -600,6 +600,10 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d for gc in gc_qs: if gc.currency != event.currency: raise OrderError(_("This gift card does not support this currency.")) + if gc.testmode and not event.testmode: + raise OrderError(_("This gift card can only be used in test mode.")) + if not gc.testmode and event.testmode: + raise OrderError(_("Only test gift cards can be used in test mode.")) if not gc.accepted_by(event.organizer): raise OrderError(_("This gift card is not accepted by this event organizer.")) checked_gift_cards.append(gc) @@ -1687,7 +1691,7 @@ def signal_listener_issue_giftcards(sender: Event, order: Order, **kwargs): for p in order.positions.all(): if p.item.issue_giftcard: gc = sender.organizer.issued_gift_cards.create( - currency=sender.currency, issued_in=p + currency=sender.currency, issued_in=p, testmode=order.testmode ) gc.transactions.create(value=p.price, order=order) any_giftcards = True diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index 503720f00..69427ca8c 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -355,4 +355,4 @@ class GiftCardCreateForm(forms.ModelForm): class Meta: model = GiftCard - fields = ['secret', 'currency'] + fields = ['secret', 'currency', 'testmode'] diff --git a/src/pretix/control/templates/pretixcontrol/organizers/giftcard.html b/src/pretix/control/templates/pretixcontrol/organizers/giftcard.html index 21f58c02f..34f7398e1 100644 --- a/src/pretix/control/templates/pretixcontrol/organizers/giftcard.html +++ b/src/pretix/control/templates/pretixcontrol/organizers/giftcard.html @@ -7,6 +7,9 @@ {% blocktrans trimmed with card=card.secret %} Gift card: {{ card }} {% endblocktrans %} + {% if card.testmode %} + {% trans "TEST MODE" %} + {% endif %}
diff --git a/src/pretix/control/templates/pretixcontrol/organizers/giftcard_create.html b/src/pretix/control/templates/pretixcontrol/organizers/giftcard_create.html index bc81beb2a..7d5c9a654 100644 --- a/src/pretix/control/templates/pretixcontrol/organizers/giftcard_create.html +++ b/src/pretix/control/templates/pretixcontrol/organizers/giftcard_create.html @@ -9,6 +9,7 @@ {% bootstrap_field form.secret layout="control" %} {% bootstrap_field form.value layout="control" %} {% bootstrap_field form.currency layout="control" %} + {% bootstrap_field form.testmode layout="control" %}