mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-03 22:08:49 +00:00
331 lines
8.8 KiB
JavaScript
331 lines
8.8 KiB
JavaScript
/* Stock API functions
|
|
* Requires api.js to be loaded first
|
|
*/
|
|
|
|
function getStockList(filters={}, options={}) {
|
|
return inventreeGet('/api/stock/', filters, options);
|
|
}
|
|
|
|
function getStockDetail(pk, options={}) {
|
|
return inventreeGet('/api/stock/' + pk + '/', {}, options)
|
|
}
|
|
|
|
function getStockLocations(filters={}, options={}) {
|
|
return inventreeGet('/api/stock/location/', filters, options)
|
|
}
|
|
|
|
/* Functions for interacting with stock management forms
|
|
*/
|
|
|
|
function removeStockRow(e) {
|
|
// Remove a selected row from a stock modal form
|
|
|
|
e = e || window.event;
|
|
var src = e.target || e.srcElement;
|
|
|
|
var row = $(src).attr('row');
|
|
|
|
$('#' + row).remove();
|
|
}
|
|
|
|
function loadStockTable(table, options) {
|
|
/* Load data into a stock table with adjustable options.
|
|
* Fetches data (via AJAX) and loads into a bootstrap table.
|
|
* Also links in default button callbacks.
|
|
*
|
|
* Options:
|
|
* url - URL for the stock query
|
|
* params - query params for augmenting stock data request
|
|
* groupByField - Column for grouping stock items
|
|
* buttons - Which buttons to link to stock selection callbacks
|
|
*/
|
|
|
|
var params = options.params || {};
|
|
|
|
table.bootstrapTable({
|
|
sortable: true,
|
|
search: true,
|
|
method: 'get',
|
|
pagination: true,
|
|
pageSize: 25,
|
|
rememberOrder: true,
|
|
formatNoMatches: function() {
|
|
return 'No stock items matching query';
|
|
},
|
|
customSort: customGroupSorter,
|
|
groupBy: true,
|
|
groupByField: options.groupByField || 'part',
|
|
groupByFormatter: function(field, id, data) {
|
|
|
|
var row = data[0];
|
|
|
|
if (field == 'part__name') {
|
|
|
|
var name = row.part__IPN;
|
|
|
|
if (name) {
|
|
name += ' | ';
|
|
}
|
|
|
|
name += row.part__name;
|
|
|
|
return imageHoverIcon(row.part__image) + name + ' <i>(' + data.length + ' items)</i>';
|
|
}
|
|
else if (field == 'part__description') {
|
|
return row.part__description;
|
|
}
|
|
else if (field == 'quantity') {
|
|
var stock = 0;
|
|
|
|
data.forEach(function(item) {
|
|
stock += item.quantity;
|
|
});
|
|
|
|
return stock;
|
|
} else if (field == 'location__path') {
|
|
/* Determine how many locations */
|
|
var locations = [];
|
|
|
|
data.forEach(function(item) {
|
|
var loc = item.location;
|
|
|
|
if (!locations.includes(loc)) {
|
|
locations.push(loc);
|
|
}
|
|
});
|
|
|
|
if (locations.length > 1) {
|
|
return "In " + locations.length + " locations";
|
|
} else {
|
|
// A single location!
|
|
return renderLink(row.location__path, '/stock/location/' + row.location + '/')
|
|
}
|
|
}
|
|
else {
|
|
return '';
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
checkbox: true,
|
|
title: 'Select',
|
|
searchable: false,
|
|
},
|
|
{
|
|
field: 'pk',
|
|
title: 'ID',
|
|
visible: false,
|
|
},
|
|
{
|
|
field: 'part__name',
|
|
title: 'Part',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
|
|
var name = row.part__IPN;
|
|
|
|
if (name) {
|
|
name += ' | ';
|
|
}
|
|
|
|
name += row.part__name;
|
|
|
|
return imageHoverIcon(row.part__image) + renderLink(name, '/part/' + row.part + '/stock/');
|
|
}
|
|
},
|
|
{
|
|
field: 'part__description',
|
|
title: 'Description',
|
|
sortable: true,
|
|
},
|
|
{
|
|
field: 'quantity',
|
|
title: 'Stock',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
|
|
var val = value;
|
|
|
|
// If there is a single unit with a serial number, use the serial number
|
|
if (row.serial && row.quantity == 1) {
|
|
val = '# ' + row.serial;
|
|
}
|
|
|
|
var text = renderLink(val, '/stock/item/' + row.pk + '/');
|
|
|
|
if (row.status_text != 'OK') {
|
|
text = text + "<span class='badge'>" + row.status_text + "</span>";
|
|
}
|
|
|
|
return text;
|
|
}
|
|
},
|
|
{
|
|
field: 'location__path',
|
|
title: 'Location',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
if (value) {
|
|
return renderLink(value, '/stock/location/' + row.location + '/');
|
|
}
|
|
else {
|
|
return '<i>No stock location set</i>';
|
|
}
|
|
}
|
|
},
|
|
{
|
|
field: 'notes',
|
|
title: 'Notes',
|
|
}
|
|
],
|
|
url: options.url,
|
|
queryParams: params,
|
|
});
|
|
|
|
if (options.buttons) {
|
|
linkButtonsToSelection(table, options.buttons);
|
|
}
|
|
|
|
function stockAdjustment(action) {
|
|
var items = $("#stock-table").bootstrapTable("getSelections");
|
|
|
|
var stock = [];
|
|
|
|
items.forEach(function(item) {
|
|
stock.push(item.pk);
|
|
});
|
|
|
|
// Buttons for launching secondary modals
|
|
var secondary = [];
|
|
|
|
if (action == 'move') {
|
|
secondary.push({
|
|
field: 'destination',
|
|
label: 'New Location',
|
|
title: 'Create new location',
|
|
url: "/stock/location/new/",
|
|
});
|
|
}
|
|
|
|
launchModalForm("/stock/adjust/",
|
|
{
|
|
data: {
|
|
action: action,
|
|
stock: stock,
|
|
},
|
|
success: function() {
|
|
$("#stock-table").bootstrapTable('refresh');
|
|
},
|
|
secondary: secondary,
|
|
}
|
|
);
|
|
}
|
|
|
|
// Automatically link button callbacks
|
|
$('#multi-item-stocktake').click(function() {
|
|
stockAdjustment('count');
|
|
});
|
|
|
|
$('#multi-item-remove').click(function() {
|
|
stockAdjustment('take');
|
|
});
|
|
|
|
$('#multi-item-add').click(function() {
|
|
stockAdjustment('add');
|
|
});
|
|
|
|
$("#multi-item-move").click(function() {
|
|
stockAdjustment('move');
|
|
});
|
|
}
|
|
|
|
|
|
function loadStockTrackingTable(table, options) {
|
|
|
|
var cols = [
|
|
{
|
|
field: 'pk',
|
|
visible: false,
|
|
},
|
|
{
|
|
field: 'date',
|
|
title: 'Date',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
var m = moment(value);
|
|
if (m.isValid()) {
|
|
var html = m.format('dddd MMMM Do YYYY') + '<br>' + m.format('h:mm a');
|
|
return html;
|
|
}
|
|
|
|
return 'N/A';
|
|
}
|
|
},
|
|
];
|
|
|
|
// If enabled, provide a link to the referenced StockItem
|
|
if (options.partColumn) {
|
|
cols.push({
|
|
field: 'item',
|
|
title: 'Stock Item',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
return renderLink(value.part_name, value.url);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Stock transaction description
|
|
cols.push({
|
|
field: 'title',
|
|
title: 'Description',
|
|
sortable: true,
|
|
formatter: function(value, row, index, field) {
|
|
var html = "<b>" + value + "</b>";
|
|
|
|
if (row.notes) {
|
|
html += "<br><i>" + row.notes + "</i>";
|
|
}
|
|
|
|
return html;
|
|
}
|
|
});
|
|
|
|
cols.push({
|
|
field: 'quantity',
|
|
title: 'Quantity',
|
|
});
|
|
|
|
cols.push({
|
|
sortable: true,
|
|
field: 'user',
|
|
title: 'User',
|
|
formatter: function(value, row, index, field) {
|
|
if (value)
|
|
{
|
|
// TODO - Format the user's first and last names
|
|
return value.username;
|
|
}
|
|
else
|
|
{
|
|
return "No user information";
|
|
}
|
|
}
|
|
});
|
|
|
|
table.bootstrapTable({
|
|
sortable: true,
|
|
search: true,
|
|
method: 'get',
|
|
rememberOrder: true,
|
|
queryParams: options.params,
|
|
columns: cols,
|
|
pagination: true,
|
|
pageSize: 50,
|
|
url: options.url,
|
|
});
|
|
|
|
if (options.buttons) {
|
|
linkButtonsToSelection(table, options.buttons);
|
|
}
|
|
} |