Change API to accomodate for invoice numbers

This commit is contained in:
Raphael Michel
2017-07-18 10:37:32 +02:00
parent c9990e5ca4
commit 2ad9e1bb43
4 changed files with 42 additions and 23 deletions
+13 -6
View File
@@ -11,7 +11,7 @@ The invoice resource contains the following public fields:
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
invoice_no string Invoice number (without prefix)
number string Invoice number (with prefix)
order string Order code of the order this invoice belongs to
is_cancellation boolean ``True``, if this invoice is the cancellation of a
different invoice.
@@ -35,6 +35,13 @@ lines list of objects The actual invo
===================================== ========================== =======================================================
.. versionchanged:: 1.6
The attribute ``invoice_no`` has been dropped in favor of ``number`` which includes the number including the prefix,
since the prefix can now vary. Also, invoices now need to be identified by their ``number`` instead of the raw
number.
Endpoints
---------
@@ -64,7 +71,7 @@ Endpoints
"previous": null,
"results": [
{
"invoice_no": "00001",
"number": "SAMPLECONF-00001",
"order": "ABC12",
"is_cancellation": false,
"invoice_from": "Big Events LLC\nDemo street 12\nDemo town",
@@ -95,14 +102,14 @@ Endpoints
:query string refers: If set, only invoices refering to the given invoice will be returned.
:query string locale: If set, only invoices with the given locale will be returned.
:query string ordering: Manually set the ordering of results. Valid fields to be used are ``date`` and
``invoice_no``. Default: ``invoice_no``
``nr`` (equals to ``number``). Default: ``nr``
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/invoices/(invoice_no)/
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/invoices/(number)/
Returns information on one invoice, identified by its invoice number.
@@ -110,7 +117,7 @@ Endpoints
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/00001/ HTTP/1.1
GET /api/v1/organizers/bigevents/events/sampleconf/invoices/SAMPLECONF-00001/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
@@ -123,7 +130,7 @@ Endpoints
Content-Type: text/javascript
{
"invoice_no": "00001",
"number": "SAMPLECONF-00001",
"order": "ABC12",
"is_cancellation": false,
"invoice_from": "Big Events LLC\nDemo street 12\nDemo town",
+1 -1
View File
@@ -115,5 +115,5 @@ class InvoiceSerializer(I18nAwareModelSerializer):
class Meta:
model = Invoice
fields = ('order', 'invoice_no', 'is_cancellation', 'invoice_from', 'invoice_to', 'date', 'refers', 'locale',
fields = ('order', 'number', 'is_cancellation', 'invoice_from', 'invoice_to', 'date', 'refers', 'locale',
'introductory_text', 'additional_text', 'payment_provider_text', 'footer_text', 'lines')
+19 -7
View File
@@ -1,5 +1,6 @@
import django_filters
from django.db.models import Q
from django.db.models.functions import Concat
from django.http import FileResponse
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from rest_framework import viewsets
@@ -137,12 +138,21 @@ class OrderPositionViewSet(viewsets.ReadOnlyModelViewSet):
class InvoiceFilter(FilterSet):
refers = django_filters.CharFilter(name='refers', lookup_expr='invoice_no__iexact')
refers = django_filters.CharFilter(method='refers_qs')
number = django_filters.CharFilter(method='nr_qs')
order = django_filters.CharFilter(name='order', lookup_expr='code__iexact')
def refers_qs(self, queryset, name, value):
return queryset.annotate(
refers_nr=Concat('refers__prefix', 'refers__invoice_no')
).filter(refers_nr__iexact=value)
def nr_qs(self, queryset, name, value):
return queryset.filter(nr__iexact=value)
class Meta:
model = Invoice
fields = ['order', 'invoice_no', 'is_cancellation', 'refers', 'locale']
fields = ['order', 'number', 'is_cancellation', 'refers', 'locale']
class RetryException(APIException):
@@ -155,15 +165,17 @@ class InvoiceViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = InvoiceSerializer
queryset = Invoice.objects.none()
filter_backends = (DjangoFilterBackend, OrderingFilter)
ordering = ('invoice_no',)
ordering_fields = ('invoice_no', 'date')
ordering = ('nr',)
ordering_fields = ('nr', 'date')
filter_class = InvoiceFilter
lookup_field = 'invoice_no'
lookup_url_kwarg = 'invoice_no'
permission = 'can_view_orders'
lookup_url_kwarg = 'number'
lookup_field = 'nr'
def get_queryset(self):
return self.request.event.invoices.prefetch_related('lines').select_related('order')
return self.request.event.invoices.prefetch_related('lines').select_related('order', 'refers').annotate(
nr=Concat('prefix', 'invoice_no')
)
@detail_route()
def download(self, request, **kwargs):
+9 -9
View File
@@ -256,7 +256,7 @@ def invoice(order):
TEST_INVOICE_RES = {
"order": "FOO",
"invoice_no": "00001",
"number": "DUMMY-00001",
"is_cancellation": False,
"invoice_from": "",
"invoice_to": "Sample company",
@@ -291,10 +291,10 @@ def test_invoice_list(token_client, organizer, event, order, invoice):
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?order=BAR'.format(organizer.slug, event.slug))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?invoice_no={}'.format(
organizer.slug, event.slug, invoice.invoice_no))
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?number={}'.format(
organizer.slug, event.slug, invoice.number))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?invoice_no=XXX'.format(
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?number=XXX'.format(
organizer.slug, event.slug))
assert [] == resp.data['results']
@@ -313,15 +313,15 @@ def test_invoice_list(token_client, organizer, event, order, invoice):
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?is_cancellation=true'.format(
organizer.slug, event.slug))
assert len(resp.data['results']) == 1
assert resp.data['results'][0]['invoice_no'] == ic.invoice_no
assert resp.data['results'][0]['number'] == ic.number
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?refers={}'.format(
organizer.slug, event.slug, invoice.invoice_no))
organizer.slug, event.slug, invoice.number))
assert len(resp.data['results']) == 1
assert resp.data['results'][0]['invoice_no'] == ic.invoice_no
assert resp.data['results'][0]['number'] == ic.number
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?refers={}'.format(
organizer.slug, event.slug, ic.invoice_no))
organizer.slug, event.slug, ic.number))
assert [] == resp.data['results']
@@ -330,6 +330,6 @@ def test_invoice_detail(token_client, organizer, event, invoice):
res = dict(TEST_INVOICE_RES)
resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/{}/'.format(organizer.slug, event.slug,
invoice.invoice_no))
invoice.number))
assert resp.status_code == 200
assert res == resp.data