forked from CGM_Public/pretix_original
Gift card API: Allow to inspect transactions (#1868)
This commit is contained in:
@@ -22,9 +22,28 @@ expires datetime Expiry date (or
|
|||||||
conditions string Special terms and conditions for this card (or ``null``)
|
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
|
Endpoints
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
.. versionadded:: 3.14
|
||||||
|
|
||||||
|
The transaction list endpoint was added.
|
||||||
|
|
||||||
.. http:get:: /api/v1/organizers/(organizer)/giftcards/
|
.. http:get:: /api/v1/organizers/(organizer)/giftcards/
|
||||||
|
|
||||||
Returns a list of all gift cards issued by a given organizer.
|
Returns a list of all gift cards issued by a given organizer.
|
||||||
@@ -250,3 +269,45 @@ Endpoints
|
|||||||
:statuscode 401: Authentication failure
|
:statuscode 401: Authentication failure
|
||||||
:statuscode 403: The requested organizer does not exist **or** you have no permission to change this resource.
|
: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.
|
: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.
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from pretix.api.serializers.i18n import I18nAwareModelSerializer
|
|||||||
from pretix.api.serializers.order import CompatibleJSONField
|
from pretix.api.serializers.order import CompatibleJSONField
|
||||||
from pretix.base.auth import get_auth_backends
|
from pretix.base.auth import get_auth_backends
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
|
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
|
||||||
User,
|
TeamAPIToken, TeamInvite, User,
|
||||||
)
|
)
|
||||||
from pretix.base.models.seating import SeatingPlanLayoutValidator
|
from pretix.base.models.seating import SeatingPlanLayoutValidator
|
||||||
from pretix.base.services.mail import SendMailException, mail
|
from pretix.base.services.mail import SendMailException, mail
|
||||||
@@ -59,6 +59,21 @@ class GiftCardSerializer(I18nAwareModelSerializer):
|
|||||||
fields = ('id', 'secret', 'issuance', 'value', 'currency', 'testmode', 'expires', 'conditions')
|
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):
|
class EventSlugField(serializers.SlugRelatedField):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.context['organizer'].events.all()
|
return self.context['organizer'].events.all()
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ order_router = routers.DefaultRouter()
|
|||||||
order_router.register(r'payments', order.PaymentViewSet)
|
order_router.register(r'payments', order.PaymentViewSet)
|
||||||
order_router.register(r'refunds', order.RefundViewSet)
|
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
|
# Force import of all plugins to give them a chance to register URLs with the router
|
||||||
for app in apps.get_app_configs():
|
for app in apps.get_app_configs():
|
||||||
if hasattr(app, 'PretixPluginMeta'):
|
if hasattr(app, 'PretixPluginMeta'):
|
||||||
@@ -71,6 +74,7 @@ for app in apps.get_app_configs():
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^organizers/(?P<organizer>[^/]+)/', include(orga_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(),
|
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/settings/$', event.EventSettingsView.as_view(),
|
||||||
name="event.settings"),
|
name="event.settings"),
|
||||||
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/', include(event_router.urls)),
|
url(r'^organizers/(?P<organizer>[^/]+)/events/(?P<event>[^/]+)/', include(event_router.urls)),
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ from rest_framework.viewsets import GenericViewSet
|
|||||||
|
|
||||||
from pretix.api.models import OAuthAccessToken
|
from pretix.api.models import OAuthAccessToken
|
||||||
from pretix.api.serializers.organizer import (
|
from pretix.api.serializers.organizer import (
|
||||||
DeviceSerializer, GiftCardSerializer, OrganizerSerializer,
|
DeviceSerializer, GiftCardSerializer, GiftCardTransactionSerializer,
|
||||||
SeatingPlanSerializer, TeamAPITokenSerializer, TeamInviteSerializer,
|
OrganizerSerializer, SeatingPlanSerializer, TeamAPITokenSerializer,
|
||||||
TeamMemberSerializer, TeamSerializer,
|
TeamInviteSerializer, TeamMemberSerializer, TeamSerializer,
|
||||||
)
|
)
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Device, GiftCard, Organizer, SeatingPlan, Team, TeamAPIToken, TeamInvite,
|
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
|
||||||
User,
|
TeamAPIToken, TeamInvite, User,
|
||||||
)
|
)
|
||||||
from pretix.helpers.dicts import merge_dicts
|
from pretix.helpers.dicts import merge_dicts
|
||||||
|
|
||||||
@@ -191,6 +191,24 @@ class GiftCardViewSet(viewsets.ModelViewSet):
|
|||||||
raise MethodNotAllowed("Gift cards cannot be deleted.")
|
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):
|
class TeamViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = TeamSerializer
|
serializer_class = TeamSerializer
|
||||||
queryset = Team.objects.none()
|
queryset = Team.objects.none()
|
||||||
|
|||||||
@@ -186,3 +186,26 @@ def test_giftcard_no_deletion(token_client, organizer, event, giftcard):
|
|||||||
'/api/v1/organizers/{}/giftcards/{}/'.format(organizer.slug, giftcard.pk),
|
'/api/v1/organizers/{}/giftcards/{}/'.format(organizer.slug, giftcard.pk),
|
||||||
)
|
)
|
||||||
assert resp.status_code == 405
|
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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ org_permission_sub_urls = [
|
|||||||
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
('get', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||||
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
('put', 'can_manage_gift_cards', 'giftcards/1/', 404),
|
||||||
('patch', '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),
|
('get', 'can_change_organizer_settings', 'devices/', 200),
|
||||||
('post', 'can_change_organizer_settings', 'devices/', 400),
|
('post', 'can_change_organizer_settings', 'devices/', 400),
|
||||||
('get', 'can_change_organizer_settings', 'devices/1/', 404),
|
('get', 'can_change_organizer_settings', 'devices/1/', 404),
|
||||||
|
|||||||
Reference in New Issue
Block a user