@@ -164,14 +181,21 @@
// Load the "allocations" tab
onPanelLoad('allocations', function() {
- loadStockAllocationTable(
- $("#stock-allocation-table"),
- {
- params: {
- stock_item: {{ item.pk }},
- },
+ {% if item.part.component %}
+ loadBuildOrderAllocationTable('#build-order-allocation-table', {
+ params: {
+ stock_item: {{ item.pk }},
}
- );
+ });
+ {% endif %}
+
+ {% if item.part.salable %}
+ loadSalesOrderAllocationTable('#sales-order-allocation-table', {
+ params: {
+ stock_item: {{ item.pk }},
+ }
+ });
+ {% endif %}
});
$('#stock-item-install').click(function() {
diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html
index 1da0030bc6..45dcc0ba59 100644
--- a/InvenTree/stock/templates/stock/location.html
+++ b/InvenTree/stock/templates/stock/location.html
@@ -202,15 +202,17 @@
{% block js_ready %}
{{ block.super }}
- loadStockLocationTable($('#sublocation-table'), {
- params: {
- {% if location %}
- parent: {{ location.pk }},
- {% else %}
- parent: 'null',
- {% endif %}
- },
- allowTreeView: true,
+ onPanelLoad('sublocations', function() {
+ loadStockLocationTable($('#sublocation-table'), {
+ params: {
+ {% if location %}
+ parent: {{ location.pk }},
+ {% else %}
+ parent: 'null',
+ {% endif %}
+ },
+ allowTreeView: true,
+ });
});
linkButtonsToSelection(
@@ -325,19 +327,21 @@
});
});
- loadStockTable($("#stock-table"), {
- buttons: [
- '#stock-options',
- ],
- params: {
- {% if location %}
- location: {{ location.pk }},
- {% endif %}
- part_detail: true,
- location_detail: true,
- supplier_part_detail: true,
- },
- url: "{% url 'api-stock-list' %}",
+ onPanelLoad('stock', function() {
+ loadStockTable($("#stock-table"), {
+ buttons: [
+ '#stock-options',
+ ],
+ params: {
+ {% if location %}
+ location: {{ location.pk }},
+ {% endif %}
+ part_detail: true,
+ location_detail: true,
+ supplier_part_detail: true,
+ },
+ url: "{% url 'api-stock-list' %}",
+ });
});
enableSidebar('stocklocation');
diff --git a/InvenTree/templates/js/translated/model_renderers.js b/InvenTree/templates/js/translated/model_renderers.js
index 68ba496309..e3abe1186f 100644
--- a/InvenTree/templates/js/translated/model_renderers.js
+++ b/InvenTree/templates/js/translated/model_renderers.js
@@ -312,7 +312,13 @@ function renderPartCategory(name, data, parameters, options) {
// eslint-disable-next-line no-unused-vars
function renderPartParameterTemplate(name, data, parameters, options) {
- var html = `
${data.name} - [${data.units}]`;
+ var units = '';
+
+ if (data.units) {
+ units = ` [${data.units}]`;
+ }
+
+ var html = `
${data.name}${units}`;
return html;
}
diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js
index 6ea4e9ebb6..9d66fa2ab4 100644
--- a/InvenTree/templates/js/translated/order.js
+++ b/InvenTree/templates/js/translated/order.js
@@ -2048,15 +2048,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
field: 'location',
title: '{% trans "Location" %}',
formatter: function(value, row) {
-
- if (!value) {
- return '{% trans "Location not specified" %}';
- }
-
- var link = `/stock/location/${value}`;
- var text = row.location_detail.description;
-
- return renderLink(text, link);
+ return locationDetail(row.item_detail, true);
}
},
{
diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js
index ca063b3f9b..b0283a1b35 100644
--- a/InvenTree/templates/js/translated/part.js
+++ b/InvenTree/templates/js/translated/part.js
@@ -1068,68 +1068,84 @@ function loadRelatedPartsTable(table, part_id, options={}) {
}
+/* Load parametric table for part parameters
+ */
function loadParametricPartTable(table, options={}) {
- /* Load parametric table for part parameters
- *
- * Args:
- * - table: HTML reference to the table
- * - table_headers: Unique parameters found in category
- * - table_data: Parameters data
- */
- var table_headers = options.headers;
- var table_data = options.data;
+ var columns = [
+ {
+ field: 'name',
+ title: '{% trans "Part" %}',
+ switchable: false,
+ sortable: true,
+ formatter: function(value, row) {
+ var name = row.full_name;
- var columns = [];
+ var display = imageHoverIcon(row.thumbnail) + renderLink(name, `/part/${row.pk}/`);
- for (var header of table_headers) {
- if (header === 'part') {
- columns.push({
- field: header,
- title: '{% trans "Part" %}',
- sortable: true,
- sortName: 'name',
- formatter: function(value, row) {
-
- var name = '';
-
- if (row.IPN) {
- name += row.IPN + ' | ' + row.name;
- } else {
- name += row.name;
- }
-
- return renderLink(name, '/part/' + row.pk + '/');
- }
- });
- } else if (header === 'description') {
- columns.push({
- field: header,
- title: '{% trans "Description" %}',
- sortable: true,
- });
- } else {
- columns.push({
- field: header,
- title: header,
- sortable: true,
- filterControl: 'input',
- });
+ return display;
+ }
}
- }
+ ];
+
+ // Request a list of parameters we are interested in for this category
+ inventreeGet(
+ '{% url "api-part-parameter-template-list" %}',
+ {
+ category: options.category,
+ },
+ {
+ async: false,
+ success: function(response) {
+ for (var template of response) {
+ columns.push({
+ field: `parameter_${template.pk}`,
+ title: template.name,
+ switchable: true,
+ sortable: true,
+ filterControl: 'input',
+ });
+ }
+ }
+ }
+ );
+
+ // TODO: Re-enable filter control for parameter values
$(table).inventreeTable({
- sortName: 'part',
- queryParams: table_headers,
+ url: '{% url "api-part-list" %}',
+ queryParams: {
+ category: options.category,
+ cascade: true,
+ parameters: true,
+ },
groupBy: false,
- name: options.name || 'parametric',
+ name: options.name || 'part-parameters',
formatNoMatches: function() {
return '{% trans "No parts found" %}';
},
columns: columns,
showColumns: true,
- data: table_data,
- filterControl: true,
+ // filterControl: true,
+ sidePagination: 'server',
+ idField: 'pk',
+ uniqueId: 'pk',
+ onLoadSuccess: function() {
+
+ var data = $(table).bootstrapTable('getData');
+
+ for (var idx = 0; idx < data.length; idx++) {
+ var row = data[idx];
+ var pk = row.pk;
+
+ // Make each parameter accessible, based on the "template" columns
+ row.parameters.forEach(function(parameter) {
+ row[`parameter_${parameter.template}`] = parameter.data;
+ });
+
+ $(table).bootstrapTable('updateRow', pk, row);
+ }
+ }
});
}
@@ -2028,6 +2044,22 @@ function loadPartSchedulingChart(canvas_id, part_id) {
}
);
+ // If no scheduling information is available for the part,
+ // remove the chart and display a message instead
+ if (stock_schedule.length <= 1) {
+
+ var message = `
+
+ {% trans "No scheduling information available for this part" %}.
+
`;
+
+ var canvas_element = $('#part-schedule-chart');
+
+ canvas_element.closest('div').html(message);
+
+ return;
+ }
+
// Iterate through future "events" to calculate expected quantity
var quantity = part_info.in_stock;
diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js
index 421a784281..b7f4162621 100644
--- a/InvenTree/templates/js/translated/stock.js
+++ b/InvenTree/templates/js/translated/stock.js
@@ -46,7 +46,6 @@
findStockItemBySerialNumber,
installStockItem,
loadInstalledInTable,
- loadStockAllocationTable,
loadStockLocationTable,
loadStockTable,
loadStockTestResultsTable,
@@ -2302,157 +2301,6 @@ function loadStockTable(table, options) {
}
-/*
- * Display a table of allocated stock, for either a part or stock item
- * Allocations are displayed for:
- *
- * a) Sales Orders
- * b) Build Orders
- */
-function loadStockAllocationTable(table, options={}) {
-
- var params = options.params || {};
-
- params.build_detail = true;
-
- var filterListElement = options.filterList || '#filter-list-allocations';
-
- var filters = {};
-
- var filterKey = options.filterKey || options.name || 'allocations';
-
- var original = {};
-
- for (var k in params) {
- original[k] = params[k];
- filters[k] = params[k];
- }
-
- setupFilterList(filterKey, table, filterListElement);
-
- /*
- * We have two separate API queries to make here:
- * a) Build Order Allocations
- * b) Sales Order Allocations
- *
- * We will let the call to inventreeTable take care of build orders,
- * and then load sales orders after that.
- */
- table.inventreeTable({
- url: '{% url "api-build-item-list" %}',
- name: 'allocations',
- original: original,
- method: 'get',
- queryParams: filters,
- sidePagination: 'client',
- showColumns: false,
- onLoadSuccess: function(tableData) {
-
- var query_params = params;
-
- query_params.customer_detail = true;
- query_params.order_detail = true;
-
- delete query_params.build_detail;
-
- // Load sales order allocation data
- inventreeGet('{% url "api-so-allocation-list" %}', query_params, {
- success: function(data) {
- // Update table to include sales order data
- $(table).bootstrapTable('append', data);
- }
- });
- },
- columns: [
- {
- field: 'order',
- title: '{% trans "Order" %}',
- formatter: function(value, row) {
-
- var html = '';
-
- if (row.build) {
-
- // Add an icon for the part being built
- html += thumbnailImage(row.build_detail.part_detail.thumbnail, {
- title: row.build_detail.part_detail.full_name
- });
-
- html += ' ';
-
- html += renderLink(
- global_settings.BUILDORDER_REFERENCE_PREFIX + row.build_detail.reference,
- `/build/${row.build}/`
- );
-
- html += makeIconBadge('fa-tools', '{% trans "Build Order" %}');
- } else if (row.order) {
-
- // Add an icon for the customer
- html += thumbnailImage(row.customer_detail.thumbnail || row.customer_detail.image, {
- title: row.customer_detail.name,
- });
-
- html += ' ';
-
- html += renderLink(
- global_settings.SALESORDER_REFERENCE_PREFIX + row.order_detail.reference,
- `/order/sales-order/${row.order}/`
- );
- html += makeIconBadge('fa-truck', '{% trans "Sales Order" %}');
- } else {
- return '-';
- }
-
- return html;
- }
- },
- {
- field: 'description',
- title: '{% trans "Description" %}',
- formatter: function(value, row) {
- if (row.order_detail) {
- return row.order_detail.description;
- } else if (row.build_detail) {
- return row.build_detail.title;
- } else {
- return '-';
- }
- }
- },
- {
- field: 'status',
- title: '{% trans "Order Status" %}',
- formatter: function(value, row) {
- if (row.build) {
- return buildStatusDisplay(row.build_detail.status);
- } else if (row.order) {
- return salesOrderStatusDisplay(row.order_detail.status);
- } else {
- return '-';
- }
- }
- },
- {
- field: 'quantity',
- title: '{% trans "Allocated Quantity" %}',
- formatter: function(value, row) {
- var text = value;
- var pk = row.stock_item || row.item;
-
- if (pk) {
- var url = `/stock/item/${pk}/`;
- return renderLink(text, url);
- } else {
- return value;
- }
- }
- },
- ]
- });
-}
-
-
/*
* Display a table of stock locations
*/
diff --git a/InvenTree/templates/js/translated/table_filters.js b/InvenTree/templates/js/translated/table_filters.js
index a4c6a0bbac..81d43d2c3f 100644
--- a/InvenTree/templates/js/translated/table_filters.js
+++ b/InvenTree/templates/js/translated/table_filters.js
@@ -341,6 +341,15 @@ function getAvailableTableFilters(tableKey) {
};
}
+ if (tableKey == 'salesorderallocation') {
+ return {
+ outstanding: {
+ type: 'bool',
+ title: '{% trans "Outstanding" %}',
+ }
+ };
+ }
+
if (tableKey == 'salesorder') {
return {
status: {