mirror of
https://github.com/pretix/pretix.git
synced 2026-04-28 00:02:37 +00:00
GiftCard: Add more information to transactions (#3308)
This commit is contained in:
@@ -24,6 +24,8 @@ owner_ticket integer Internal ID of
|
||||
this gift card and can view all transactions. When setting
|
||||
this field, you can also give the ``secret`` of an order
|
||||
position.
|
||||
issuer string Organizer slug of the organizer who created this gift
|
||||
card and is responsible for it.
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
The gift card transaction resource contains the following public fields:
|
||||
@@ -39,8 +41,17 @@ value money (string) Transaction amo
|
||||
event string Event slug, if the gift card was used in the web shop (or ``null``)
|
||||
order string Order code, if the gift card was used in the web shop (or ``null``)
|
||||
text string Custom text of the transaction (or ``null``)
|
||||
info object Additional data about the transaction (or ``null``)
|
||||
acceptor string Organizer slug of the organizer who created this transaction
|
||||
(can be ``null`` for all transactions performed before
|
||||
this field was added.)
|
||||
===================================== ========================== =======================================================
|
||||
|
||||
.. versionchanged:: 4.20
|
||||
|
||||
The ``owner_ticket`` and ``issuer`` attributes of the gift card and the ``info`` and ``acceptor`` attributes of the
|
||||
gift card transaction resource have been added.
|
||||
|
||||
Endpoints
|
||||
---------
|
||||
|
||||
@@ -77,6 +88,7 @@ Endpoints
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"owner_ticket": null,
|
||||
"issuer": "bigevents",
|
||||
"value": "13.37"
|
||||
}
|
||||
]
|
||||
@@ -123,6 +135,7 @@ Endpoints
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"owner_ticket": null,
|
||||
"issuer": "bigevents",
|
||||
"value": "13.37"
|
||||
}
|
||||
|
||||
@@ -168,6 +181,7 @@ Endpoints
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"owner_ticket": null,
|
||||
"issuer": "bigevents",
|
||||
"value": "13.37"
|
||||
}
|
||||
|
||||
@@ -221,6 +235,7 @@ Endpoints
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"owner_ticket": null,
|
||||
"issuer": "bigevents",
|
||||
"value": "14.00"
|
||||
}
|
||||
|
||||
@@ -267,6 +282,7 @@ Endpoints
|
||||
"expires": null,
|
||||
"conditions": null,
|
||||
"owner_ticket": null,
|
||||
"issuer": "bigevents",
|
||||
"value": "15.37"
|
||||
}
|
||||
|
||||
@@ -310,7 +326,11 @@ Endpoints
|
||||
"value": "50.00",
|
||||
"event": "democon",
|
||||
"order": "FXQYW",
|
||||
"text": null
|
||||
"text": null,
|
||||
"acceptor": "bigevents",
|
||||
"info": {
|
||||
"created_by": "plugin1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ Core
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: periodic_task, event_live_issues, event_copy_data, email_filter, register_notification_types,
|
||||
item_copy_data, register_sales_channels, register_global_settings, quota_availability, global_email_filter,
|
||||
register_ticket_secret_generators
|
||||
register_ticket_secret_generators, gift_card_transaction_display
|
||||
|
||||
Order events
|
||||
""""""""""""
|
||||
|
||||
@@ -160,6 +160,7 @@ class FlexibleTicketRelatedField(serializers.PrimaryKeyRelatedField):
|
||||
class GiftCardSerializer(I18nAwareModelSerializer):
|
||||
value = serializers.DecimalField(max_digits=13, decimal_places=2, min_value=Decimal('0.00'))
|
||||
owner_ticket = FlexibleTicketRelatedField(required=False, allow_null=True, queryset=OrderPosition.all.none())
|
||||
issuer = serializers.SlugRelatedField(slug_field='slug', read_only=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@@ -196,7 +197,8 @@ class GiftCardSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = GiftCard
|
||||
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions', 'owner_ticket')
|
||||
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions', 'owner_ticket',
|
||||
'issuer')
|
||||
|
||||
|
||||
class OrderEventSlugField(serializers.RelatedField):
|
||||
@@ -207,11 +209,12 @@ class OrderEventSlugField(serializers.RelatedField):
|
||||
|
||||
class GiftCardTransactionSerializer(I18nAwareModelSerializer):
|
||||
order = serializers.SlugRelatedField(slug_field='code', read_only=True)
|
||||
acceptor = serializers.SlugRelatedField(slug_field='slug', read_only=True)
|
||||
event = OrderEventSlugField(source='order', read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = GiftCardTransaction
|
||||
fields = ('id', 'datetime', 'value', 'event', 'order', 'text')
|
||||
fields = ('id', 'datetime', 'value', 'event', 'order', 'text', 'info', 'acceptor')
|
||||
|
||||
|
||||
class EventSlugField(serializers.SlugRelatedField):
|
||||
|
||||
@@ -155,7 +155,9 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
qs = self.request.organizer.accepted_gift_cards
|
||||
else:
|
||||
qs = self.request.organizer.issued_gift_cards.all()
|
||||
return qs
|
||||
return qs.prefetch_related(
|
||||
'issuer'
|
||||
)
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
@@ -166,7 +168,7 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
def perform_create(self, serializer):
|
||||
value = serializer.validated_data.pop('value')
|
||||
inst = serializer.save(issuer=self.request.organizer)
|
||||
inst.transactions.create(value=value)
|
||||
inst.transactions.create(value=value, acceptor=self.request.organizer)
|
||||
inst.log_action(
|
||||
'pretix.giftcards.transaction.manual',
|
||||
user=self.request.user,
|
||||
@@ -197,7 +199,7 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
if 'value' in self.request.data and value is not None:
|
||||
old_value = serializer.instance.value
|
||||
diff = value - old_value
|
||||
inst.transactions.create(value=diff)
|
||||
inst.transactions.create(value=diff, acceptor=self.request.organizer)
|
||||
inst.log_action(
|
||||
'pretix.giftcards.transaction.manual',
|
||||
user=self.request.user,
|
||||
@@ -217,11 +219,14 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
||||
text = serializers.CharField(allow_blank=True, allow_null=True).to_internal_value(
|
||||
request.data.get('text', '')
|
||||
)
|
||||
info = serializers.JSONField(required=False, allow_null=True).to_internal_value(
|
||||
request.data.get('info', {})
|
||||
)
|
||||
if gc.value + value < Decimal('0.00'):
|
||||
return Response({
|
||||
'value': ['The gift card does not have sufficient credit for this operation.']
|
||||
}, status=status.HTTP_409_CONFLICT)
|
||||
gc.transactions.create(value=value, text=text)
|
||||
gc.transactions.create(value=value, text=text, info=info, acceptor=self.request.organizer)
|
||||
gc.log_action(
|
||||
'pretix.giftcards.transaction.manual',
|
||||
user=self.request.user,
|
||||
@@ -249,7 +254,7 @@ class GiftCardTransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
return get_object_or_404(qs, pk=self.kwargs.get('giftcard'))
|
||||
|
||||
def get_queryset(self):
|
||||
return self.giftcard.transactions.select_related('order', 'order__event')
|
||||
return self.giftcard.transactions.select_related('order', 'order__event').prefetch_related('acceptor')
|
||||
|
||||
|
||||
class TeamViewSet(viewsets.ModelViewSet):
|
||||
|
||||
24
src/pretix/base/migrations/0239_giftcard_info.py
Normal file
24
src/pretix/base/migrations/0239_giftcard_info.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 3.2.18 on 2023-05-11 11:02
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0238_giftcard_owner_ticket'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='giftcardtransaction',
|
||||
name='acceptor',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='gift_card_transactions', to='pretixbase.organizer'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='giftcardtransaction',
|
||||
name='info',
|
||||
field=models.JSONField(null=True),
|
||||
),
|
||||
]
|
||||
@@ -25,7 +25,9 @@ from django.conf import settings
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.db.models import Sum
|
||||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.html import format_html
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
|
||||
@@ -160,6 +162,61 @@ class GiftCardTransaction(models.Model):
|
||||
on_delete=models.PROTECT
|
||||
)
|
||||
text = models.TextField(blank=True, null=True)
|
||||
info = models.JSONField(
|
||||
null=True, blank=True,
|
||||
)
|
||||
acceptor = models.ForeignKey(
|
||||
'Organizer',
|
||||
related_name='gift_card_transactions',
|
||||
on_delete=models.PROTECT,
|
||||
null=True, blank=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ("datetime",)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk and not self.acceptor:
|
||||
raise ValueError("`acceptor` should be set on all new gift card transactions.")
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def display(self, customer_facing=True):
|
||||
from ..signals import gift_card_transaction_display
|
||||
|
||||
for receiver, response in gift_card_transaction_display.send(self, transaction=self, customer_facing=customer_facing):
|
||||
if response:
|
||||
return response
|
||||
|
||||
if self.order_id:
|
||||
if not self.text:
|
||||
if not customer_facing:
|
||||
return format_html(
|
||||
'<a href="{}">{}</a>',
|
||||
reverse(
|
||||
"control:event.order",
|
||||
kwargs={
|
||||
"event": self.order.event.slug,
|
||||
"organizer": self.order.event.organizer.slug,
|
||||
"code": self.order.code,
|
||||
}
|
||||
),
|
||||
self.order.full_code
|
||||
)
|
||||
return self.order.full_code
|
||||
else:
|
||||
return self.text
|
||||
else:
|
||||
if self.text:
|
||||
return format_html(
|
||||
'<em>{}:</em> {}',
|
||||
_('Manual transaction'),
|
||||
self.text,
|
||||
)
|
||||
else:
|
||||
return _('Manual transaction')
|
||||
|
||||
def display_backend(self):
|
||||
return self.display(customer_facing=False)
|
||||
|
||||
def display_presale(self):
|
||||
return self.display(customer_facing=True)
|
||||
|
||||
@@ -1469,7 +1469,8 @@ class GiftCardPayment(BasePaymentProvider):
|
||||
trans = gc.transactions.create(
|
||||
value=-1 * payment.amount,
|
||||
order=payment.order,
|
||||
payment=payment
|
||||
payment=payment,
|
||||
acceptor=self.event.organizer,
|
||||
)
|
||||
payment.info_data = {
|
||||
'gift_card': gc.pk,
|
||||
@@ -1490,7 +1491,8 @@ class GiftCardPayment(BasePaymentProvider):
|
||||
trans = gc.transactions.create(
|
||||
value=refund.amount,
|
||||
order=refund.order,
|
||||
refund=refund
|
||||
refund=refund,
|
||||
acceptor=self.event.organizer,
|
||||
)
|
||||
refund.info_data = {
|
||||
'gift_card': gc.pk,
|
||||
|
||||
@@ -235,7 +235,7 @@ def reactivate_order(order: Order, force: bool=False, user: User=None, auth=None
|
||||
|
||||
for gc in position.issued_gift_cards.all():
|
||||
gc = GiftCard.objects.select_for_update(of=OF_SELF).get(pk=gc.pk)
|
||||
gc.transactions.create(value=position.price, order=order)
|
||||
gc.transactions.create(value=position.price, order=order, acceptor=order.event.organizer)
|
||||
break
|
||||
|
||||
for m in position.granted_memberships.all():
|
||||
@@ -513,7 +513,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
|
||||
)
|
||||
)
|
||||
else:
|
||||
gc.transactions.create(value=-position.price, order=order)
|
||||
gc.transactions.create(value=-position.price, order=order, acceptor=order.event.organizer)
|
||||
|
||||
for m in position.granted_memberships.all():
|
||||
m.canceled = True
|
||||
@@ -2186,7 +2186,7 @@ class OrderChangeManager:
|
||||
card=gc.secret
|
||||
))
|
||||
else:
|
||||
gc.transactions.create(value=-op.position.price, order=self.order)
|
||||
gc.transactions.create(value=-op.position.price, order=self.order, acceptor=self.order.event.organizer)
|
||||
|
||||
for m in op.position.granted_memberships.with_usages().all():
|
||||
m.canceled = True
|
||||
@@ -2202,7 +2202,7 @@ class OrderChangeManager:
|
||||
card=gc.secret
|
||||
))
|
||||
else:
|
||||
gc.transactions.create(value=-opa.position.price, order=self.order)
|
||||
gc.transactions.create(value=-opa.position.price, order=self.order, acceptor=self.order.event.organizer)
|
||||
|
||||
for m in opa.granted_memberships.with_usages().all():
|
||||
m.canceled = True
|
||||
@@ -2918,7 +2918,7 @@ def signal_listener_issue_giftcards(sender: Event, order: Order, **kwargs):
|
||||
currency=sender.currency, issued_in=p, testmode=order.testmode,
|
||||
expires=sender.organizer.default_gift_card_expiry,
|
||||
)
|
||||
gc.transactions.create(value=p.price - issued, order=order)
|
||||
gc.transactions.create(value=p.price - issued, order=order, acceptor=sender.organizer)
|
||||
any_giftcards = True
|
||||
p.secret = gc.secret
|
||||
p.save(update_fields=['secret'])
|
||||
|
||||
@@ -578,6 +578,20 @@ All plugins that are installed may send fields for the global settings form, as
|
||||
an OrderedDict of (setting name, form field).
|
||||
"""
|
||||
|
||||
gift_card_transaction_display = django.dispatch.Signal()
|
||||
"""
|
||||
Arguments: ``transaction``, ``customer_facing``
|
||||
|
||||
To display an instance of the ``GiftCardTransaction`` model to a human user,
|
||||
``pretix.base.signals.gift_card_transaction_display`` will be sent out with a ``transaction`` argument.
|
||||
The ``customer_facing`` argument specifies whether the HTML will be shown to an end-user or if it is being
|
||||
used in the backend.
|
||||
|
||||
The first received response that is not ``None`` will be used to display the log entry
|
||||
to the user. The receivers are expected to return a string (that might be marked with ``mark_safe`` from Django if
|
||||
it contains HTML).
|
||||
"""
|
||||
|
||||
order_fee_calculation = EventPluginSignal()
|
||||
"""
|
||||
Arguments: ``positions``, ``invoice_address``, ``meta_info``, ``total``, ``gift_cards``, ``payment_requests``
|
||||
|
||||
@@ -70,29 +70,32 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Order" %}</th>
|
||||
<th>{% trans "Information" %}</th>
|
||||
<th class="text-right">{% trans "Value" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for t in card.transactions.all %}
|
||||
{% for t in transactions %}
|
||||
<tr>
|
||||
<td>{{ t.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
<td>
|
||||
{% if t.order %}
|
||||
<a href="{% url "control:event.order" event=t.order.event.slug organizer=t.order.event.organizer.slug code=t.order.code %}">
|
||||
{{ t.order.full_code }}
|
||||
</a>
|
||||
{% if t.refund and t.value > 0 and t.value <= card.value %}
|
||||
<button type="submit" name="revert" value="{{ t.pk }}"
|
||||
class="btn btn-default btn-xs" data-toggle="tooltip"
|
||||
title="{% trans "Create a payment on the respective order that cancels out with this transaction. The order will then likely be overpaid." %}">
|
||||
<span class="fa fa-repeat"></span>
|
||||
{% trans "Revert" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<em>{% trans "Manual transaction" %}{% if t.text %}: {{ t.text }}{% endif %}</em>
|
||||
{{ t.display_backend }}
|
||||
{% if t.refund and t.value > 0 and t.value <= card.value %}
|
||||
<button type="submit" name="revert" value="{{ t.pk }}"
|
||||
class="btn btn-default btn-xs" data-toggle="tooltip"
|
||||
title="{% trans "Create a payment on the respective order that cancels out with this transaction. The order will then likely be overpaid." %}">
|
||||
<span class="fa fa-repeat"></span>
|
||||
{% trans "Revert" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if staff_session and t.info %}
|
||||
<pre><code>{{ t.info|pprint }}</code></pre>
|
||||
{% endif %}
|
||||
{% if t.acceptor and t.acceptor != request.organizer %}
|
||||
<span class="text-muted">
|
||||
<br>
|
||||
<span class="fa fa-group"></span> {{ t.acceptor }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
|
||||
@@ -1452,6 +1452,7 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
self.object.transactions.create(
|
||||
value=value,
|
||||
text=request.POST.get('text') or None,
|
||||
acceptor=request.organizer,
|
||||
)
|
||||
self.object.log_action(
|
||||
'pretix.giftcards.transaction.manual',
|
||||
@@ -1471,6 +1472,16 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
))
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(
|
||||
**kwargs,
|
||||
transactions=self.object.transactions.select_related(
|
||||
'order', 'order__event', 'order__event__organizer', 'payment', 'refund'
|
||||
).prefetch_related(
|
||||
'acceptor'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class GiftCardCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin, CreateView):
|
||||
template_name = 'pretixcontrol/organizers/giftcard_create.html'
|
||||
@@ -1497,6 +1508,7 @@ class GiftCardCreateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
||||
form.instance.issuer = self.request.organizer
|
||||
super().form_valid(form)
|
||||
form.instance.transactions.create(
|
||||
acceptor=self.request.organizer,
|
||||
value=form.cleaned_data['value']
|
||||
)
|
||||
form.instance.log_action('pretix.giftcards.created', user=self.request.user, data={})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Date" %}</th>
|
||||
<th>{% trans "Order" %}</th>
|
||||
<th>{% trans "Information" %}</th>
|
||||
<th class="text-right">{% trans "Value" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -13,11 +13,7 @@
|
||||
<tr>
|
||||
<td>{{ t.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
|
||||
<td>
|
||||
{% if t.order %}
|
||||
{{ t.order.full_code }}
|
||||
{% else %}
|
||||
<em>{% if t.text %}{{ t.text }}{% else %}{% trans "Manual transaction" %}{% endif %}</em>
|
||||
{% endif %}
|
||||
{{ t.display_presale }}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
{{ t.value|money:giftcard.currency }}
|
||||
|
||||
@@ -33,7 +33,7 @@ from pretix.base.models import GiftCard, Order, Organizer
|
||||
@pytest.fixture
|
||||
def giftcard(organizer, event):
|
||||
gc = organizer.issued_gift_cards.create(secret="ABCDEF", currency="EUR")
|
||||
gc.transactions.create(value=Decimal('23.00'))
|
||||
gc.transactions.create(value=Decimal('23.00'), acceptor=organizer)
|
||||
return gc
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ TEST_GC_RES = {
|
||||
"expires": None,
|
||||
"conditions": None,
|
||||
"currency": "EUR",
|
||||
"issuer": "dummy",
|
||||
"owner_ticket": None
|
||||
}
|
||||
|
||||
@@ -264,7 +265,8 @@ def test_giftcard_transact(token_client, organizer, event, giftcard):
|
||||
'/api/v1/organizers/{}/giftcards/{}/transact/'.format(organizer.slug, giftcard.pk),
|
||||
{
|
||||
'value': '10.00',
|
||||
'text': 'bla'
|
||||
'text': 'bla',
|
||||
'info': {"a": "b"}
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
@@ -272,6 +274,23 @@ def test_giftcard_transact(token_client, organizer, event, giftcard):
|
||||
giftcard.refresh_from_db()
|
||||
assert giftcard.value == Decimal('43.00')
|
||||
assert giftcard.transactions.last().text == 'bla'
|
||||
assert giftcard.transactions.last().info == {"a": "b"}
|
||||
assert giftcard.transactions.last().acceptor == organizer
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_giftcard_transact_cross_organizer(token_client, organizer, event, other_giftcard):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/giftcards/{}/transact/?include_accepted=true'.format(organizer.slug, other_giftcard.pk),
|
||||
{
|
||||
'value': '10.00',
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
other_giftcard.refresh_from_db()
|
||||
assert other_giftcard.value == Decimal('10.00')
|
||||
assert other_giftcard.transactions.last().acceptor == organizer
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@@ -314,7 +333,9 @@ def test_giftcard_transactions(token_client, organizer, giftcard):
|
||||
"value": "23.00",
|
||||
"event": None,
|
||||
"order": None,
|
||||
"text": None
|
||||
"text": None,
|
||||
"info": None,
|
||||
"acceptor": organizer.slug
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ from pretix.base.models import Order, Organizer, ReusableMedium
|
||||
@pytest.fixture
|
||||
def giftcard(organizer):
|
||||
gc = organizer.issued_gift_cards.create(secret="ABCDEF", currency="EUR")
|
||||
gc.transactions.create(value=Decimal('23.00'))
|
||||
gc.transactions.create(value=Decimal('23.00'), acceptor=organizer)
|
||||
return gc
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ def organizer2():
|
||||
@pytest.fixture
|
||||
def giftcard2(organizer2):
|
||||
gc = organizer2.issued_gift_cards.create(secret="ABCDEF", currency="EUR")
|
||||
gc.transactions.create(value=Decimal('23.00'))
|
||||
gc.transactions.create(value=Decimal('23.00'), acceptor=organizer2)
|
||||
return gc
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ def test_medium_detail(token_client, organizer, event, medium, giftcard, custome
|
||||
"expires": None,
|
||||
"conditions": None,
|
||||
"owner_ticket": resp.data["linked_orderposition"],
|
||||
"issuer": "dummy",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -965,7 +965,7 @@ class OrderCancelTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_auto_refund_possible_issued_giftcard(self):
|
||||
gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)
|
||||
gc.transactions.create(value=23)
|
||||
gc.transactions.create(value=23, acceptor=self.o)
|
||||
self.order.payments.create(
|
||||
amount=Decimal('46.00'),
|
||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
||||
@@ -979,7 +979,7 @@ class OrderCancelTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_auto_refund_impossible_issued_giftcard_used(self):
|
||||
gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.o)
|
||||
self.order.payments.create(
|
||||
amount=Decimal('46.00'),
|
||||
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
||||
@@ -1397,7 +1397,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_cancel_issued_giftcard(self):
|
||||
gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)
|
||||
gc.transactions.create(value=23)
|
||||
gc.transactions.create(value=23, acceptor=self.o)
|
||||
self.ocm.cancel(self.op1)
|
||||
self.ocm.commit()
|
||||
assert gc.value == Decimal('0.00')
|
||||
@@ -1422,7 +1422,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_cancel_issued_giftcard_used(self):
|
||||
gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.o)
|
||||
self.ocm.cancel(self.op1)
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.commit()
|
||||
@@ -1430,7 +1430,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_change_price_issued_giftcard_used(self):
|
||||
gc = self.o.issued_gift_cards.create(currency="EUR", issued_in=self.op1)
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.o)
|
||||
with self.assertRaises(OrderError):
|
||||
self.ocm.change_price(self.op1, 25)
|
||||
|
||||
@@ -3181,9 +3181,9 @@ def test_giftcard_multiple(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
gc2 = event.organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc2.transactions.create(value=12)
|
||||
gc2.transactions.create(value=12, acceptor=event.organizer)
|
||||
order = _create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3233,7 +3233,7 @@ def test_giftcard_partial(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
order = _create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3280,7 +3280,7 @@ def test_giftcard_payment_fee(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
order = _create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3326,7 +3326,7 @@ def test_giftcard_invalid_currency(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="USD")
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
_create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3368,7 +3368,7 @@ def test_giftcard_invalid_organizer(event):
|
||||
)
|
||||
o2 = Organizer.objects.create(slug="foo", name="bar")
|
||||
gc1 = o2.issued_gift_cards.create(currency="EUR")
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
_create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3409,7 +3409,7 @@ def test_giftcard_test_mode_invalid(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR", testmode=True)
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
_create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3452,7 +3452,7 @@ def test_giftcard_test_mode_event(event):
|
||||
event.testmode = True
|
||||
event.save()
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR", testmode=False)
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
_create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
@@ -3493,7 +3493,7 @@ def test_giftcard_swap(event):
|
||||
item=ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123"
|
||||
)
|
||||
gc1 = event.organizer.issued_gift_cards.create(currency="EUR", testmode=False)
|
||||
gc1.transactions.create(value=12)
|
||||
gc1.transactions.create(value=12, acceptor=event.organizer)
|
||||
_create_order(
|
||||
event, email='dummy@example.org', positions=[cp1],
|
||||
now_dt=now(),
|
||||
|
||||
@@ -44,7 +44,7 @@ def organizer2():
|
||||
@pytest.fixture
|
||||
def gift_card(organizer):
|
||||
gc = organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=42)
|
||||
gc.transactions.create(value=42, acceptor=organizer)
|
||||
return gc
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ def test_card_detail_view_transact_revert_refund(organizer, admin_user, gift_car
|
||||
r = o.refunds.create(
|
||||
amount=o.total, provider='giftcard', state=OrderRefund.REFUND_STATE_DONE
|
||||
)
|
||||
t = gift_card.transactions.create(value=14, order=o, refund=r)
|
||||
t = gift_card.transactions.create(value=14, order=o, refund=r, acceptor=organizer)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
r = client.post('/control/organizer/dummy/giftcard/{}/'.format(gift_card.pk), {
|
||||
|
||||
@@ -44,7 +44,7 @@ def medium(organizer):
|
||||
@pytest.fixture
|
||||
def gift_card(organizer):
|
||||
gc = organizer.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=42)
|
||||
gc.transactions.create(value=42, acceptor=organizer)
|
||||
return gc
|
||||
|
||||
|
||||
|
||||
@@ -1440,7 +1440,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_partial(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_stripe__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1483,9 +1483,9 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_full_with_multiple(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
gc2 = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc2.transactions.create(value=20)
|
||||
gc2.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_stripe__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1526,7 +1526,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_full(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=30)
|
||||
gc.transactions.create(value=30, acceptor=self.orga)
|
||||
self.event.settings.set('payment_stripe__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1555,7 +1555,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_racecondition(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_stripe__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1584,7 +1584,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
assert '€20.00' in response.content.decode()
|
||||
assert '3.00' in response.content.decode()
|
||||
|
||||
gc.transactions.create(value=-2)
|
||||
gc.transactions.create(value=-2, acceptor=self.orga)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
@@ -1601,7 +1601,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_expired(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR", expires=now() - timedelta(days=1))
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
@@ -1616,7 +1616,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_invalid_currency(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="USD")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
@@ -1633,7 +1633,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.orga.issued_gift_cards.create(currency="EUR")
|
||||
orga2 = Organizer.objects.create(slug="foo2", name="foo2")
|
||||
gc = orga2.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
@@ -1650,7 +1650,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.orga.issued_gift_cards.create(currency="EUR")
|
||||
orga2 = Organizer.objects.create(slug="foo2", name="foo2")
|
||||
gc = orga2.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=23)
|
||||
gc.transactions.create(value=23, acceptor=orga2)
|
||||
self.orga.gift_card_issuer_acceptance.create(issuer=orga2)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1670,11 +1670,15 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
with scopes_disabled():
|
||||
o = Order.objects.last()
|
||||
assert o.payments.get(provider='giftcard').amount == Decimal('23.00')
|
||||
p = o.payments.get(provider='giftcard')
|
||||
assert p.amount == Decimal('23.00')
|
||||
gc.refresh_from_db()
|
||||
assert gc.issuer == orga2
|
||||
assert gc.transactions.last().acceptor == self.orga
|
||||
|
||||
def test_giftcard_in_test_mode(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
self.event.testmode = True
|
||||
self.event.save()
|
||||
@@ -1691,7 +1695,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_not_in_test_mode(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR", testmode=True)
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
@@ -1720,7 +1724,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_twice(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
@@ -1739,7 +1743,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_swap(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
self.ticket.issue_giftcard = True
|
||||
self.ticket.save()
|
||||
@@ -1756,7 +1760,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
def test_giftcard_like_method_with_min_value(self):
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=20)
|
||||
gc.transactions.create(value=20, acceptor=self.orga)
|
||||
self.event.settings.set('payment_stripe__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
with scopes_disabled():
|
||||
@@ -1790,7 +1794,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
# Our built-in gift card payment does not actually support setting a payment fee, but we still want to
|
||||
# test the core behavior in case a gift-card plugin does
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=27)
|
||||
gc.transactions.create(value=27, acceptor=self.orga)
|
||||
self.event.settings.set('payment_giftcard__fee_percent', 10)
|
||||
self.event.settings.set('payment_giftcard__fee_reverse_calc', False)
|
||||
with scopes_disabled():
|
||||
@@ -1829,7 +1833,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
# Our built-in gift card payment does not actually support setting a payment fee, but we still want to
|
||||
# test the core behavior in case a gift-card plugin does
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=23)
|
||||
gc.transactions.create(value=23, acceptor=self.orga)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
self.event.settings.set('payment_banktransfer__fee_percent', 20)
|
||||
self.event.settings.set('payment_banktransfer__fee_reverse_calc', False)
|
||||
|
||||
@@ -1276,7 +1276,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
amount=Decimal('10.00'),
|
||||
)
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
)
|
||||
@@ -1315,7 +1315,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
amount=Decimal('10.00'),
|
||||
)
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
self.ticket.issue_giftcard = True
|
||||
self.ticket.save()
|
||||
response = self.client.post(
|
||||
@@ -1330,7 +1330,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
def test_change_paymentmethod_giftcard_wrong_currency(self):
|
||||
with scopes_disabled():
|
||||
gc = self.orga.issued_gift_cards.create(currency="USD")
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{
|
||||
@@ -1345,7 +1345,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
self.order.testmode = True
|
||||
self.order.save()
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{
|
||||
@@ -1358,7 +1358,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
def test_change_paymentmethod_giftcard_not_in_test_mode(self):
|
||||
with scopes_disabled():
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR", testmode=True)
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{
|
||||
@@ -1385,7 +1385,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
o = Organizer.objects.create(slug='Foo', name='bar')
|
||||
self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc = o.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=10)
|
||||
gc.transactions.create(value=10, acceptor=self.orga)
|
||||
response = self.client.post(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{
|
||||
@@ -1403,7 +1403,7 @@ class OrdersTest(BaseOrdersTest):
|
||||
amount=Decimal('10.00'),
|
||||
)
|
||||
gc = self.orga.issued_gift_cards.create(currency="EUR")
|
||||
gc.transactions.create(value=100)
|
||||
gc.transactions.create(value=100, acceptor=self.orga)
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user