From 2c6e8da90ec55ed3da1a6eea1b1594a0bbfdd73b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 21 Apr 2020 17:33:02 +1000 Subject: [PATCH] Ability to filter StockItemList API by sales_order or sales_order_line --- InvenTree/stock/api.py | 20 ++++++++++++++++--- .../migrations/0028_auto_20200421_0724.py | 18 +++++++++++++++++ InvenTree/stock/models.py | 12 +++++------ 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 InvenTree/stock/migrations/0028_auto_20200421_0724.py diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 77b35f45d0..450f6e95f1 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -12,6 +12,7 @@ from django.db.models import Q from .models import StockLocation, StockItem from .models import StockItemTracking +from order.models import SalesOrder from part.models import Part, PartCategory from .serializers import StockItemSerializer @@ -387,7 +388,7 @@ class StockList(generics.ListCreateAPIView): stock_list = stock_list.filter(part=part_id) except (ValueError, Part.DoesNotExist): - pass + raise ValidationError({"part": "Invalid Part ID specified"}) # Does the client wish to filter by the 'ancestor'? anc_id = self.request.query_params.get('ancestor', None) @@ -400,7 +401,7 @@ class StockList(generics.ListCreateAPIView): stock_list = stock_list.filter(id__in=[item.pk for item in ancestor.children.all()]) except (ValueError, Part.DoesNotExist): - pass + raise ValidationError({"ancestor": "Invalid ancestor ID specified"}) # Does the client wish to filter by stock location? loc_id = self.request.query_params.get('location', None) @@ -433,7 +434,7 @@ class StockList(generics.ListCreateAPIView): stock_list = stock_list.filter(part__category__in=category.getUniqueChildren()) except (ValueError, PartCategory.DoesNotExist): - pass + raise ValidationError({"category": "Invalid category id specified"}) # Filter by StockItem status status = self.request.query_params.get('status', None) @@ -465,10 +466,22 @@ class StockList(generics.ListCreateAPIView): if manufacturer is not None: stock_list = stock_list.filter(supplier_part__manufacturer=manufacturer) + # Filter by sales order + sales_order = self.request.query_params.get('sales_order', None) + + if sales_order is not None: + try: + sales_order = SalesOrder.objects.get(pk=sales_order) + lines = [line.pk for line in sales_order.lines.all()] + stock_list = stock_list.filter(sales_order_line__in=lines) + except (SalesOrder.DoesNotExist, ValueError): + raise ValidationError({'sales_order': 'Invalid SalesOrder object specified'}) + # Also ensure that we pre-fecth all the related items stock_list = stock_list.prefetch_related( 'part', 'part__category', + 'sales_order_line__order', 'location' ) @@ -493,6 +506,7 @@ class StockList(generics.ListCreateAPIView): 'customer', 'belongs_to', 'build', + 'sales_order_line' ] diff --git a/InvenTree/stock/migrations/0028_auto_20200421_0724.py b/InvenTree/stock/migrations/0028_auto_20200421_0724.py new file mode 100644 index 0000000000..61ebe97039 --- /dev/null +++ b/InvenTree/stock/migrations/0028_auto_20200421_0724.py @@ -0,0 +1,18 @@ +# Generated by Django 3.0.5 on 2020-04-21 07:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0027_stockitem_sales_order'), + ] + + operations = [ + migrations.RenameField( + model_name='stockitem', + old_name='sales_order', + new_name='sales_order_line', + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 1129a3ce79..4970083f0c 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -266,13 +266,13 @@ class StockItem(MPTTModel): try: # If this StockItem is assigned to a SalesOrderLineItem, # the "Part" that the line item references is the same as the part that THIS references - if self.sales_order is not None: + if self.sales_order_line is not None: - if self.sales_order.part == None: - raise ValidationError({'sales_order': _('Stock item cannot be assigned to a LineItem which does not reference a part')}) + if self.sales_order_line.part == None: + raise ValidationError({'sales_order_line': _('Stock item cannot be assigned to a LineItem which does not reference a part')}) - if not self.sales_order.part == self.part: - raise ValidationError({'sales_order': _('Stock item does not reference the same part object as the LineItem')}) + if not self.sales_order_line.part == self.part: + raise ValidationError({'sales_order_line': _('Stock item does not reference the same part object as the LineItem')}) except SalesOrderLineItem.DoesNotExist: pass @@ -369,7 +369,7 @@ class StockItem(MPTTModel): help_text=_('Purchase order for this stock item') ) - sales_order = models.ForeignKey( + sales_order_line = models.ForeignKey( SalesOrderLineItem, on_delete=models.SET_NULL, related_name='stock_items',