Merge remote-tracking branch 'inventree/master' into receive-via-api

This commit is contained in:
Oliver 2021-08-24 15:07:55 +10:00
commit 86e3e26196
11 changed files with 293 additions and 244 deletions

View File

@ -105,7 +105,7 @@
{% if roles.purchase_order.add %} {% if roles.purchase_order.add %}
<div id='po-button-bar'> <div id='po-button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-primary' type='button' id='company-order2' title='{% trans "Create new purchase order" %}'> <button class='btn btn-success' type='button' id='company-order2' title='{% trans "Create new purchase order" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %}</button> <span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %}</button>
<div class='filter-list' id='filter-list-purchaseorder'> <div class='filter-list' id='filter-list-purchaseorder'>
<!-- Empty div --> <!-- Empty div -->
@ -127,7 +127,7 @@
{% if roles.sales_order.add %} {% if roles.sales_order.add %}
<div id='so-button-bar'> <div id='so-button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-primary' type='button' id='new-sales-order' title='{% trans "Create new sales order" %}'> <button class='btn btn-success' type='button' id='new-sales-order' title='{% trans "Create new sales order" %}'>
<div class='fas fa-plus-circle'></div> {% trans "New Sales Order" %} <div class='fas fa-plus-circle'></div> {% trans "New Sales Order" %}
</button> </button>
<div class='filter-list' id='filter-list-salesorder'> <div class='filter-list' id='filter-list-salesorder'>

View File

@ -160,7 +160,7 @@ src="{% static 'img/blank_image.png' %}"
<div class='panel-content'> <div class='panel-content'>
{% if roles.purchase_order.add %} {% if roles.purchase_order.add %}
<div id='price-break-toolbar' class='btn-group'> <div id='price-break-toolbar' class='btn-group'>
<button class='btn btn-primary' id='new-price-break' type='button'> <button class='btn btn-success' id='new-price-break' type='button'>
<span class='fas fa-plus-circle'></span> {% trans "Add Price Break" %} <span class='fas fa-plus-circle'></span> {% trans "Add Price Break" %}
</button> </button>
</div> </div>

View File

@ -19,7 +19,7 @@
<div class='panel-content'> <div class='panel-content'>
<div id='order-toolbar-buttons' class='btn-group' style='float: right;'> <div id='order-toolbar-buttons' class='btn-group' style='float: right;'>
{% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %} {% if order.status == PurchaseOrderStatus.PENDING and roles.purchase_order.change %}
<button type='button' class='btn btn-primary' id='new-po-line'> <button type='button' class='btn btn-success' id='new-po-line'>
<span class='fas fa-plus-circle'></span> {% trans "Add Line Item" %} <span class='fas fa-plus-circle'></span> {% trans "Add Line Item" %}
</button> </button>
<a class='btn btn-primary' href='{% url "po-upload" order.id %}' role='button'> <a class='btn btn-primary' href='{% url "po-upload" order.id %}' role='button'>

View File

@ -17,7 +17,7 @@
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<div class='btn-group'> <div class='btn-group'>
{% if roles.purchase_order.add %} {% if roles.purchase_order.add %}
<button class='btn btn-primary' type='button' id='po-create' title='{% trans "Create new purchase order" %}'> <button class='btn btn-success' type='button' id='po-create' title='{% trans "Create new purchase order" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %} <span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %}
</button> </button>
{% endif %} {% endif %}

View File

@ -17,7 +17,7 @@
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
<div class='btn-group'> <div class='btn-group'>
{% if roles.sales_order.add %} {% if roles.sales_order.add %}
<button class='btn btn-primary' type='button' id='so-create' title='{% trans "Create new sales order" %}'> <button class='btn btn-success' type='button' id='so-create' title='{% trans "Create new sales order" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Sales Order" %} <span class='fas fa-plus-circle'></span> {% trans "New Sales Order" %}
</button> </button>
{% endif %} {% endif %}

View File

