mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds "required parts" tab to build view
This commit is contained in:
parent
8cb3d6ab0a
commit
bfbcbe252b
@ -1,9 +1,10 @@
|
|||||||
{% extends "build/build_base.html" %}
|
{% extends "build/build_base.html" %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block details %}
|
|
||||||
{% load status_codes %}
|
{% load status_codes %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
{% include "build/tabs.html" with tab='details' %}
|
{% include "build/tabs.html" with tab='details' %}
|
||||||
|
|
||||||
<h4>{% trans "Build Details" %}</h4>
|
<h4>{% trans "Build Details" %}</h4>
|
||||||
|
28
InvenTree/build/templates/build/parts.html
Normal file
28
InvenTree/build/templates/build/parts.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{% extends "build/build_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load status_codes %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
{% include "build/tabs.html" with tab='parts' %}
|
||||||
|
|
||||||
|
<h4>{% trans "Build Parts" %}</h4>
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<table class='table table-striped table-condensed' id='parts-table'></table>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
loadBuildPartsTable($('#parts-table'), {
|
||||||
|
part: {{ build.part.pk }},
|
||||||
|
build: {{ build.pk }},
|
||||||
|
build_quantity: {{ build.quantity }},
|
||||||
|
build_remaining: {{ build.remaining }},
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -5,16 +5,22 @@
|
|||||||
<a href="{% url 'build-detail' build.id %}">{% trans "Details" %}</a>
|
<a href="{% url 'build-detail' build.id %}">{% trans "Details" %}</a>
|
||||||
</li>
|
</li>
|
||||||
{% if build.active %}
|
{% if build.active %}
|
||||||
|
<li {% if tab == 'parts' %} class='active'{% endif %}>
|
||||||
|
<a href='{% url "build-parts" build.id %}'>
|
||||||
|
{% trans "Required Parts" %}
|
||||||
|
<span class='badge'>{{ build.part.bom_count }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li{% if tab == 'allocate' %} class='active'{% endif %}>
|
<li{% if tab == 'allocate' %} class='active'{% endif %}>
|
||||||
<a href="{% url 'build-allocate' build.id %}">
|
<a href="{% url 'build-allocate' build.id %}">
|
||||||
{% trans "Incomplete" %}
|
{% trans "In Progress" %}
|
||||||
<span class='badge'>{{ build.incomplete_outputs.count }}</span>
|
<span class='badge'>{{ build.incomplete_outputs.count }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li{% if tab == 'output' %} class='active'{% endif %}>
|
<li{% if tab == 'output' %} class='active'{% endif %}>
|
||||||
<a href="{% url 'build-output' build.id %}">
|
<a href="{% url 'build-output' build.id %}">
|
||||||
{% trans "Build Outputs" %}
|
{% trans "Completed Outputs" %}
|
||||||
<span class='badge'>{{ build.output_count }}</span>
|
<span class='badge'>{{ build.output_count }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -20,6 +20,7 @@ build_detail_urls = [
|
|||||||
|
|
||||||
url(r'^notes/', views.BuildNotes.as_view(), name='build-notes'),
|
url(r'^notes/', views.BuildNotes.as_view(), name='build-notes'),
|
||||||
|
|
||||||
|
url(r'^parts/', views.BuildDetail.as_view(template_name='build/parts.html'), name='build-parts'),
|
||||||
url(r'^attachments/', views.BuildDetail.as_view(template_name='build/attachments.html'), name='build-attachments'),
|
url(r'^attachments/', views.BuildDetail.as_view(template_name='build/attachments.html'), name='build-attachments'),
|
||||||
url(r'^output/', views.BuildDetail.as_view(template_name='build/build_output.html'), name='build-output'),
|
url(r'^output/', views.BuildDetail.as_view(template_name='build/build_output.html'), name='build-output'),
|
||||||
|
|
||||||
|
@ -77,19 +77,6 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_load %}
|
|
||||||
{{ block.super }}
|
|
||||||
|
|
||||||
<!-- jquery-treegrid -->
|
|
||||||
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.js" %}'></script>
|
|
||||||
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.bootstrap3.js" %}'></script>
|
|
||||||
|
|
||||||
<!-- boostrap-table-treegrid -->
|
|
||||||
<script type='text/javascript' src='{% static "bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.js" %}'></script>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block js_ready %}
|
{% block js_ready %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
||||||
|
@ -107,6 +107,13 @@ InvenTree
|
|||||||
<script type='text/javascript' src="{% static 'script/bootstrap/bootstrap-table-filter-control.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/bootstrap/bootstrap-table-filter-control.js' %}"></script>
|
||||||
<!-- <script type='text/javascript' src="{% static 'script/bootstrap/filter-control-utils.js' %}"></script> -->
|
<!-- <script type='text/javascript' src="{% static 'script/bootstrap/filter-control-utils.js' %}"></script> -->
|
||||||
|
|
||||||
|
<!-- jquery-treegrid -->
|
||||||
|
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.js" %}'></script>
|
||||||
|
<script type='text/javascript' src='{% static "treegrid/js/jquery.treegrid.bootstrap3.js" %}'></script>
|
||||||
|
|
||||||
|
<!-- boostrap-table-treegrid -->
|
||||||
|
<script type='text/javascript' src='{% static "bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.js" %}'></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
|
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
|
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
|
||||||
|
@ -834,3 +834,146 @@ function loadAllocationTable(table, part_id, part, url, required, button) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function loadBuildPartsTable(table, options={}) {
|
||||||
|
/**
|
||||||
|
* Display a "required parts" table for build view.
|
||||||
|
*
|
||||||
|
* This is a simplified BOM view:
|
||||||
|
* - Does not display sub-bom items
|
||||||
|
* - Does not allow editing of BOM items
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* part: Part ID
|
||||||
|
* build: Build ID
|
||||||
|
* build_quantity: Total build quantity
|
||||||
|
* build_remaining: Number of items remaining
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Query params
|
||||||
|
var params = {
|
||||||
|
sub_part_detail: true,
|
||||||
|
part: options.part,
|
||||||
|
};
|
||||||
|
|
||||||
|
var filters = {};
|
||||||
|
|
||||||
|
if (!options.disableFilters) {
|
||||||
|
filters = loadTableFilters('bom');
|
||||||
|
}
|
||||||
|
|
||||||
|
setupFilterList('bom', $(table));
|
||||||
|
|
||||||
|
for (var key in params) {
|
||||||
|
filters[key] = params[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
var columns = [
|
||||||
|
{
|
||||||
|
field: 'sub_part',
|
||||||
|
title: '{% trans "Part" %}',
|
||||||
|
switchable: false,
|
||||||
|
sortable: true,
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
var url = `/part/${row.sub_part}/`;
|
||||||
|
var html = imageHoverIcon(row.sub_part_detail.thumbnail) + renderLink(row.sub_part_detail.full_name, url);
|
||||||
|
|
||||||
|
var sub_part = row.sub_part_detail;
|
||||||
|
|
||||||
|
html += makePartIcons(row.sub_part_detail);
|
||||||
|
|
||||||
|
// Display an extra icon if this part is an assembly
|
||||||
|
if (sub_part.assembly) {
|
||||||
|
var text = `<span title='{% trans "Open subassembly" %}' class='fas fa-stream label-right'></span>`;
|
||||||
|
|
||||||
|
html += renderLink(text, `/part/${row.sub_part}/bom/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'sub_part_detail.description',
|
||||||
|
title: '{% trans "Description" %}',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'reference',
|
||||||
|
title: '{% trans "Reference" %}',
|
||||||
|
searchable: true,
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
title: '{% trans "Quantity" %}',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sortable: true,
|
||||||
|
switchable: false,
|
||||||
|
field: 'sub_part_detail.stock',
|
||||||
|
title: '{% trans "Available" %}',
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
return makeProgressBar(
|
||||||
|
value,
|
||||||
|
row.quantity * options.build_remaining,
|
||||||
|
{
|
||||||
|
id: `part-progress-${row.part}`
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
sorter: function(valA, valB, rowA, rowB) {
|
||||||
|
if (rowA.received == 0 && rowB.received == 0) {
|
||||||
|
return (rowA.quantity > rowB.quantity) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var progressA = parseFloat(rowA.sub_part_detail.stock) / (rowA.quantity * options.build_remaining);
|
||||||
|
var progressB = parseFloat(rowB.sub_part_detail.stock) / (rowB.quantity * options.build_remaining);
|
||||||
|
|
||||||
|
return (progressA < progressB) ? 1 : -1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'actions',
|
||||||
|
title: '{% trans "Actions" %}',
|
||||||
|
switchable: false,
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
// TODO - Add actions to build / order stock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
table.inventreeTable({
|
||||||
|
url: '{% url "api-bom-list" %}',
|
||||||
|
showColumns: true,
|
||||||
|
name: 'build-parts',
|
||||||
|
sortable: true,
|
||||||
|
search: true,
|
||||||
|
rowStyle: function(row, index) {
|
||||||
|
var classes = [];
|
||||||
|
|
||||||
|
// Shade rows differently if they are for different parent parts
|
||||||
|
if (row.part != options.part) {
|
||||||
|
classes.push('rowinherited');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.validated) {
|
||||||
|
classes.push('rowvalid');
|
||||||
|
} else {
|
||||||
|
classes.push('rowinvalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
classes: classes.join(' '),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
formatNoMatches: function() {
|
||||||
|
return '{% trans "No BOM items found" %}';
|
||||||
|
},
|
||||||
|
clickToSelect: true,
|
||||||
|
queryParams: filters,
|
||||||
|
original: params,
|
||||||
|
columns: columns,
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user