mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 20:16:44 +00:00
Update progress bars for build output allocation
This commit is contained in:
parent
df9a33935d
commit
6c6ebe70c2
@ -726,6 +726,35 @@ function loadBuildOrderAllocationTable(table, options={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal helper functions for performing calculations on BOM data */
|
||||||
|
|
||||||
|
// Iterate through a list of allocations, returning *only* those which match a particular BOM row
|
||||||
|
function getAllocationsForBomRow(bom_row, allocations) {
|
||||||
|
var part_id = bom_row.sub_part;
|
||||||
|
|
||||||
|
var matching_allocations = [];
|
||||||
|
|
||||||
|
allocations.forEach(function(allocation) {
|
||||||
|
if (allocation.bom_part == part_id) {
|
||||||
|
matching_allocations.push(allocation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return matching_allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum the allocation quantity for a given BOM row
|
||||||
|
function sumAllocationsForBomRow(bom_row, allocations) {
|
||||||
|
var quantity = 0;
|
||||||
|
|
||||||
|
getAllocationsForBomRow(bom_row, allocations).forEach(function(allocation) {
|
||||||
|
quantity += allocation.quantity;
|
||||||
|
});
|
||||||
|
|
||||||
|
return parseFloat(quantity).toFixed(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display a "build output" table for a particular build.
|
* Display a "build output" table for a particular build.
|
||||||
*
|
*
|
||||||
@ -919,6 +948,32 @@ function loadBuildOutputTable(build_info, options={}) {
|
|||||||
rows.forEach(function(row) {
|
rows.forEach(function(row) {
|
||||||
row.allocations = allocations[row.pk] || [];
|
row.allocations = allocations[row.pk] || [];
|
||||||
$(table).bootstrapTable('updateByUniqueId', row.pk, row, true);
|
$(table).bootstrapTable('updateByUniqueId', row.pk, row, true);
|
||||||
|
|
||||||
|
var n_completed_lines = 0;
|
||||||
|
|
||||||
|
// Check how many BOM lines have been completely allocated for this build output
|
||||||
|
bom_items.forEach(function(bom_item) {
|
||||||
|
|
||||||
|
var required_quantity = bom_item.quantity * row.quantity;
|
||||||
|
|
||||||
|
if (sumAllocationsForBomRow(bom_item, row.allocations) >= required_quantity) {
|
||||||
|
n_completed_lines += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var output_progress_bar = $(`#output-progress-${row.pk}`);
|
||||||
|
|
||||||
|
if (output_progress_bar.exists()) {
|
||||||
|
output_progress_bar.html(
|
||||||
|
makeProgressBar(
|
||||||
|
n_completed_lines,
|
||||||
|
bom_items.length,
|
||||||
|
{
|
||||||
|
max_width: '150px',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1092,14 +1147,33 @@ function loadBuildOutputTable(build_info, options={}) {
|
|||||||
visible: true,
|
visible: true,
|
||||||
switchable: false,
|
switchable: false,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
// Display a progress bar which shows how many rows have been allocated
|
|
||||||
var n_bom_lines = 0;
|
// Display a progress bar which shows how many BOM lines have been fully allocated
|
||||||
|
var n_bom_lines = 1;
|
||||||
|
var n_completed_lines = 0;
|
||||||
|
|
||||||
if (bom_items) {
|
// Work out how many lines have been allocated for this build output
|
||||||
|
if (bom_items && row.allocations) {
|
||||||
n_bom_lines = bom_items.length;
|
n_bom_lines = bom_items.length;
|
||||||
|
|
||||||
|
bom_items.forEach(function(bom_row) {
|
||||||
|
var required_quantity = row.quantity * bom_row.quantity;
|
||||||
|
|
||||||
|
if (sumAllocationsForBomRow(bom_row, row.allocations) >= required_quantity) {
|
||||||
|
n_completed_lines += 1;
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return `lines: ${n_bom_lines}`;
|
|
||||||
return `<div id='output-progress-${row.pk}'><span class='fas fa-spin fa-spinner'></span></div>`;
|
var progressBar = makeProgressBar(
|
||||||
|
n_completed_lines,
|
||||||
|
n_bom_lines,
|
||||||
|
{
|
||||||
|
max_width: '150px',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return `<div id='output-progress-${row.pk}'>${progressBar}</div>`;
|
||||||
},
|
},
|
||||||
sorter: function(value_a, value_b, row_a, row_b) {
|
sorter: function(value_a, value_b, row_a, row_b) {
|
||||||
// TODO: Custom sorter for "allocated stock" column
|
// TODO: Custom sorter for "allocated stock" column
|
||||||
@ -1108,7 +1182,7 @@ function loadBuildOutputTable(build_info, options={}) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'tests',
|
field: 'tests',
|
||||||
title: '{% trans "Tests" %}',
|
title: '{% trans "Completed Tests" %}',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
switchable: true,
|
switchable: true,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
@ -1186,6 +1260,26 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
outputId = 'untracked';
|
outputId = 'untracked';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bom_items = buildInfo.bom_items || null;
|
||||||
|
|
||||||
|
// If BOM items have not been provided, load via the API
|
||||||
|
if (bom_items == null) {
|
||||||
|
inventreeGet(
|
||||||
|
'{% url "api-bom-list" %}',
|
||||||
|
{
|
||||||
|
part: partId,
|
||||||
|
sub_part_detail: true,
|
||||||
|
sub_part_trackable: trackable,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
async: false,
|
||||||
|
success: function(results) {
|
||||||
|
bom_items = results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
var table = options.table;
|
var table = options.table;
|
||||||
|
|
||||||
if (options.table == null) {
|
if (options.table == null) {
|
||||||
@ -1209,6 +1303,42 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
|
|
||||||
var allocated_items = output == null ? null : output.allocations;
|
var allocated_items = output == null ? null : output.allocations;
|
||||||
|
|
||||||
|
function redrawAllocationData() {
|
||||||
|
// Force a refresh of each row in the table
|
||||||
|
// Note we cannot call 'refresh' because we are passing data from memory
|
||||||
|
// var rows = $(table).bootstrapTable('getData');
|
||||||
|
|
||||||
|
// How many rows are fully allocated?
|
||||||
|
var allocated_rows = 0;
|
||||||
|
|
||||||
|
bom_items.forEach(function(row) {
|
||||||
|
$(table).bootstrapTable('updateByUniqueId', row.pk, row, true);
|
||||||
|
|
||||||
|
if (isRowFullyAllocated(row)) {
|
||||||
|
allocated_rows += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Find the top-level progess bar for this build output
|
||||||
|
var output_progress_bar = $(`#output-progress-${outputId}`);
|
||||||
|
|
||||||
|
if (output_progress_bar.exists()) {
|
||||||
|
if (bom_items.length > 0) {
|
||||||
|
output_progress_bar.html(
|
||||||
|
makeProgressBar(
|
||||||
|
allocated_rows,
|
||||||
|
bom_items.length,
|
||||||
|
{
|
||||||
|
max_width: '150px',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn(`Could not find progress bar for output '${outputId}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function reloadAllocationData(async=true) {
|
function reloadAllocationData(async=true) {
|
||||||
// Reload stock allocation data for this particular build output
|
// Reload stock allocation data for this particular build output
|
||||||
|
|
||||||
@ -1225,32 +1355,18 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
success: function(response) {
|
success: function(response) {
|
||||||
allocated_items = response;
|
allocated_items = response;
|
||||||
|
|
||||||
if (async) {
|
redrawAllocationData();
|
||||||
|
|
||||||
// Force a refresh of each row in the table
|
|
||||||
// Note we cannot call 'refresh' because we are passing data from memory
|
|
||||||
var rows = $(table).bootstrapTable('getData');
|
|
||||||
|
|
||||||
// How many rows are fully allocated?
|
|
||||||
var allocated_rows = 0;
|
|
||||||
|
|
||||||
rows.forEach(function(row) {
|
|
||||||
$(table).bootstrapTable('updateByUniqueId', row.pk, row, true);
|
|
||||||
|
|
||||||
if (isRowFullyAllocated(row)) {
|
|
||||||
allocated_rows += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocated_items == null) {
|
if (allocated_items == null) {
|
||||||
|
|
||||||
// No allocation data provided? Request from server (blocking)
|
// No allocation data provided? Request from server (blocking)
|
||||||
reloadAllocationData(false);
|
reloadAllocationData(false);
|
||||||
|
} else {
|
||||||
|
redrawAllocationData();
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadTable() {
|
function reloadTable() {
|
||||||
@ -1293,38 +1409,15 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return available;
|
return available;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllocationsForRow(row) {
|
function allocatedQuantity(row) {
|
||||||
var part_id = row.sub_part;
|
row.allocated = sumAllocationsForBomRow(row, allocated_items);
|
||||||
|
|
||||||
var allocations = [];
|
|
||||||
|
|
||||||
allocated_items.forEach(function(allocation) {
|
|
||||||
if (allocation.bom_part == part_id) {
|
|
||||||
allocations.push(allocation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return allocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sumAllocations(row) {
|
|
||||||
|
|
||||||
var allocated_quantity = 0;
|
|
||||||
|
|
||||||
getAllocationsForRow(row).forEach(function(allocation) {
|
|
||||||
allocated_quantity += allocation.quantity;
|
|
||||||
});
|
|
||||||
|
|
||||||
row.allocated = parseFloat(allocated_quantity.toFixed(15));
|
|
||||||
|
|
||||||
return row.allocated;
|
return row.allocated;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRowFullyAllocated(row) {
|
function isRowFullyAllocated(row) {
|
||||||
return sumAllocations(row) >= requiredQuantity(row);
|
return allocatedQuantity(row) >= requiredQuantity(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupCallbacks() {
|
function setupCallbacks() {
|
||||||
@ -1386,7 +1479,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
newBuildOrder({
|
newBuildOrder({
|
||||||
part: pk,
|
part: pk,
|
||||||
parent: buildId,
|
parent: buildId,
|
||||||
quantity: requiredQuantity(row) - sumAllocations(row),
|
quantity: requiredQuantity(row) - allocatedQuantity(row),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1408,26 +1501,6 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var bom_items = buildInfo.bom_items || null;
|
|
||||||
|
|
||||||
// If BOM items have not been provided, load via the API
|
|
||||||
if (bom_items == null) {
|
|
||||||
inventreeGet(
|
|
||||||
'{% url "api-bom-list" %}',
|
|
||||||
{
|
|
||||||
part: partId,
|
|
||||||
sub_part_detail: true,
|
|
||||||
sub_part_trackable: trackable,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
async: false,
|
|
||||||
success: function(results) {
|
|
||||||
bom_items = results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load table of BOM items
|
// Load table of BOM items
|
||||||
$(table).inventreeTable({
|
$(table).inventreeTable({
|
||||||
data: bom_items,
|
data: bom_items,
|
||||||
@ -1446,7 +1519,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
showColumns: false,
|
showColumns: false,
|
||||||
detailView: true,
|
detailView: true,
|
||||||
detailFilter: function(index, row) {
|
detailFilter: function(index, row) {
|
||||||
return sumAllocations(row) > 0;
|
return allocatedQuantity(row) > 0;
|
||||||
},
|
},
|
||||||
detailFormatter: function(index, row, element) {
|
detailFormatter: function(index, row, element) {
|
||||||
// Contruct an 'inner table' which shows which stock items have been allocated
|
// Contruct an 'inner table' which shows which stock items have been allocated
|
||||||
@ -1460,7 +1533,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
var subTable = $(`#${subTableId}`);
|
var subTable = $(`#${subTableId}`);
|
||||||
|
|
||||||
subTable.bootstrapTable({
|
subTable.bootstrapTable({
|
||||||
data: getAllocationsForRow(row),
|
data: getAllocationsForBomRow(row, allocated_items),
|
||||||
showHeader: true,
|
showHeader: true,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
@ -1660,15 +1733,15 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
title: '{% trans "Allocated" %}',
|
title: '{% trans "Allocated" %}',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
var allocated = sumAllocations(row);
|
var allocated = allocatedQuantity(row);
|
||||||
var required = requiredQuantity(row)
|
var required = requiredQuantity(row)
|
||||||
return makeProgressBar(allocated, required);
|
return makeProgressBar(allocated, required);
|
||||||
},
|
},
|
||||||
sorter: function(valA, valB, rowA, rowB) {
|
sorter: function(valA, valB, rowA, rowB) {
|
||||||
// Custom sorting function for progress bars
|
// Custom sorting function for progress bars
|
||||||
|
|
||||||
var aA = sumAllocations(rowA);
|
var aA = allocatedQuantity(rowA);
|
||||||
var aB = sumAllocations(rowB);
|
var aB = allocatedQuantity(rowB);
|
||||||
|
|
||||||
var qA = requiredQuantity(rowA);
|
var qA = requiredQuantity(rowA);
|
||||||
var qB = requiredQuantity(rowB);
|
var qB = requiredQuantity(rowB);
|
||||||
@ -1703,7 +1776,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
// Generate action buttons for this build output
|
// Generate action buttons for this build output
|
||||||
var html = `<div class='btn-group float-right' role='group'>`;
|
var html = `<div class='btn-group float-right' role='group'>`;
|
||||||
|
|
||||||
if (sumAllocations(row) < requiredQuantity(row)) {
|
if (allocatedQuantity(row) < requiredQuantity(row)) {
|
||||||
if (row.sub_part_detail.assembly) {
|
if (row.sub_part_detail.assembly) {
|
||||||
html += makeIconButton('fa-tools icon-blue', 'button-build', row.sub_part, '{% trans "Build stock" %}');
|
html += makeIconButton('fa-tools icon-blue', 'button-build', row.sub_part, '{% trans "Build stock" %}');
|
||||||
}
|
}
|
||||||
@ -1719,7 +1792,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
|
|||||||
'fa-minus-circle icon-red', 'button-unallocate', row.sub_part,
|
'fa-minus-circle icon-red', 'button-unallocate', row.sub_part,
|
||||||
'{% trans "Unallocate stock" %}',
|
'{% trans "Unallocate stock" %}',
|
||||||
{
|
{
|
||||||
disabled: sumAllocations(row) == 0,
|
disabled: allocatedQuantity(row) == 0,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -163,27 +163,29 @@ function makeProgressBar(value, maximum, opts={}) {
|
|||||||
|
|
||||||
var style = options.style || '';
|
var style = options.style || '';
|
||||||
|
|
||||||
var text = '';
|
var text = options.text;
|
||||||
|
|
||||||
|
if (!text) {
|
||||||
|
if (style == 'percent') {
|
||||||
|
// Display e.g. "50%"
|
||||||
|
|
||||||
if (style == 'percent') {
|
text = `${percent}%`;
|
||||||
// Display e.g. "50%"
|
} else if (style == 'max') {
|
||||||
|
// Display just the maximum value
|
||||||
|
text = `${maximum}`;
|
||||||
|
} else if (style == 'value') {
|
||||||
|
// Display just the current value
|
||||||
|
text = `${value}`;
|
||||||
|
} else if (style == 'blank') {
|
||||||
|
// No display!
|
||||||
|
text = '';
|
||||||
|
} else {
|
||||||
|
/* Default style
|
||||||
|
* Display e.g. "5 / 10"
|
||||||
|
*/
|
||||||
|
|
||||||
text = `${percent}%`;
|
text = `${value} / ${maximum}`;
|
||||||
} else if (style == 'max') {
|
}
|
||||||
// Display just the maximum value
|
|
||||||
text = `${maximum}`;
|
|
||||||
} else if (style == 'value') {
|
|
||||||
// Display just the current value
|
|
||||||
text = `${value}`;
|
|
||||||
} else if (style == 'blank') {
|
|
||||||
// No display!
|
|
||||||
text = '';
|
|
||||||
} else {
|
|
||||||
/* Default style
|
|
||||||
* Display e.g. "5 / 10"
|
|
||||||
*/
|
|
||||||
|
|
||||||
text = `${value} / ${maximum}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = options.id || 'progress-bar';
|
var id = options.id || 'progress-bar';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user