From 99fcbcc64657b20cdb5e4b691396a5647f605e42 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@gmail.com>
Date: Mon, 20 Apr 2020 09:41:21 +1000
Subject: [PATCH] Consolidation of PurchaseOrder API

---
 InvenTree/order/api.py         | 109 ++++++++++++++++++++-------------
 InvenTree/order/serializers.py |  39 +++++++++++-
 2 files changed, 104 insertions(+), 44 deletions(-)

diff --git a/InvenTree/order/api.py b/InvenTree/order/api.py
index 18ba890127..cf546bee21 100644
--- a/InvenTree/order/api.py
+++ b/InvenTree/order/api.py
@@ -14,6 +14,7 @@ from django.conf import settings
 from django.conf.urls import url
 
 from InvenTree.status_codes import OrderStatus
+from InvenTree.helpers import str2bool
 
 import os
 
@@ -34,66 +35,67 @@ class POList(generics.ListCreateAPIView):
     queryset = PurchaseOrder.objects.all()
     serializer_class = POSerializer
 
-    def list(self, request, *args, **kwargs):
+    def get_serializer(self, *args, **kwargs):
 
-        queryset = self.get_queryset().prefetch_related('supplier', 'lines')
+        try:
+            kwargs['supplier_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
+        except AttributeError:
+            pass
 
-        queryset = self.filter_queryset(queryset)
+        # Ensure the request context is passed through
+        kwargs['context'] = self.get_serializer_context()
+
+        return self.serializer_class(*args, **kwargs)
+
+    def get_queryset(self, *args, **kwargs):
+
+        queryset = super().get_queryset(*args, **kwargs)
+
+        queryset = queryset.prefetch_related(
+            'supplier',
+            'lines',
+        )
+
+        queryset = POSerializer.annotate_queryset(queryset)
+
+        return queryset
+
+
+    def filter_queryset(self, queryset):
+
+        # Perform basic filtering
+        queryset = super().filter_queryset(queryset)
+
+        params = self.request.query_params
 
         # Special filtering for 'status' field
-        if 'status' in request.GET:
-            status = request.GET['status']
+        status = params.get('status', None)
 
+        if status is not None:
             # First attempt to filter by integer value
-            try:
-                status = int(status)
-                queryset = queryset.filter(status=status)
-            except ValueError:
-                try:
-                    value = OrderStatus.value(status)
-                    queryset = queryset.filter(status=value)
-                except ValueError:
-                    pass
+            queryset = queryset.filter(status=status)
 
         # Attempt to filter by part
-        if 'part' in request.GET:
+        part = params.get('part', None)
+
+        if part is not None:
             try:
-                part = Part.objects.get(pk=request.GET['part'])
+                part = Part.objects.get(pk=part)
                 queryset = queryset.filter(id__in=[p.id for p in part.purchase_orders()])
             except (Part.DoesNotExist, ValueError):
                 pass
 
         # Attempt to filter by supplier part
-        if 'supplier_part' in request.GET:
+        supplier_part = params.get('supplier_part', None)
+
+        if supplier_part is not None:
             try:
-                supplier_part = SupplierPart.objects.get(pk=request.GET['supplier_part'])
+                supplier_part = SupplierPart.objects.get(pk=supplier_part)
                 queryset = queryset.filter(id__in=[p.id for p in supplier_part.purchase_orders()])
             except (ValueError, SupplierPart.DoesNotExist):
                 pass
 
-        data = queryset.values(
-            'pk',
-            'supplier',
-            'supplier_reference',
-            'supplier__name',
-            'supplier__image',
-            'reference',
-            'description',
-            'link',
-            'status',
-            'notes',
-            'creation_date',
-        )
-
-        for item in data:
-
-            order = queryset.get(pk=item['pk'])
-
-            item['supplier__image'] = os.path.join(settings.MEDIA_URL, item['supplier__image'])
-            item['status_text'] = OrderStatus.label(item['status'])
-            item['lines'] = order.lines.count()
-
-        return Response(data)
+        return queryset
 
     permission_classes = [
         permissions.IsAuthenticated,
@@ -123,6 +125,31 @@ class PODetail(generics.RetrieveUpdateAPIView):
     queryset = PurchaseOrder.objects.all()
     serializer_class = POSerializer
 
+    def get_serializer(self, *args, **kwargs):
+
+        try:
+            kwargs['supplier_detail'] = str2bool(self.request.query_params.get('supplier_detail', False))
+        except AttributeError:
+            pass
+
+        # Ensure the request context is passed through
+        kwargs['context'] = self.get_serializer_context()
+
+        return self.serializer_class(*args, **kwargs)
+
+    def get_queryset(self, *args, **kwargs):
+
+        queryset = super().get_queryset(*args, **kwargs)
+
+        queryset = queryset.prefetch_related(
+            'supplier',
+            'lines',
+        )
+
+        queryset = POSerializer.annotate_queryset(queryset)
+
+        return queryset
+
     permission_classes = [
         permissions.IsAuthenticated
     ]
diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py
index 9a8f1afee5..ab1471cdc1 100644
--- a/InvenTree/order/serializers.py
+++ b/InvenTree/order/serializers.py
@@ -5,7 +5,12 @@ JSON serializers for the Order API
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
+from rest_framework import serializers
+
+from django.db.models import Count
+
 from InvenTree.serializers import InvenTreeModelSerializer
+from company.serializers import CompanyBriefSerializer
 
 from .models import PurchaseOrder, PurchaseOrderLineItem
 
@@ -13,17 +18,45 @@ from .models import PurchaseOrder, PurchaseOrderLineItem
 class POSerializer(InvenTreeModelSerializer):
     """ Serializes an Order object """
 
+    def __init__(self, *args, **kwargs):
+
+        supplier_detail = kwargs.pop('supplier_detail', False)
+
+        super().__init__(*args, **kwargs)
+
+        if supplier_detail is not True:
+            self.fields.pop('supplier_detail')
+
+    @staticmethod
+    def annotate_queryset(queryset):
+        """
+        Add extra information to the queryset
+        """
+
+        return queryset.annotate(
+            line_items=Count('lines'),
+        )
+
+    supplier_detail = CompanyBriefSerializer(source='supplier', many=False, read_only=True)
+    
+    line_items = serializers.IntegerField(read_only=True)
+
+    status_text = serializers.CharField(source='get_status_display', read_only=True)
+
     class Meta:
         model = PurchaseOrder
         
         fields = [
             'pk',
-            'supplier',
-            'supplier_reference',
-            'reference',
             'description',
+            'line_items',
             'link',
+            'reference',
+            'supplier',
+            'supplier_detail',
+            'supplier_reference',
             'status',
+            'status_text',
             'notes',
         ]