diff --git a/InvenTree/build/templates/build/build_output.html b/InvenTree/build/templates/build/build_output.html
index e5a3e77e61..75257f2d5d 100644
--- a/InvenTree/build/templates/build/build_output.html
+++ b/InvenTree/build/templates/build/build_output.html
@@ -19,7 +19,7 @@
loadStockTable($("#stock-table"), {
params: {
location_detail: true,
- part_details: true,
+ part_detail: true,
build: {{ build.id }},
},
groupByField: 'location',
diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py
index 900a94ed52..55bc62a44e 100644
--- a/InvenTree/stock/api.py
+++ b/InvenTree/stock/api.py
@@ -476,6 +476,26 @@ class StockList(generics.ListCreateAPIView):
if sales_order:
queryset = queryset.filter(sales_order=sales_order)
+ # Filter stock items which are installed in another (specific) stock item
+ installed_in = params.get('installed_in', None)
+
+ if installed_in:
+ # Note: The "installed_in" field is called "belongs_to"
+ queryset = queryset.filter(belongs_to=installed_in)
+
+ # Filter stock items which are installed in another stock item
+ installed = params.get('installed', None)
+
+ if installed is not None:
+ installed = str2bool(installed)
+
+ if installed:
+ # Exclude items which are *not* installed in another item
+ queryset = queryset.exclude(belongs_to=None)
+ else:
+ # Exclude items which are instaled in another item
+ queryset = queryset.filter(belongs_to=None)
+
# Filter by customer
customer = params.get('customer', None)
diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html
new file mode 100644
index 0000000000..abecaf6e3c
--- /dev/null
+++ b/InvenTree/stock/templates/stock/item_installed.html
@@ -0,0 +1,31 @@
+{% extends "stock/item_base.html" %}
+
+{% load static %}
+{% load i18n %}
+
+{% block details %}
+
+{% include "stock/tabs.html" with tab='installed' %}
+
+
{% trans "Installed Items" %}
+
+
+
+
+{% endblock %}
+
+{% block js_ready %}
+
+{{ block.super }}
+
+loadStockTable($("#installed-table"), {
+ params: {
+ installed_in: {{ item.id }},
+ part_detail: true,
+ },
+ name: 'stock-item-installed',
+ url: "{% url 'api-stock-list' %}",
+})
+
+{% endblock %}
\ No newline at end of file
diff --git a/InvenTree/stock/templates/stock/tabs.html b/InvenTree/stock/templates/stock/tabs.html
index 72da8a5cf2..05841987da 100644
--- a/InvenTree/stock/templates/stock/tabs.html
+++ b/InvenTree/stock/templates/stock/tabs.html
@@ -38,11 +38,11 @@
{% trans "Children" %}{% if item.child_count > 0 %}{{ item.child_count }}{% endif %}
{% endif %}
- {% if item.installedItemCount > 0 %}
+ {% if item.part.assembly or item.installedItemCount > 0 %}
-
+
{% trans "Installed Parts" %}
- {{ item.installedItemCount }}
+ {% if item.installedItemCount > 0 %}{{ item.installedItemCount }}{% endif %}
{% endif %}
diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py
index 51067b57de..c6b0b2b54c 100644
--- a/InvenTree/stock/urls.py
+++ b/InvenTree/stock/urls.py
@@ -34,6 +34,7 @@ stock_item_detail_urls = [
url(r'^test/', views.StockItemDetail.as_view(template_name='stock/item_tests.html'), name='stock-item-test-results'),
url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'),
url(r'^attachments/', views.StockItemDetail.as_view(template_name='stock/item_attachments.html'), name='stock-item-attachments'),
+ url(r'^installed/', views.StockItemDetail.as_view(template_name='stock/item_installed.html'), name='stock-item-installed'),
url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'),
url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'),
diff --git a/InvenTree/templates/js/stock.html b/InvenTree/templates/js/stock.html
index bb0673c16d..9a9e629efe 100644
--- a/InvenTree/templates/js/stock.html
+++ b/InvenTree/templates/js/stock.html
@@ -512,16 +512,20 @@ function loadStockTable(table, options) {
title: '{% trans "Location" %}',
sortable: true,
formatter: function(value, row, index, field) {
- if (value) {
+ if (row.belongs_to) {
+ var text = "{% trans 'Installed in Stock Item ' %}" + row.belongs_to;
+ var url = `/stock/item/${row.belongs_to}/installed/`;
+
+ return renderLink(text, url);
+ } else if (row.customer) {
+ var text = "{% trans "Shipped to customer" %}";
+ return renderLink(text, `/company/${row.customer}/assigned-stock/`);
+ }
+ else if (value) {
return renderLink(value, `/stock/location/${row.location}/`);
}
else {
- if (row.customer) {
- var text = "{% trans "Shipped to customer" %}";
- return renderLink(text, `/company/${row.customer}/assigned-stock/`);
- } else {
- return '{% trans "No stock location set" %}';
- }
+ return '{% trans "No stock location set" %}';
}
}
},
diff --git a/InvenTree/templates/js/table_filters.html b/InvenTree/templates/js/table_filters.html
index 316abcad7b..44c4149265 100644
--- a/InvenTree/templates/js/table_filters.html
+++ b/InvenTree/templates/js/table_filters.html
@@ -65,6 +65,11 @@ function getAvailableTableFilters(tableKey) {
title: '{% trans "In Stock" %}',
description: '{% trans "Show items which are in stock" %}',
},
+ installed: {
+ type: 'bool',
+ title: '{% trans "Installed" %}',
+ description: '{% trans "Show stock items which are installed in another item" %}',
+ },
sent_to_customer: {
type: 'bool',
title: '{% trans "Sent to customer" %}',