@ -74,7 +74,7 @@
<div id='so-button-bar'> <div id='so-button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'> <div class='button-toolbar container-fluid' style='float: right;'>
{% if 0 %} {% if 0 %}
<button class='btn btn-primary' type='button' id='part-order2' title='{% trans "New sales order" %}'>{% trans "New Order" %}</button> <button class='btn btn-success' type='button' id='part-order2' title='{% trans "New sales order" %}'>{% trans "New Order" %}</button>
{% endif %} {% endif %}
<div class='filter-list' id='filter-list-salesorder'> <div class='filter-list' id='filter-list-salesorder'>
<!-- An empty div in which the filter list will be constructed --> <!-- An empty div in which the filter list will be constructed -->
@ -185,7 +185,7 @@
<div id='related-button-bar'> <div id='related-button-bar'>
<div class='button-toolbar container-fluid' style='float: left;'> <div class='button-toolbar container-fluid' style='float: left;'>
{% if roles.part.change %} {% if roles.part.change %}
<button class='btn btn-primary' type='button' id='add-related-part' title='{% trans "Add Related" %}'>{% trans "Add Related" %}</button> <button class='btn btn-success' type='button' id='add-related-part' title='{% trans "Add Related" %}'>{% trans "Add Related" %}</button>
<div class='filter-list' id='filter-list-related'> <div class='filter-list' id='filter-list-related'>
<!-- An empty div in which the filter list will be constructed --> <!-- An empty div in which the filter list will be constructed -->
</div> </div>

View File

@ -87,7 +87,7 @@
</li> </li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if roles.sales_order.view and enable_sell and enable_so %} {% if part.salable and roles.sales_order.view and enable_sell and enable_so %}
<li class='list-group-item' title='{% trans "Sales Orders" %}'> <li class='list-group-item' title='{% trans "Sales Orders" %}'>
<a href='#' id='select-sales-orders' class='nav-toggle'> <a href='#' id='select-sales-orders' class='nav-toggle'>
<span class='menu-tab-icon fas fa-truck sidebar-icon'></span> <span class='menu-tab-icon fas fa-truck sidebar-icon'></span>

View File

@ -211,7 +211,7 @@
</div> </div>
<div class="col col-md-4"> <div class="col col-md-4">
<div id='internal-price-break-toolbar' class='btn-group'> <div id='internal-price-break-toolbar' class='btn-group'>
<button class='btn btn-primary' id='new-internal-price-break' type='button'> <button class='btn btn-success' id='new-internal-price-break' type='button'>
<span class='fas fa-plus-circle'></span> {% trans "Add Internal Price Break" %} <span class='fas fa-plus-circle'></span> {% trans "Add Internal Price Break" %}
</button> </button>
</div> </div>
@ -267,7 +267,7 @@
</div> </div>
<div class="col col-md-4"> <div class="col col-md-4">
<div id='price-break-toolbar' class='btn-group'> <div id='price-break-toolbar' class='btn-group'>
<button class='btn btn-primary' id='new-price-break' type='button'> <button class='btn btn-success' id='new-price-break' type='button'>
<span class='fas fa-plus-circle'></span> {% trans "Add Price Break" %} <span class='fas fa-plus-circle'></span> {% trans "Add Price Break" %}
</button> </button>
</div> </div>

View File

