GiftCard: Add more information to transactions (#3308)

This commit is contained in:
Raphael Michel
2023-05-12 09:38:35 +02:00
committed by GitHub
parent 916ee0697f
commit c0419518c3
19 changed files with 247 additions and 85 deletions

View File

@@ -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"
}
}
]
}

View File

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

View File

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

View File

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

View 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),
),
]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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={})

View File

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

View File

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

View File

@@ -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",
}

View File

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

View File

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

View File

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

View File

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

View File

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