Add testmode for gift cards

This commit is contained in:
Raphael Michel
2019-10-17 18:05:04 +02:00
parent 302966808e
commit 4b2f25ce8a
14 changed files with 62 additions and 7 deletions

View File

@@ -46,4 +46,4 @@ class GiftCardSerializer(I18nAwareModelSerializer):
class Meta:
model = GiftCard
fields = ('id', 'secret', 'issuance', 'value', 'currency')
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode')

View File

@@ -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(

View File

@@ -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')},

View File

@@ -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)

View File

@@ -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()

View File

@@ -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(

View File

@@ -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)

View File

@@ -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

View File

@@ -355,4 +355,4 @@ class GiftCardCreateForm(forms.ModelForm):
class Meta:
model = GiftCard
fields = ['secret', 'currency']
fields = ['secret', 'currency', 'testmode']

View File

@@ -7,6 +7,9 @@
{% blocktrans trimmed with card=card.secret %}
Gift card: {{ card }}
{% endblocktrans %}
{% if card.testmode %}
<span class="label label-warning">{% trans "TEST MODE" %}</span>
{% endif %}
</h1>
<div class="panel panel-primary items">
<div class="panel-heading">

View File

@@ -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" %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}

View File

@@ -54,6 +54,9 @@
<a href="{% url "control:organizer.giftcard" organizer=request.organizer.slug giftcard=g.id %}">
<strong>{{ g.secret }}</strong>
</a>
{% if g.testmode %}
<span class="label label-warning">{% trans "TEST MODE" %}</span>
{% endif %}
</td>
<td>{{ g.issuance|date:"SHORT_DATETIME_FORMAT" }}</td>
<td class="text-right">

View File

@@ -18,6 +18,7 @@ TEST_GC_RES = {
"id": 1,
"secret": "ABCDEF",
"value": "23.00",
"testmode": False,
"currency": "EUR"
}
@@ -46,6 +47,7 @@ def test_giftcard_detail(token_client, organizer, event, giftcard):
TEST_GIFTCARD_CREATE_PAYLOAD = {
"secret": "DEFABC",
"value": "12.00",
"testmode": False,
"currency": "EUR",
}
@@ -84,6 +86,7 @@ def test_giftcard_patch(token_client, organizer, event, giftcard):
{
'secret': 'foo',
'value': '10.00',
'testmode': True,
'currency': 'USD'
},
format='json'
@@ -93,6 +96,7 @@ def test_giftcard_patch(token_client, organizer, event, giftcard):
assert giftcard.value == Decimal('10.00')
assert giftcard.secret == "ABCDEF"
assert giftcard.currency == "EUR"
assert not giftcard.testmode
@pytest.mark.django_db