@ -111,9 +111,17 @@ function inventreeDocReady() {
}, },
create: function () { create: function () {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) { $(this).data('ui-autocomplete')._renderItem = function (ul, item) {
return $('<li>')
.append('<span>' + imageHoverIcon(item.thumbnail) + item.label + '</span>') var html = `<a href='/part/${item.id}/'><span>`;
.appendTo(ul);
html += `<img class='hover-img-thumb' src='`;
html += item.thumbnail || `/static/img/blank_image.png`;
html += `'> `;
html += item.label;
html += '</span></a>';
return $('<li>').append(html).appendTo(ul);
}; };
}, },
select: function( event, ui ) { select: function( event, ui ) {

View File

@ -74,34 +74,34 @@ function partFields(options={}) {
icon: 'fa-boxes', icon: 'fa-boxes',
}, },
component: { component: {
value: global_settings.PART_COMPONENT, default: global_settings.PART_COMPONENT,
group: 'attributes', group: 'attributes',
}, },
assembly: { assembly: {
value: global_settings.PART_ASSEMBLY, default: global_settings.PART_ASSEMBLY,
group: 'attributes', group: 'attributes',
}, },
is_template: { is_template: {
value: global_settings.PART_TEMPLATE, default: global_settings.PART_TEMPLATE,
group: 'attributes', group: 'attributes',
}, },
trackable: { trackable: {
value: global_settings.PART_TRACKABLE, default: global_settings.PART_TRACKABLE,
group: 'attributes', group: 'attributes',
}, },
purchaseable: { purchaseable: {
value: global_settings.PART_PURCHASEABLE, default: global_settings.PART_PURCHASEABLE,
group: 'attributes', group: 'attributes',
onEdit: function(value, name, field, options) { onEdit: function(value, name, field, options) {
setFormGroupVisibility('supplier', value, options); setFormGroupVisibility('supplier', value, options);
} }
}, },
salable: { salable: {
value: global_settings.PART_SALABLE, default: global_settings.PART_SALABLE,
group: 'attributes', group: 'attributes',
}, },
virtual: { virtual: {
value: global_settings.PART_VIRTUAL, default: global_settings.PART_VIRTUAL,
group: 'attributes', group: 'attributes',
}, },
}; };

View File

