Merge pull request #1084 from SchrodingersGat/used-in-table

Used in table
This commit is contained in:
Oliver 2020-10-28 21:21:44 +11:00 committed by GitHub
commit c8ec55a5fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 4511 additions and 4356 deletions

View File

@ -89,14 +89,14 @@ settings_urls = [
# Some javascript files are served 'dynamically', allowing them to pass through the Django translation layer
dynamic_javascript_urls = [
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.html'), name='barcode.js'),
url(r'^part.js', DynamicJsView.as_view(template_name='js/part.html'), name='part.js'),
url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.html'), name='stock.js'),
url(r'^build.js', DynamicJsView.as_view(template_name='js/build.html'), name='build.js'),
url(r'^order.js', DynamicJsView.as_view(template_name='js/order.html'), name='order.js'),
url(r'^company.js', DynamicJsView.as_view(template_name='js/company.html'), name='company.js'),
url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.html'), name='bom.js'),
url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.html'), name='table_filters.js'),
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'),
url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.js'),
url(r'^build.js', DynamicJsView.as_view(template_name='js/build.js'), name='build.js'),
url(r'^company.js', DynamicJsView.as_view(template_name='js/company.js'), name='company.js'),
url(r'^order.js', DynamicJsView.as_view(template_name='js/order.js'), name='order.js'),
url(r'^part.js', DynamicJsView.as_view(template_name='js/part.js'), name='part.js'),
url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'),
url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'),
]
urlpatterns = [

View File

@ -15,7 +15,7 @@
</div>
</div>
<table class='table table-striped table-condensed' id='stock-table'></table>
<table class='table table-striped table-condensed' id='stock-table' data-toolbar='#button-toolbar'></table>
{% endblock %}

View File

@ -10,21 +10,30 @@
<hr>
{% if roles.purchase_order.change %}
<div id='button-toolbar' class='btn-group'>
{% if roles.purchase_order.add %}
<button class="btn btn-success" id='part-create' title='{% trans "Create new supplier part" %}'>{% trans "New Supplier Part" %}</button>
{% endif %}
<div class="dropdown" style="float: right;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %}
<span class="caret"></span></button>
<ul class="dropdown-menu">
<div id='button-toolbar'>
<div class='button-toolbar container-fluid'>
<div class='btn-group role='group'>
{% if roles.purchase_order.add %}
<li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li>
<button class="btn btn-success" id='part-create' title='{% trans "Create new supplier part" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Supplier Part" %}
</button>
{% endif %}
{% if roles.purchase_order.delete %}
<li><a href='#' id='multi-part-delete' title='{% trans "Delete parts" %}'>{% trans "Delete Parts" %}</a></li>
{% endif %}
</ul>
<div class='btn-group'>
<div class="dropdown" style="float: right;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %}
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{% if roles.purchase_order.add %}
<li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li>
{% endif %}
{% if roles.purchase_order.delete %}
<li><a href='#' id='multi-part-delete' title='{% trans "Delete parts" %}'>{% trans "Delete Parts" %}</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
{% endif %}

View File

@ -12,7 +12,8 @@
{% if roles.purchase_order.add %}
<div id='button-bar'>
<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" %}'>{% trans "New Purchase Order" %}</button>
<button class='btn btn-primary' type='button' id='company-order2' title='{% trans "Create new purchase order" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Purchase Order" %}</button>
<div class='filter-list' id='filter-list-purchaseorder'>
<!-- Empty div -->
</div>

View File

@ -12,7 +12,9 @@
{% if roles.sales_order.add %}
<div id='button-bar'>
<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" %}'>{% trans "New Sales Order" %}</button>
<button class='btn btn-primary' type='button' id='new-sales-order' title='{% trans "Create new sales order" %}'>
<div class='fas fa-plus-circle'></div> {% trans "New Sales Order" %}
</button>
<div class='filter-list' id='filter-list-salesorder'>
<!-- Empty div -->
</div>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,8 @@ InvenTree | {% trans "Sales Orders" %}
<div id='table-buttons'>
<div class='button-toolbar container-fluid' style='float: right;'>
{% if roles.sales_order.add %}
<button class='btn btn-primary' type='button' id='so-create' title='{% trans "Create new sales order" %}'>{% trans "New Sales Order" %}</button>
<button class='btn btn-primary' type='button' id='so-create' title='{% trans "Create new sales order" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Sales Order" %}</button>
{% endif %}
<div class='filter-list' id='filter-list-salesorder'>
<!-- An empty div in which the filter list will be constructed -->

View File

@ -761,12 +761,26 @@ class BomList(generics.ListCreateAPIView):
if sub_part is not None:
queryset = queryset.filter(sub_part=sub_part)
# Filter by "trackable" status of the sub-part
trackable = params.get('trackable', None)
# Filter by "active" status of the part
part_active = params.get('part_active', None)
if trackable is not None:
trackable = str2bool(trackable)
queryset = queryset.filter(sub_part__trackable=trackable)
if part_active is not None:
part_active = str2bool(part_active)
queryset = queryset.filter(part__active=part_active)
# Filter by "trackable" status of the part
part_trackable = params.get('part_trackable', None)
if part_trackable is not None:
part_trackable = str2bool(part_trackable)
queryset = queryset.filter(part__trackable=part_trackable)
# Filter by "trackable" status of the sub-part
sub_part_trackable = params.get('sub_part_trackable', None)
if sub_part_trackable is not None:
sub_part_trackable = str2bool(sub_part_trackable)
queryset = queryset.filter(sub_part__trackable=sub_part_trackable)
return queryset

View File

@ -17,15 +17,15 @@
</tr>
{% for allocation in part.build_order_allocations %}
<tr>
<td><a href="{% url 'build-detail' allocation.build.id %}">{% trans "Build Order" %}: {{ allocation.build.pk }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.stock_item.id %}">{% trans "Stock Item" %}: {{ allocation.stock_item.id }}</a></td>
<td><a href="{% url 'build-detail' allocation.build.id %}">{% trans "Build Order" %}: {{ allocation.build }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.stock_item.id %}">{% trans "Stock Item" %}: {{ allocation.stock_item }}</a></td>
<td>{% decimal allocation.quantity %}</td>
</tr>
{% endfor %}
{% for allocation in part.sales_order_allocations %}
<tr>
<td><a href="{% url 'so-detail' allocation.line.order.id %}">{% trans "Sales Order" %}: {{ allocation.line.order.pk }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.item.id %}">{% trans "Stock Item" %}: {{ allocation.item.id }}</a></td>
<td><a href="{% url 'so-detail' allocation.line.order.id %}">{% trans "Sales Order" %}: {{ allocation.line.order }}</a></td>
<td><a href="{% url 'stock-item-detail' allocation.item.id %}">{% trans "Stock Item" %}: {{ allocation.item }}</a></td>
<td>{% decimal allocation.quantity %}</td>
</tr>
{% endfor %}

View File

@ -32,21 +32,40 @@
</div>
{% endif %}
<div id='button-toolbar' class="btn-group" role="group" aria-label="...">
{% if editing_enabled %}
<button class='btn btn-default action-button' type='button' title='{% trans "Remove selected BOM items" %}' id='bom-item-delete'><span class='fas fa-trash-alt'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Import BOM data" %}' id='bom-upload'><span class='fas fa-file-upload'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "New BOM Item" %}' id='bom-item-new'><span class='fas fa-plus-circle'></span></button>
<button class='btn btn-default action-button' type='button' title='{% trans "Finish Editing" %}' id='editing-finished'><span class='fas fa-check-circle'></span></button>
{% elif part.active %}
{% if roles.part.change %}
<button class='btn btn-default action-button' type='button' title='{% trans "Edit BOM" %}' id='edit-bom'><span class='fas fa-edit'></span></button>
{% if part.is_bom_valid == False %}
<button class='btn btn-default action-button' id='validate-bom' title='{% trans "Validate Bill of Materials" %}' type='button'><span class='fas fa-clipboard-check'></span></button>
{% endif %}
{% endif %}
<button title='{% trans "Export Bill of Materials" %}' class='btn btn-default action-button' id='download-bom' type='button'><span class='fas fa-file-download'></span></button>
{% endif %}
<div id='button-toolbar'>
<div class="btn-group" role="group" aria-label="...">
{% if editing_enabled %}
<button class='btn btn-default' type='button' title='{% trans "Remove selected BOM items" %}' id='bom-item-delete'>
<span class='fas fa-trash-alt'></span>
</button>
<button class='btn btn-primary' type='button' title='{% trans "Import BOM data" %}' id='bom-upload'>
<span class='fas fa-file-upload'></span> {% trans "Upload" %}
</button>
<button class='btn btn-default' type='button' title='{% trans "New BOM Item" %}' id='bom-item-new'>
<span class='fas fa-plus-circle'></span> {% trans "Add Item" %}
</button>
<button class='btn btn-success' type='button' title='{% trans "Finish Editing" %}' id='editing-finished'>
<span class='fas fa-check-circle'></span> {% trans "Finished" %}
</button>
{% elif part.active %}
{% if roles.part.change %}
<button class='btn btn-primary' type='button' title='{% trans "Edit BOM" %}' id='edit-bom'>
<span class='fas fa-edit'></span> {% trans "Edit" %}
</button>
{% if part.is_bom_valid == False %}
<button class='btn btn-success' id='validate-bom' title='{% trans "Validate Bill of Materials" %}' type='button'>
<span class='fas fa-clipboard-check'></span> {% trans "Validate" %}
</button>
{% endif %}
{% endif %}
<button title='{% trans "Export Bill of Materials" %}' class='btn btn-default' id='download-bom' type='button'>
<span class='fas fa-file-download'></span> {% trans "Export" %}
</button>
{% endif %}
</div>
<div class='filter-list' id='filter-list-bom'>
<!-- Empty div (will be filled out with avilable BOM filters) -->
</div>
</div>
<table class='table table-striped table-condensed' data-toolbar="#button-toolbar" id='bom-table'>
@ -184,4 +203,4 @@
{% endif %}
{% endblock %}
{% endblock %}

View File

@ -107,22 +107,24 @@
<hr>
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style="float: right;">
<div class='btn-group'>
<button class='btn btn-default' id='part-export' title='{% trans "Export Part Data" %}'>
<span class='fas fa-file-download'></span> {% trans "Export" %}
</button>
{% if roles.part.add %}
<button class='btn btn-success' id='part-create' title='{% trans "Create new part" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Part" %}
</button>
{% endif %}
<div class='btn-group'>
<button class='btn btn-default' id='part-export' title='{% trans "Export Part Data" %}'>{% trans "Export" %}</button>
{% if roles.part.add %}
<button class='btn btn-success' id='part-create' title='{% trans "Create new part" %}'>{% trans "New Part" %}</button>
{% endif %}
<div class='btn-group'>
<button id='part-options' class='btn btn-primary dropdown-toggle' type='button' data-toggle="dropdown">{% trans "Options" %}<span class='caret'></span></button>
<ul class='dropdown-menu'>
{% if roles.part.change %}
<li><a href='#' id='multi-part-category' title='{% trans "Set category" %}'>{% trans "Set Category" %}</a></li>
{% endif %}
<li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li>
<li><a href='#' id='multi-part-export' title='{% trans "Export" %}'>{% trans "Export Data" %}</a></li>
</ul>
</div>
<button id='part-options' class='btn btn-primary dropdown-toggle' type='button' data-toggle="dropdown">{% trans "Options" %}<span class='caret'></span></button>
<ul class='dropdown-menu'>
{% if roles.part.change %}
<li><a href='#' id='multi-part-category' title='{% trans "Set category" %}'>{% trans "Set Category" %}</a></li>
{% endif %}
<li><a href='#' id='multi-part-order' title='{% trans "Order parts" %}'>{% trans "Order Parts" %}</a></li>
<li><a href='#' id='multi-part-export' title='{% trans "Export" %}'>{% trans "Export Data" %}</a></li>
</ul>
</div>
</div>
<div class='filter-list' id='filter-list-parts'>

View File

@ -11,7 +11,9 @@
<div id='button-bar'>
<div class='button-toolbar container-fluid' style='float: right;'>
<button class='btn btn-primary' type='button' id='part-order2' title='{% trans "Order part" %}'>{% trans "Order Part" %}</button>
<button class='btn btn-primary' type='button' id='part-order2' title='{% trans "Order part" %}'>
<span class='fas fa-shopping-cart'></span> {% trans "Order Part" %}
</button>
<div class='filter-list' id='filter-list-purchaseorder'>
<!-- An empty div in which the filter list will be constructed -->
</div>

View File

@ -11,7 +11,9 @@
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style='float: right;'>
{% if roles.part.add %}
<button title='{% trans "Add new parameter" %}' class='btn btn-success' id='param-create'>{% trans "New Parameter" %}</button>
<button title='{% trans "Add new parameter" %}' class='btn btn-success' id='param-create'>
<span class='fas fa-plus-circle'></span> {% trans "New Parameter" %}
</button>
{% endif %}
</div>
</div>

View File

@ -10,7 +10,9 @@
<div id='button-toolbar'>
<div class='btn-group'>
<button class="btn btn-success" id='supplier-create'>{% trans "New Supplier Part" %}</button>
<button class="btn btn-success" id='supplier-create'>
<span class='fas fa-plus-circle'></span> {% trans "New Supplier Part" %}
</button>
<div id='opt-dropdown' class="btn-group">
<button id='supplier-part-options' class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %}<span class="caret"></span></button>
<ul class="dropdown-menu">

View File

@ -8,7 +8,13 @@
<hr>
<table class="table table-striped table-condensed" id='used-table'>
<div id='button-toolbar'>
<div class='filter-list' id='filter-list-usedin'>
<!-- Empty div (will be filled out with avilable BOM filters) -->
</div>
</div>
<table class="table table-striped table-condensed" id='used-table' data-toolbar='#button-toolbar'>
</table>
{% endblock %}
@ -16,52 +22,10 @@
{% block js_ready %}
{{ block.super }}
$("#used-table").inventreeTable({
formatNoMatches: function() { return "{{ part.full_name }} is not used to make any other parts"; },
queryParams: function(p) {
return {
sub_part: {{ part.id }},
part_detail: true,
}
},
columns: [
{
field: 'pk',
title: 'ID',
visible: false,
switchable: false,
},
{
field: 'part_detail',
title: 'Part',
sortable: true,
formatter: function(value, row, index, field) {
var link = `/part/${value.pk}/bom/`;
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(value.full_name, link);
loadUsedInTable('#used-table', {
part_detail: true,
part_id: {{ part.pk }}
});
if (!row.part_detail.active) {
html += "<span class='label label-warning' style='float: right;'>{% trans "INACTIVE" %}</span>";
}
return html;
}
},
{
field: 'part_detail.description',
title: 'Description',
sortable: true,
},
{
sortable: true,
field: 'quantity',
title: 'Uses',
formatter: function(value, row, index, field) {
return parseFloat(value);
},
}
],
url: "{% url 'api-bom-list' %}"
})
{% endblock %}

View File

@ -14,7 +14,9 @@
{% if roles.stock.change %}
<div id='table-toolbar'>
<div class='btn-group'>
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>New Entry</button>
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>
<span class='fas fa-plus-circle'></span> {% trans "New Entry" %}
</button>
</div>
</div>
{% endif %}

View File

@ -14,10 +14,16 @@
<div class='button-toolbar container-fluid' style="float: right;">
<div class='btn-group' role='group'>
{% if user.is_staff %}
<button type='button' class='btn btn-danger' id='delete-test-results'>{% trans "Delete Test Data" %}</button>
<button type='button' class='btn btn-danger' id='delete-test-results'>
<span class='fas fa-trash-alt'></span> {% trans "Delete Test Data" %}
</button>
{% endif %}
<button type='button' class='btn btn-success' id='add-test-result'>{% trans "Add Test Data" %}</button>
<button type='button' class='btn btn-default' id='test-report'>{% trans "Test Report" %} <span class='fas fa-tasks'></span></button>
<button type='button' class='btn btn-success' id='add-test-result'>
<span class='fas fa-plus-circle'></span> {% trans "Add Test Data" %}
</button>
<button type='button' class='btn btn-default' id='test-report'>
<span class='fas fa-tasks'></span> {% trans "Test Report" %}
</button>
</div>
<div class='filter-list' id='filter-list-stocktests'>
<!-- Empty div -->

View File

@ -3,7 +3,9 @@
{% if roles.stock.change %}
<div id='attachment-buttons'>
<div class='btn-group'>
<button type='button' class='btn btn-success' id='new-attachment'>{% trans "Add Attachment" %}</button>
<button type='button' class='btn btn-success' id='new-attachment'>
<span class='fas fa-plus-circle'></span> {% trans "Add Attachment" %}
</button>
</div>
</div>
{% endif %}

View File

@ -427,4 +427,86 @@ function loadBomTable(table, options) {
);
});
}
}
function loadUsedInTable(table, options) {
/* Load a table which displays all the parts that the given part is used in.
*/
var params = {
sub_part: options.part_id,
ordering: 'name',
}
if (options.part_detail) {
params.part_detail = true;
}
if (options.sub_part_detail) {
params.sub_part_detail = true;
}
var filters = {};
if (!options.disableFilters) {
filters = loadTableFilters("usedin");
}
for (var key in params) {
filters[key] = params[key];
}
setupFilterList("usedin", $(table));
// Columns to display in the table
var cols = [
{
field: 'pk',
title: 'ID',
visible: false,
switchable: false,
},
{
field: 'part_detail.full_name',
title: '{% trans "Part" %}',
sortable: true,
formatter: function(value, row, index, field) {
var link = `/part/${row.part}/bom/`;
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(row.part_detail.full_name, link);
if (!row.part_detail.active) {
html += "<span class='label label-warning' style='float: right;'>{% trans 'INACTIVE' %}</span>";
}
return html;
}
},
{
field: 'part_detail.description',
title: '{% trans "Description" %}',
sortable: true,
},
{
sortable: true,
field: 'quantity',
title: '{% trans "Uses" %}',
formatter: function(value, row, index, field) {
return parseFloat(value);
},
}
];
// Load the table
$(table).inventreeTable({
url: "{% url 'api-bom-list' %}",
formatNoMatches: function() {
return '{% trans "No matching parts found" %}';
},
columns: cols,
showColumns: true,
sortable: true,
serach: true,
queryParams: filters,
original: params,
});
}

