From 3c5968ef1ae21ddb3afd3ddc752b0e1cbdcaa28b Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 4 Oct 2020 22:58:41 +1100 Subject: [PATCH] Add subrow table to the "installed items" view Ah, javascript... --- .../stock/templates/stock/item_installed.html | 151 +--------------- InvenTree/templates/js/stock.html | 170 +++++++++++++++++- 2 files changed, 174 insertions(+), 147 deletions(-) diff --git a/InvenTree/stock/templates/stock/item_installed.html b/InvenTree/stock/templates/stock/item_installed.html index cac55c9dce..2a6a0db057 100644 --- a/InvenTree/stock/templates/stock/item_installed.html +++ b/InvenTree/stock/templates/stock/item_installed.html @@ -10,19 +10,7 @@

{% trans "Installed Stock Items" %}


-
-
-
- - -
-
-
- - -
+
{% endblock %} @@ -30,135 +18,14 @@ {{ block.super }} -$('#installed-table').inventreeTable({ - formatNoMatches: function() { - return '{% trans "No stock items installed" %}'; - }, - url: "{% url 'api-stock-list' %}", - queryParams: { - installed_in: {{ item.id }}, - part_detail: true, - }, - name: 'stock-item-installed', - url: "{% url 'api-stock-list' %}", - showColumns: true, - columns: [ - { - checkbox: true, - title: '{% trans 'Select' %}', - searchable: false, - switchable: false, - }, - { - field: 'pk', - title: 'ID', - visible: false, - switchable: false, - }, - { - field: 'part_name', - title: '{% trans "Part" %}', - sortable: true, - formatter: function(value, row, index, field) { - - var url = `/stock/item/${row.pk}/`; - var thumb = row.part_detail.thumbnail; - var name = row.part_detail.full_name; - - html = imageHoverIcon(thumb) + renderLink(name, url); - - return html; - } - }, - { - field: 'IPN', - title: 'IPN', - sortable: true, - formatter: function(value, row, index, field) { - return row.part_detail.IPN; - }, - }, - { - field: 'part_description', - title: '{% trans "Description" %}', - sortable: true, - formatter: function(value, row, index, field) { - return row.part_detail.description; - } - }, - { - field: 'quantity', - title: '{% trans "Stock" %}', - sortable: true, - formatter: function(value, row, index, field) { - - var val = parseFloat(value); - - // If there is a single unit with a serial number, use the serial number - if (row.serial && row.quantity == 1) { - val = '# ' + row.serial; - } else { - val = +val.toFixed(5); - } - - var html = renderLink(val, `/stock/item/${row.pk}/`); - - return html; - } - }, - { - field: 'status', - title: '{% trans "Status" %}', - sortable: 'true', - formatter: function(value, row, index, field) { - return stockStatusDisplay(value); - }, - }, - { - field: 'batch', - title: '{% trans "Batch" %}', - sortable: true, - }, - { - field: 'actions', - switchable: false, - title: '', - formatter: function(value, row) { - var pk = row.pk; - - var html = `
`; - - html += makeIconButton('fa-unlink', 'button-uninstall', pk, '{% trans "Uninstall item" %}'); - - html += `
`; - - return html; - } - } - ], - onLoadSuccess: function() { - - var table = $('#installed-table'); - - // Find buttons and associate actions - table.find('.button-uninstall').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - "{% url 'stock-item-uninstall' %}", - { - data: { - 'items[]': [pk], - }, - reload: true, - } - ); - }); - }, - buttons: [ - '#stock-options', - ] -}); +loadInstalledInTable( + $('#installed-table'), + { + stock_item: {{ item.pk }}, + part: {{ item.part.pk }}, + quantity: {{ item.quantity }}, + } +); $('#multi-item-uninstall').click(function() { diff --git a/InvenTree/templates/js/stock.html b/InvenTree/templates/js/stock.html index 4ec2507b31..330be924e5 100644 --- a/InvenTree/templates/js/stock.html +++ b/InvenTree/templates/js/stock.html @@ -830,8 +830,25 @@ function loadInstalledInTable(table, options) { * * - stock_item: The PK of the master stock_item object * - part: The PK of the Part reference of the stock_item object + * - quantity: The quantity of the stock item */ + function updateCallbacks() { + // Setup callback functions when buttons are pressed + table.find('.button-install').click(function() { + var pk = $(this).attr('pk'); + + launchModalForm( + `/stock/item/${options.stock_item}/install/`, + { + data: { + part: pk, + }, + } + ); + }); + } + table.inventreeTable( { url: "{% url 'api-bom-list' %}", @@ -842,6 +859,92 @@ function loadInstalledInTable(table, options) { }, showColumns: false, name: 'installed-in', + detailView: true, + detailViewByClick: true, + detailFilter: function(index, row) { + return row.installed_count && row.installed_count > 0; + }, + detailFormatter: function(index, row, element) { + var subTableId = `installed-table-${row.sub_part}`; + + var html = `
`; + + element.html(html); + + var subTable = $(`#${subTableId}`); + + // Display a "sub table" showing all the linked stock items + subTable.bootstrapTable({ + data: row.installed_items, + showHeader: true, + columns: [ + { + field: 'item', + title: '{% trans "Stock Item" %}', + formatter: function(value, subrow, index, field) { + + var pk = subrow.pk; + var html = ''; + + html += row.sub_part_detail.full_name; + html += " | "; + + if (subrow.serial && subrow.quantity == 1) { + html += `{% trans "Serial" %}: ${subrow.serial}`; + } else { + html += `{% trans "Quantity" %}: ${subrow.quantity}`; + } + + return html; + }, + }, + { + field: 'status', + title: '{% trans "Status" %}', + formatter: function(value, subrow, index, field) { + return stockStatusDisplay(value); + } + }, + { + field: 'actions', + title: '', + formatter: function(value, subrow, index) { + + var pk = subrow.pk; + var html = ''; + + // Add some buttons yo! + html += `
`; + + html += makeIconButton('fa-unlink', 'button-uninstall', pk, "{% trans "Uninstall stock item" %}"); + + html += `
`; + + return html; + } + } + ], + onPostBody: function() { + // Setup button callbacks + subTable.find('.button-uninstall').click(function() { + var pk = $(this).attr('pk'); + + launchModalForm( + "{% url 'stock-item-uninstall' %}", + { + data: { + 'items[]': [pk], + }, + success: function() { + // Refresh entire table! + table.bootstrapTable('refresh'); + } + } + ); + }); + } + }); + }, columns: [ { checkbox: true, @@ -861,7 +964,7 @@ function loadInstalledInTable(table, options) { sortable: true, formatter: function(value, row, index, field) { - var url = `/stock/item/${row.pk}/`; + var url = `/part/${row.sub_part}/`; var thumb = row.sub_part_detail.thumbnail; var name = row.sub_part_detail.full_name; @@ -877,9 +980,11 @@ function loadInstalledInTable(table, options) { formatter: function(value, row, index, field) { // Construct a progress showing how many items have been installed - var installed = row.installed || 0; + var installed = row.installed_count || 0; var required = row.quantity || 0; + required *= options.quantity; + var progress = makeProgressBar(installed, required, { id: row.sub_part.pk, }); @@ -891,7 +996,7 @@ function loadInstalledInTable(table, options) { field: 'actions', switchable: false, formatter: function(value, row) { - var pk = row.sub_part.pk; + var pk = row.sub_part; var html = `
`; @@ -904,8 +1009,63 @@ function loadInstalledInTable(table, options) { } ], onLoadSuccess: function() { - console.log('data loaded!'); - } + // Grab a list of parts which are actually installed in this stock item + + inventreeGet( + "{% url 'api-stock-list' %}", + { + installed_in: options.stock_item, + }, + { + success: function(stock_items) { + + var table_data = table.bootstrapTable('getData'); + + stock_items.forEach(function(item) { + + var match = false; + + for (var idx = 0; idx < table_data.length; idx++) { + + var row = table_data[idx]; + + // Check each row in the table to see if this stock item matches + table_data.forEach(function(row) { + + // Match on "sub_part" + if (row.sub_part == item.part) { + + // First time? + if (row.installed_count == null) { + row.installed_count = 0; + row.installed_items = []; + } + + row.installed_count += item.quantity; + row.installed_items.push(item); + + // Push the row back into the table + table.bootstrapTable('updateRow', idx, row, true); + + match = true; + } + + }); + + if (match) { + break; + } + } + }); + + // Update button callback links + updateCallbacks(); + } + } + ); + + updateCallbacks(); + }, } ); } \ No newline at end of file