@ -706,6 +706,264 @@ function loadStockTable(table, options) {
// Ref: https://github.com/wenzhixin/bootstrap-table/issues/3250 // Ref: https://github.com/wenzhixin/bootstrap-table/issues/3250
grouping = false; grouping = false;
var columns = [
{
checkbox: true,
title: '{% trans "Select" %}',
searchable: false,
switchable: false,
},
{
field: 'pk',
title: 'ID',
visible: false,
switchable: false,
}
];
col = {
field: 'part_detail.full_name',
title: '{% trans "Part" %}',
sortName: 'part__name',
visible: params['part_detail'],
switchable: params['part_detail'],
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);
html += makePartIcons(row.part_detail);
return html;
}
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'part_detail.IPN',
title: 'IPN',
sortName: 'part__IPN',
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
return row.part_detail.IPN;
},
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
columns.push({
field: 'part_detail.description',
title: '{% trans "Description" %}',
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
return row.part_detail.description;
}
});
col = {
field: 'quantity',
title: '{% trans "Stock" %}',
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}/`);
if (row.is_building) {
html += makeIconBadge('fa-tools', '{% trans "Stock item is in production" %}');
}
if (row.sales_order) {
// Stock item has been assigned to a sales order
html += makeIconBadge('fa-truck', '{% trans "Stock item assigned to sales order" %}');
} else if (row.customer) {
// StockItem has been assigned to a customer
html += makeIconBadge('fa-user', '{% trans "Stock item assigned to customer" %}');
}
if (row.expired) {
html += makeIconBadge('fa-calendar-times icon-red', '{% trans "Stock item has expired" %}');
} else if (row.stale) {
html += makeIconBadge('fa-stopwatch', '{% trans "Stock item will expire soon" %}');
}
if (row.allocated) {
html += makeIconBadge('fa-bookmark', '{% trans "Stock item has been allocated" %}');
}
if (row.belongs_to) {
html += makeIconBadge('fa-box', '{% trans "Stock item has been installed in another item" %}');
}
// Special stock status codes
// REJECTED
if (row.status == {{ StockStatus.REJECTED }}) {
html += makeIconBadge('fa-times-circle icon-red', '{% trans "Stock item has been rejected" %}');
}
// LOST
else if (row.status == {{ StockStatus.LOST }}) {
html += makeIconBadge('fa-question-circle','{% trans "Stock item is lost" %}');
}
else if (row.status == {{ StockStatus.DESTROYED }}) {
html += makeIconBadge('fa-skull-crossbones', '{% trans "Stock item is destroyed" %}');
}
if (row.quantity <= 0) {
html += `<span class='label label-right label-danger'>{% trans "Depleted" %}</span>`;
}
return html;
}
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'status',
title: '{% trans "Status" %}',
formatter: function(value, row, index, field) {
return stockStatusDisplay(value);
},
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'batch',
title: '{% trans "Batch" %}',
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'location_detail.pathstring',
title: '{% trans "Location" %}',
formatter: function(value, row, index, field) {
return locationDetail(row);
}
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'stocktake_date',
title: '{% trans "Stocktake" %}',
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'expiry_date',
title: '{% trans "Expiry Date" %}',
visible: global_settings.STOCK_ENABLE_EXPIRY,
switchable: global_settings.STOCK_ENABLE_EXPIRY,
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
col = {
field: 'updated',
title: '{% trans "Last Updated" %}',
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
columns.push({
field: 'purchase_order',
title: '{% trans "Purchase Order" %}',
formatter: function(value, row) {
if (!value) {
return '-';
}
var link = `/order/purchase-order/${row.purchase_order}/`;
var text = `${row.purchase_order}`;
if (row.purchase_order_reference) {
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
text = prefix + row.purchase_order_reference;
}
return renderLink(text, link);
}
},
{
field: 'supplier_part',
title: '{% trans "Supplier Part" %}',
visible: params['supplier_part_detail'] || false,
switchable: params['supplier_part_detail'] || false,
formatter: function(value, row) {
if (!value) {
return '-';
}
var link = `/supplier-part/${row.supplier_part}/?display=stock`;
var text = '';
if (row.supplier_part_detail) {
text = `${row.supplier_part_detail.SKU}`;
} else {
text = `<i>{% trans "Supplier part not specified" %}</i>`;
}
return renderLink(text, link);
}
});
col = {
field: 'purchase_price_string',
title: '{% trans "Purchase Price" %}',
};
if (!options.params.ordering) {
col['sortable'] = true;
};
columns.push(col);
columns.push({
field: 'packaging',
title: '{% trans "Packaging" %}',
},
{
field: 'notes',
title: '{% trans "Notes" %}',
});
table.inventreeTable({ table.inventreeTable({
method: 'get', method: 'get',
formatNoMatches: function() { formatNoMatches: function() {
@ -717,6 +975,7 @@ function loadStockTable(table, options) {
name: 'stock', name: 'stock',
original: original, original: original,
showColumns: true, showColumns: true,
columns: columns,
{% if False %} {% if False %}
groupByField: options.groupByField || 'part', groupByField: options.groupByField || 'part',
groupBy: grouping, groupBy: grouping,
@ -734,8 +993,7 @@ function loadStockTable(table, options) {
html += makePartIcons(row.part_detail); html += makePartIcons(row.part_detail);
return html; return html;
} } else if (field == 'part_detail.IPN') {
else if (field == 'part_detail.IPN') {
var ipn = row.part_detail.IPN; var ipn = row.part_detail.IPN;
if (ipn) { if (ipn) {
@ -743,11 +1001,9 @@ function loadStockTable(table, options) {
} else { } else {
return '-'; return '-';
} }
} } else if (field == 'part_detail.description') {
else if (field == 'part_detail.description') {
return row.part_detail.description; return row.part_detail.description;
} } else if (field == 'packaging') {
else if (field == 'packaging') {
var packaging = []; var packaging = [];
data.forEach(function(item) { data.forEach(function(item) {
@ -769,8 +1025,7 @@ function loadStockTable(table, options) {
} else { } else {
return "-"; return "-";
} }
} } else if (field == 'quantity') {
else if (field == 'quantity') {
var stock = 0; var stock = 0;
var items = 0; var items = 0;
@ -874,225 +1129,11 @@ function loadStockTable(table, options) {
} else { } else {
return '-'; return '-';
} }
} } else {
else {
return ''; return '';
} }
}, },
{% endif %} {% endif %}
columns: [
{
checkbox: true,
title: '{% trans "Select" %}',
searchable: false,
switchable: false,
},
{
field: 'pk',
title: 'ID',
visible: false,
switchable: false,
},
{
field: 'part_detail.full_name',
title: '{% trans "Part" %}',
sortName: 'part__name',
sortable: true,
visible: params['part_detail'],
switchable: params['part_detail'],
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);
html += makePartIcons(row.part_detail);
return html;
}
},
{
field: 'part_detail.IPN',
title: 'IPN',
sortName: 'part__IPN',
sortable: true,
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
return row.part_detail.IPN;
},
},
{
field: 'part_detail.description',
title: '{% trans "Description" %}',
visible: params['part_detail'],
switchable: params['part_detail'],
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}/`);
if (row.is_building) {
html += makeIconBadge('fa-tools', '{% trans "Stock item is in production" %}');
}
if (row.sales_order) {
// Stock item has been assigned to a sales order
html += makeIconBadge('fa-truck', '{% trans "Stock item assigned to sales order" %}');
} else if (row.customer) {
// StockItem has been assigned to a customer
html += makeIconBadge('fa-user', '{% trans "Stock item assigned to customer" %}');
}
if (row.expired) {
html += makeIconBadge('fa-calendar-times icon-red', '{% trans "Stock item has expired" %}');
} else if (row.stale) {
html += makeIconBadge('fa-stopwatch', '{% trans "Stock item will expire soon" %}');
}
if (row.allocated) {
html += makeIconBadge('fa-bookmark', '{% trans "Stock item has been allocated" %}');
}
if (row.belongs_to) {
html += makeIconBadge('fa-box', '{% trans "Stock item has been installed in another item" %}');
}
// Special stock status codes
// REJECTED
if (row.status == {{ StockStatus.REJECTED }}) {
html += makeIconBadge('fa-times-circle icon-red', '{% trans "Stock item has been rejected" %}');
}
// LOST
else if (row.status == {{ StockStatus.LOST }}) {
html += makeIconBadge('fa-question-circle','{% trans "Stock item is lost" %}');
}
else if (row.status == {{ StockStatus.DESTROYED }}) {
html += makeIconBadge('fa-skull-crossbones', '{% trans "Stock item is destroyed" %}');
}
if (row.quantity <= 0) {
html += `<span class='label label-right label-danger'>{% trans "Depleted" %}</span>`;
}
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: 'location_detail.pathstring',
title: '{% trans "Location" %}',
sortable: true,
formatter: function(value, row, index, field) {
return locationDetail(row);
}
},
{
field: 'stocktake_date',
title: '{% trans "Stocktake" %}',
sortable: true,
},
{
field: 'expiry_date',
title: '{% trans "Expiry Date" %}',
sortable: true,
visible: global_settings.STOCK_ENABLE_EXPIRY,
switchable: global_settings.STOCK_ENABLE_EXPIRY,
},
{
field: 'updated',
title: '{% trans "Last Updated" %}',
sortable: true,
},
{
field: 'purchase_order',
title: '{% trans "Purchase Order" %}',
formatter: function(value, row) {
if (!value) {
return '-';
}
var link = `/order/purchase-order/${row.purchase_order}/`;
var text = `${row.purchase_order}`;
if (row.purchase_order_reference) {
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
text = prefix + row.purchase_order_reference;
}
return renderLink(text, link);
}
},
{
field: 'supplier_part',
title: '{% trans "Supplier Part" %}',
visible: params['supplier_part_detail'] || false,
switchable: params['supplier_part_detail'] || false,
formatter: function(value, row) {
if (!value) {
return '-';
}
var link = `/supplier-part/${row.supplier_part}/?display=stock`;
var text = '';
if (row.supplier_part_detail) {
text = `${row.supplier_part_detail.SKU}`;
} else {
text = `<i>{% trans "Supplier part not specified" %}</i>`;
}
return renderLink(text, link);
}
},
{
field: 'purchase_price_string',
title: '{% trans "Purchase Price" %}',
sortable: true,
},
{
field: 'packaging',
title: '{% trans "Packaging" %}',
},
{
field: 'notes',
title: '{% trans "Notes" %}',
}
],
}); });
/* /*