View File

@ -11,6 +11,30 @@ function getAvailableTableFilters(tableKey) {
tableKey = tableKey.toLowerCase();
// Filters for Bill of Materials table
if (tableKey == "bom") {
return {
sub_part_trackable: {
type: 'bool',
title: '{% trans "Trackable Part" %}'
},
validated: {
type: 'bool',
title: '{% trans "Validated" %}',
},
};
}
// Filters for the "used in" table
if (tableKey == 'usedin') {
return {
'part_active': {
type: 'bool',
title: '{% trans "Active" %}',
},
};
}
// Filters for the "customer stock" table (really a subset of "stock")
if (tableKey == "customerstock") {
return {

View File

@ -3,11 +3,15 @@
<div id='button-toolbar'>
<div class='button-toolbar container-fluid' style='float: right;'>
<div class='btn-group'>
<button class='btn btn-default' id='stock-export' title='{% trans "Export Stock Information" %}'>{% trans "Export" %}</button>
<button class='btn btn-default' id='stock-export' title='{% trans "Export Stock Information" %}'>
<span class='fas fa-file-download'></span> {% trans "Export" %}
</button>
{% if read_only %}
{% else %}
{% if roles.stock.add %}
<button class="btn btn-success" id='item-create'>{% trans "New Stock Item" %}</button>
<button class="btn btn-success" id='item-create'>
<span class='fas fa-plus-circle'></span> {% trans "New Stock Item" %}
</button>
{% endif %}
{% if roles.stock.change or roles.stock.delete %}
<div class="btn-group">

View File

@ -171,7 +171,7 @@ def translate(c):
or after adding translations for existing strings.
"""
manage(c, "makemessages")
manage(c, "makemessages -e html -e py -e js")
manage(c, "compilemessages")
@task