diff --git a/InvenTree/InvenTree/static/script/inventree/part.js b/InvenTree/InvenTree/static/script/inventree/part.js index 05b209b9b8..05328dbbd8 100644 --- a/InvenTree/InvenTree/static/script/inventree/part.js +++ b/InvenTree/InvenTree/static/script/inventree/part.js @@ -87,7 +87,7 @@ function loadPartTable(table, url, options={}) { * buttons: If provided, link buttons to selection status of this table */ - var params = options.parms || {}; + var params = options.params || {}; var filters = loadTableFilters("parts"); @@ -147,6 +147,10 @@ function loadPartTable(table, url, options={}) { display += ``; } + if (row.starred) { + display += ``; + } + /* if (row.component) { display = display + ``; diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index e1258385a5..59833d3e6b 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -494,15 +494,16 @@ class IndexView(TemplateView): context = super(TemplateView, self).get_context_data(**kwargs) - context['starred'] = [star.part for star in self.request.user.starred_parts.all()] + # TODO - Re-implement this when a less expensive method is worked out + # context['starred'] = [star.part for star in self.request.user.starred_parts.all()] # Generate a list of orderable parts which have stock below their minimum values # TODO - Is there a less expensive way to get these from the database - context['to_order'] = [part for part in Part.objects.filter(purchaseable=True) if part.need_to_restock()] + # context['to_order'] = [part for part in Part.objects.filter(purchaseable=True) if part.need_to_restock()] # Generate a list of assembly parts which have stock below their minimum values # TODO - Is there a less expensive way to get these from the database - context['to_build'] = [part for part in Part.objects.filter(assembly=True) if part.need_to_restock()] + # context['to_build'] = [part for part in Part.objects.filter(assembly=True) if part.need_to_restock()] return context diff --git a/InvenTree/company/templates/company/detail_part.html b/InvenTree/company/templates/company/detail_part.html index 537f7b07c3..2364f36b61 100644 --- a/InvenTree/company/templates/company/detail_part.html +++ b/InvenTree/company/templates/company/detail_part.html @@ -33,16 +33,29 @@ "{% url 'supplier-part-create' %}", { data: { - supplier: {{ company.id }} + {% if company.is_supplier %}supplier: {{ company.id }},{% endif %} + {% if company.is_manufacturer %}manufacturer: {{ company.id }},{% endif %} }, reload: true, secondary: [ { field: 'part', - label: 'New Part', - title: 'Create New Part', + label: '{% trans "New Part" %}', + title: '{% trans "Create new Part" %}', url: "{% url 'part-create' %}" }, + { + field: 'supplier', + label: "{% trans 'New Supplier' %}", + title: "{% trans 'Create new Supplier' %}", + url: "{% url 'supplier-create' %}", + }, + { + field: 'manufacturer', + label: '{% trans "New Manufacturer" %}', + title: '{% trans "Create new Manufacturer" %}', + url: "{% url 'manufacturer-create' %}", + }, ] }); }); diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index d1fc9b643f..ae88629505 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -273,10 +273,6 @@ class SupplierPartCreate(AjaxCreateView): Hide some fields if they are not appropriate in context """ form = super(AjaxCreateView, self).get_form() - - if form.initial.get('supplier', None): - # Hide the supplier field - form.fields['supplier'].widget = HiddenInput() if form.initial.get('part', None): # Hide the part field @@ -292,20 +288,27 @@ class SupplierPartCreate(AjaxCreateView): """ initials = super(SupplierPartCreate, self).get_initial().copy() + manufacturer_id = self.get_param('manufacturer') supplier_id = self.get_param('supplier') part_id = self.get_param('part') if supplier_id: try: initials['supplier'] = Company.objects.get(pk=supplier_id) - except Company.DoesNotExist: - initials['supplier'] = None + except (ValueError, Company.DoesNotExist): + pass + + if manufacturer_id: + try: + initials['manufacturer'] = Company.objects.get(pk=manufacturer_id) + except (ValueError, Company.DoesNotExist): + pass if part_id: try: initials['part'] = Part.objects.get(pk=part_id) - except Part.DoesNotExist: - initials['part'] = None + except (ValueError, Part.DoesNotExist): + pass return initials diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index 7d193fa1ee..e36d4a568b 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -153,6 +153,7 @@ class PartList(generics.ListCreateAPIView): The Part object list can be filtered by: - category: Filter by PartCategory reference - cascade: If true, include parts from sub-categories + - starred: Is the part "starred" by the current user? - is_template: Is the part a template part? - variant_of: Filter by variant_of Part reference - assembly: Filter by assembly field @@ -257,12 +258,18 @@ class PartList(generics.ListCreateAPIView): # Filter items which have an 'in_stock' level higher than 'minimum_stock' data = data.filter(Q(in_stock__gte=F('minimum_stock'))) + # Get a list of the parts that this user has starred + starred_parts = [star.part.pk for star in self.request.user.starred_parts.all()] + # Reduce the number of lookups we need to do for the part categories categories = {} for item in data: if item['image']: + # Is this part 'starred' for the current user? + item['starred'] = item['pk'] in starred_parts + img = item['image'] # Use the 'thumbnail' image here instead of the full-size image @@ -294,32 +301,53 @@ class PartList(generics.ListCreateAPIView): return Response(data) def get_queryset(self): - - # Does the user wish to filter by category? - cat_id = self.request.query_params.get('category', None) + """ + Implement custom filtering for the Part list API + """ # Start with all objects parts_list = Part.objects.all() - cascade = str2bool(self.request.query_params.get('cascade', False)) + # Filter by 'starred' parts? + starred = str2bool(self.request.query_params.get('starred', None)) + + if starred is not None: + starred_parts = [star.part.pk for star in self.request.user.starred_parts.all()] + + if starred: + parts_list = parts_list.filter(pk__in=starred_parts) + else: + parts_list = parts_list.exclude(pk__in=starred_parts) + + cascade = str2bool(self.request.query_params.get('cascade', None)) + + # Does the user wish to filter by category? + cat_id = self.request.query_params.get('category', None) if cat_id is None: - # Top-level parts - if not cascade: - parts_list = parts_list.filter(category=None) - + # No category filtering if category is not specified + pass + else: - try: - category = PartCategory.objects.get(pk=cat_id) + # Category has been specified! + if isNull(cat_id): + # A 'null' category is the top-level category + if cascade is False: + # Do not cascade, only list parts in the top-level category + parts_list = parts_list.filter(category=None) - # If '?cascade=true' then include parts which exist in sub-categories - if cascade: - parts_list = parts_list.filter(category__in=category.getUniqueChildren()) - # Just return parts directly in the requested category - else: - parts_list = parts_list.filter(category=cat_id) - except (ValueError, PartCategory.DoesNotExist): - pass + else: + try: + category = PartCategory.objects.get(pk=cat_id) + + # If '?cascade=true' then include parts which exist in sub-categories + if cascade: + parts_list = parts_list.filter(category__in=category.getUniqueChildren()) + # Just return parts directly in the requested category + else: + parts_list = parts_list.filter(category=cat_id) + except (ValueError, PartCategory.DoesNotExist): + pass # Ensure that related models are pre-loaded to reduce DB trips parts_list = self.get_serializer_class().setup_eager_loading(parts_list) diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index cc663a63c4..63a60bd71e 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -200,11 +200,11 @@ {% if category %} $("#cat-edit").click(function () { launchModalForm( - "{% url 'category-edit' category.id %}", - { - reload: true - }, - ); + "{% url 'category-edit' category.id %}", + { + reload: true + }, + ); return false; }); @@ -227,9 +227,9 @@ "#part-table", "{% url 'api-part-list' %}", { - query: { - {% if category %} - category: {{ category.id }}, + params: { + {% if category %}category: {{ category.id }}, + {% else %}category: "null", {% endif %} }, buttons: ['#part-options'], diff --git a/InvenTree/templates/InvenTree/index.html b/InvenTree/templates/InvenTree/index.html index c4eb5990cc..570378e55d 100644 --- a/InvenTree/templates/InvenTree/index.html +++ b/InvenTree/templates/InvenTree/index.html @@ -9,13 +9,7 @@ InvenTree | Index