diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 85e7c051bf..6041c2827e 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -41,7 +41,7 @@ from InvenTree.models import InvenTreeTree, InvenTreeAttachment from InvenTree.fields import InvenTreeURLField from InvenTree.helpers import decimal2string, normalize -from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus +from InvenTree.status_codes import BuildStatus, PurchaseOrderStatus, SalesOrderStatus from build import models as BuildModels from order import models as OrderModels @@ -940,6 +940,42 @@ class Part(MPTTModel): return quantity + def requiring_sales_orders(self): + """ + Return a list of sales orders which require this part + """ + + orders = set() + + # Get a list of line items for open orders which match this part + open_lines = OrderModels.SalesOrderLineItem.objects.filter( + order__status__in=SalesOrderStatus.OPEN, + part=self + ) + + for line in open_lines: + orders.add(line.order) + + return orders + + def required_sales_order_quantity(self): + """ + Return the quantity of this part required for active sales orders + """ + + # Get a list of line items for open orders which match this part + open_lines = OrderModels.SalesOrderLineItem.objects.filter( + order__status__in=SalesOrderStatus.OPEN, + part=self + ) + + quantity = 0 + + for line in open_lines: + quantity += line.quantity + + return quantity + @property def quantity_to_order(self): """ Return the quantity needing to be ordered for this part. """ diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 0ddb5d2180..24c0c0b234 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -126,28 +126,6 @@ {% trans "In Stock" %} {% include "part/stock_count.html" %} - {% if not part.is_template %} - {% if part.required_build_order_quantity > 0 %} - - - {% trans "Required for Build Orders" %} - {% decimal part.required_build_order_quantity %} - - {% endif %} - {% if part.build_order_allocation_count > 0 %} - - - {% trans "Allocated to Build Orders" %} - {% decimal part.build_order_allocation_count %} - - {% endif %} - {% if part.sales_order_allocation_count > 0 %} - - - {% trans "Allocated to Sales Orders" %} - {% decimal part.sales_order_allocation_count %} - - {% endif %} {% if part.on_order > 0 %} @@ -155,7 +133,21 @@ {% decimal part.on_order %} {% endif %} + {% if required > 0 %} + + + {% trans "Required for Orders" %} + {% decimal required %} + {% endif %} + {% if allocated > 0 %} + + + {% trans "Allocated to Orders" %} + {% decimal allocated %} + + {% endif %} + {% if not part.is_template %} {% if part.assembly %} @@ -169,11 +161,11 @@ {% trans "Can Build" %} {% decimal part.can_build %} - {% if part.quantity_being_built > 0 %} + {% if quantity_being_built > 0 %} {% trans "Underway" %} - {% decimal part.quantity_being_built %} + {% decimal quantity_being_built %} {% endif %} {% endif %} diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 8f1c86fdfc..42c48c8cab 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -792,6 +792,16 @@ class PartDetail(InvenTreeRoleMixin, DetailView): context['starred'] = part.isStarredBy(self.request.user) context['disabled'] = not part.active + # Pre-calculate complex queries so they only need to be performed once + context['required_build_order_quantity'] = part.required_build_order_quantity() + context['allocated_build_order_quantity'] = part.build_order_allocation_count() + + context['required_sales_order_quantity'] = part.required_sales_order_quantity() + context['allocated_sales_order_quantity'] = part.sales_order_allocation_count() + + context['required'] = context['required_build_order_quantity'] + context['required_sales_order_quantity'] + context['allocated'] = context['allocated_build_order_quantity'] + context['allocated_sales_order_quantity'] + return context