Gift card API: Allow to inspect transactions (#1868)

This commit is contained in:
Raphael Michel
2020-12-02 16:10:05 +01:00
committed by GitHub
parent 87a514ca8b
commit 99c3981e2d
6 changed files with 130 additions and 7 deletions

View File

@@ -22,9 +22,28 @@ expires datetime Expiry date (or
conditions string Special terms and conditions for this card (or ``null``)
===================================== ========================== =======================================================
The gift card transaction resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the gift card transaction
datetime datetime Creation date of the transaction
value money (string) Transaction amount
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``)
===================================== ========================== =======================================================
Endpoints
---------
.. versionadded:: 3.14
The transaction list endpoint was added.
.. http:get:: /api/v1/organizers/(organizer)/giftcards/
Returns a list of all gift cards issued by a given organizer.
@@ -250,3 +269,45 @@ Endpoints
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
:statuscode 409: There is not sufficient credit on the gift card.
.. http:get:: /api/v1/organizers/(organizer)/giftcards/(id)/transactions/
List all transactions of a gift card.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/giftcards/1/transactions/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 82,
"datetime": "2020-06-22T15:41:42.800534Z",
"value": "50.00",
"event": "democon",
"order": "FXQYW",
"text": null
}
]
}
:param organizer: The ``slug`` field of the organizer to view
:param id: The ``id`` field of the gift card to view
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer does not exist **or** you have no permission to view this resource.

View File

@@ -9,8 +9,8 @@ from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.api.serializers.order import CompatibleJSONField
from pretix.base.auth import get_auth_backends
from pretix.base.models import (
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
User,
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
TeamAPIToken, TeamInvite, User,
)
from pretix.base.models.seating import SeatingPlanLayoutValidator
from pretix.base.services.mail import SendMailException, mail
@@ -59,6 +59,21 @@ class GiftCardSerializer(I18nAwareModelSerializer):
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions')
class OrderEventSlugField(serializers.RelatedField):
def to_representation(self, obj):
return obj.event.slug
class GiftCardTransactionSerializer(I18nAwareModelSerializer):
order = serializers.SlugRelatedField(slug_field='code', read_only=True)
event = OrderEventSlugField(source='order', read_only=True)
class Meta:
model = GiftCardTransaction
fields = ('id', 'datetime', 'value', 'event', 'order', 'text')
class EventSlugField(serializers.SlugRelatedField):
def get_queryset(self):
return self.context['organizer'].events.all()

View File

@@ -62,6 +62,9 @@ order_router = routers.DefaultRouter()
order_router.register(r'payments', order.PaymentViewSet)
order_router.register(r'refunds', order.RefundViewSet)
giftcard_router = routers.DefaultRouter()
giftcard_router.register(r'transactions', organizer.GiftCardTransactionViewSet)
# Force import of all plugins to give them a chance to register URLs with the router
for app in apps.get_app_configs():
if hasattr(app, 'PretixPluginMeta'):
@@ -71,6 +74,7 @@ for app in apps.get_app_configs():
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/', include(orga_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/giftcards/(?P<giftcard>[^/]+)/', include(giftcard_router.urls)),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/settings/$', event.EventSettingsView.as_view(),
name="event.settings"),
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/', include(event_router.urls)),

View File

@@ -15,13 +15,13 @@ from rest_framework.viewsets import GenericViewSet
from pretix.api.models import OAuthAccessToken
from pretix.api.serializers.organizer import (
DeviceSerializer, GiftCardSerializer, OrganizerSerializer,
SeatingPlanSerializer, TeamAPITokenSerializer, TeamInviteSerializer,
TeamMemberSerializer, TeamSerializer,
DeviceSerializer, GiftCardSerializer, GiftCardTransactionSerializer,
OrganizerSerializer, SeatingPlanSerializer, TeamAPITokenSerializer,
TeamInviteSerializer, TeamMemberSerializer, TeamSerializer,
)
from pretix.base.models import (
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
User,
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
TeamAPIToken, TeamInvite, User,
)
from pretix.helpers.dicts import merge_dicts
@@ -191,6 +191,24 @@ class GiftCardViewSet(viewsets.ModelViewSet):
raise MethodNotAllowed("Gift cards cannot be deleted.")
class GiftCardTransactionViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = GiftCardTransactionSerializer
queryset = GiftCardTransaction.objects.none()
permission = 'can_manage_gift_cards'
write_permission = 'can_manage_gift_cards'
@cached_property
def giftcard(self):
if self.request.GET.get('include_accepted') == 'true':
qs = self.request.organizer.accepted_gift_cards
else:
qs = self.request.organizer.issued_gift_cards.all()
return get_object_or_404(qs, pk=self.kwargs.get('giftcard'))
def get_queryset(self):
return self.giftcard.transactions.select_related('order', 'order__event')
class TeamViewSet(viewsets.ModelViewSet):
serializer_class = TeamSerializer
queryset = Team.objects.none()

View File

@@ -186,3 +186,26 @@ def test_giftcard_no_deletion(token_client, organizer, event, giftcard):
'/api/v1/organizers/{}/giftcards/{}/'.format(organizer.slug, giftcard.pk),
)
assert resp.status_code == 405
@pytest.mark.django_db
def test_giftcard_transactions(token_client, organizer, giftcard):
resp = token_client.get(
'/api/v1/organizers/{}/giftcards/{}/transactions/'.format(organizer.slug, giftcard.pk),
)
assert resp.status_code == 200
assert resp.data == {
"count": 1,
"next": None,
"previous": None,
"results": [
{
"id": giftcard.transactions.first().pk,
"datetime": giftcard.transactions.first().datetime.isoformat().replace("+00:00", "Z"),
"value": "23.00",
"event": None,
"order": None,
"text": None
}
]
}

View File

@@ -148,6 +148,8 @@ org_permission_sub_urls = [
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
('patch', 'can_manage_gift_cards', 'giftcards/1/', 404),
('get', 'can_manage_gift_cards', 'giftcards/1/transactions/', 404),
('get', 'can_manage_gift_cards', 'giftcards/1/transactions/1/', 404),
('get', 'can_change_organizer_settings', 'devices/', 200),
('post', 'can_change_organizer_settings', 'devices/', 400),
('get', 'can_change_organizer_settings', 'devices/1/', 404),