diff --git a/InvenTree/InvenTree/static/script/inventree/part.js b/InvenTree/InvenTree/static/script/inventree/part.js
index c94c512d6f..693a4d1faa 100644
--- a/InvenTree/InvenTree/static/script/inventree/part.js
+++ b/InvenTree/InvenTree/static/script/inventree/part.js
@@ -181,9 +181,7 @@ function loadPartTable(table, url, options={}) {
title: 'Stock',
searchable: false,
sortable: true,
- formatter: function(value, row, index, field) {
- console.log("On order:", row.on_order);
-
+ formatter: function(value, row, index, field) {
var html = "";
var link = "stock";
@@ -198,6 +196,9 @@ function loadPartTable(table, url, options={}) {
} else if (row.on_order) {
value = "On Order : " + row.on_order + "";
link = "orders";
+ } else if (row.building) {
+ value = "Building : " + row.building + "";
+ link = "builds";
} else {
value ="No Stock";
}
diff --git a/InvenTree/InvenTree/status_codes.py b/InvenTree/InvenTree/status_codes.py
index e49f9a9824..cbc9f3565f 100644
--- a/InvenTree/InvenTree/status_codes.py
+++ b/InvenTree/InvenTree/status_codes.py
@@ -71,11 +71,17 @@ class StockStatus(StatusCode):
LOST: _("Lost"),
}
- # The following codes correspond to parts that are 'available'
+ # The following codes correspond to parts that are 'available' or 'in stock'
AVAILABLE_CODES = [
OK,
ATTENTION,
- DAMAGED
+ DAMAGED,
+ ]
+
+ # The following codes correspond to parts that are 'unavailable'
+ UNAVAILABLE_CODES = [
+ DESTROYED,
+ LOST,
]
diff --git a/InvenTree/order/tests.py b/InvenTree/order/tests.py
index 351c152472..35cf8909be 100644
--- a/InvenTree/order/tests.py
+++ b/InvenTree/order/tests.py
@@ -130,9 +130,10 @@ class OrderTest(TestCase):
order.receive_line_item(line, loc, 50, user=None)
line = PurchaseOrderLineItem.objects.get(id=2)
- order.receive_line_item(line, loc, 2 * line.quantity, user=None)
- self.assertEqual(part.on_order, 1100)
+ order.receive_line_item(line, loc, 500, user=None)
+
+ self.assertEqual(part.on_order, 800)
self.assertEqual(order.status, OrderStatus.PLACED)
for line in order.pending_line_items():
diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py
index d24f0dc6ee..1d6aaa84aa 100644
--- a/InvenTree/part/api.py
+++ b/InvenTree/part/api.py
@@ -8,7 +8,7 @@ from __future__ import unicode_literals
from django_filters.rest_framework import DjangoFilterBackend
from django.conf import settings
-from django.db.models import Sum, Count
+from django.db.models import Q, Sum, Count
from rest_framework import status
from rest_framework.response import Response
@@ -25,6 +25,7 @@ from .models import PartParameter, PartParameterTemplate
from . import serializers as part_serializers
+from InvenTree.status_codes import OrderStatus, StockStatus, BuildStatus
from InvenTree.views import TreeSerializer
from InvenTree.helpers import str2bool
@@ -153,6 +154,18 @@ class PartList(generics.ListCreateAPIView):
queryset = self.filter_queryset(self.get_queryset())
+ # Filters for annotations
+
+ # "in_stock" count should only sum stock items which are "in stock"
+ stock_filter = Q(stock_items__status__in=StockStatus.AVAILABLE_CODES)
+
+ # "on_order" items should only sum orders which are currently outstanding
+ order_filter = Q(supplier_parts__purchase_order_line_items__order__status__in=OrderStatus.OPEN)
+
+ # "building" should only reference builds which are active
+ build_filter = Q(builds__status__in=BuildStatus.ACTIVE_CODES)
+
+ # Set of fields we wish to serialize
data = queryset.values(
'pk',
'category',
@@ -171,13 +184,12 @@ class PartList(generics.ListCreateAPIView):
'salable',
'active',
).annotate(
- in_stock=Sum('stock_items__quantity'),
- on_order=Sum('supplier_parts__purchase_order_line_items__quantity'),
+ # Quantity of items which are "in stock"
+ in_stock=Sum('stock_items__quantity', filter=stock_filter),
+ on_order=Sum('supplier_parts__purchase_order_line_items__quantity', filter=order_filter),
+ building=Sum('builds__quantity', filter=build_filter),
)
- # TODO - Annotate total being built
- # TODO - Annotate total on order
-
# Reduce the number of lookups we need to do for the part categories
categories = {}
diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py
index d22e6e7be1..58ee8bbd2c 100644
--- a/InvenTree/part/models.py
+++ b/InvenTree/part/models.py
@@ -569,7 +569,12 @@ class Part(models.Model):
""" Return the current number of parts currently being built
"""
- return sum([b.quantity for b in self.active_builds])
+ quantity = self.active_builds.aggregate(quantity=Sum('quantity'))['quantity']
+
+ if quantity is None:
+ quantity = 0
+
+ return quantity
@property
def build_allocation(self):
@@ -919,7 +924,21 @@ class Part(models.Model):
def on_order(self):
""" Return the total number of items on order for this part. """
- return sum([part.on_order() for part in self.supplier_parts.all().prefetch_related('purchase_order_line_items')])
+ orders = self.supplier_parts.filter(purchase_order_line_items__order__status__in=OrderStatus.OPEN).aggregate(
+ quantity=Sum('purchase_order_line_items__quantity'),
+ received=Sum('purchase_order_line_items__received')
+ )
+
+ quantity = orders['quantity']
+ received = orders['received']
+
+ if quantity is None:
+ quantity = 0
+
+ if received is None:
+ received = 0
+
+ return quantity - received
def get_parameters(self):
""" Return all parameters for this part, ordered by name """