Allocate "non tracked" parts separately from tracked ones

This commit is contained in:
Oliver Walters 2020-10-26 18:21:45 +11:00
parent 7525bc2ead
commit 5e0d1fe25a
6 changed files with 128 additions and 56 deletions

View File

@ -177,4 +177,4 @@ class EditBuildAttachmentForm(HelperForm):
'build',
'attachment',
'comment'
]
]

View File

@ -25,29 +25,39 @@ InvenTree | Allocate Parts
<table class='table table-striped table-condensed' id='build-item-list' data-toolbar='#build-item-toolbar'></table>
-->
<h4>{% trans "Untracked Parts" %}</h4>
<div class="panel-group" id="build-output-accordion" role="tablist" aria-multiselectable="true">
{% for item in build.incomplete_outputs %}
{% include "build/allocation_card.html" with item=item complete=False %}
{% endfor %}
{% include "build/allocation_card.html" %}
</div>
{% if build.incomplete_outputs %}
<h4>{% trans "Tracked Build Ouputs" %}</h4>
<div class="panel-group" id="build-output-accordion" role="tablist" aria-multiselectable="true">
{% for item in build.incomplete_outputs %}
{% include "build/allocation_card.html" with item=item %}
{% endfor %}
</div>
{% endif %}
{% endblock %}
{% block js_ready %}
{{ block.super }}
{% for item in build.incomplete_outputs %}
var buildInfo = {
pk: {{ build.pk }},
quantity: {{ build.quantity }},
completed: {{ build.completed }},
part: {{ build.part.pk }},
};
loadBuildOutputAllocationTable(buildInfo, null);
{% for item in build.incomplete_outputs %}
// Get the build output as a javascript object
inventreeGet('{% url 'api-stock-detail' item.pk %}', {},
{
success: function(response) {
loadBuildOutputAllocationTable(
{{ build.pk }},
{{ build.part.pk }},
response
);
loadBuildOutputAllocationTable(buildInfo, response);
}
}
);

View File

@ -1,33 +1,44 @@
{% load i18n %}
{% load inventree_extras %}
<div class="panel panel-default" id='allocation-panel-{{ item.pk }}'>
<div class="panel-heading" role="tab" id="heading-{{ item.pk }}">
{% if item %}
{% define item.pk as pk %}
{% else %}
{% define 'untracked' as pk %}
{% endif %}
<div class="panel panel-default" id='allocation-panel-{{ pk }}'>
<div class="panel-heading" role="tab" id="heading-{{ pk }}">
<div class="panel-title">
<div class='row'>
<div class='col-sm-6'>
<a role="button" data-toggle="collapse" data-parent="#build-output-accordion" href="#collapse-{{ item.pk }}" aria-expanded="true" aria-controls="collapse-{{ item.pk }}">
<a role="button" data-toggle="collapse" data-parent="#build-output-accordion" href="#collapse-{{ pk }}" aria-expanded="true" aria-controls="collapse-{{ pk }}">
{% if item %}
{{ item }}
{% else %}
{% trans "Untracked items" %}
{% endif %}
</div>
</a>
<div class='col-sm-3'>
<div>
{% trans "Completed lines" %}:
<div id='output-progress-{{ item.pk }}'>
<div id='output-progress-{{ pk }}'>
<span class='fas fa-spin fa-spinner'></span>
</div>
</div>
</div>
<div class='col-sm-3'>
<div class='btn-group float-right' id='output-actions-{{ item.pk }}'>
<div class='btn-group float-right' id='output-actions-{{ pk }}'>
<span class='fas fa-spin fa-spinner'></span>
</div>
</div>
</div>
</div>
</div>
<div id="collapse-{{ item.pk }}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-{{ item.pk }}">
<div id="collapse-{{ pk }}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-{{ pk }}">
<div class="panel-body">
<table class='table table-striped table-condensed' id='allocation-table-{{ item.pk }}'></table>
<table class='table table-striped table-condensed' id='allocation-table-{{ pk }}'></table>
</div>
</div>
</div>

View File

@ -646,6 +646,16 @@ class BuildItemCreate(AjaxCreateView):
"""
pass
# If the sub_part is supplied, limit to matching stock items
part_id = self.get_param('part')
if part_id:
try:
self.part = Part.objects.get(pk=part_id)
except (ValueError, Part.DoesNotExist):
pass
# If the output stock item is specified, hide the input field
output_id = form['install_into'].value()
@ -657,15 +667,10 @@ class BuildItemCreate(AjaxCreateView):
except (ValueError, StockItem.DoesNotExist):
pass
# If the sub_part is supplied, limit to matching stock items
part_id = self.get_param('part')
if part_id:
try:
self.part = Part.objects.get(pk=part_id)
except (ValueError, Part.DoesNotExist):
pass
else:
# If the output is not specified, but we know that the part is non-trackable, hide the install_into field
if self.part and not self.part.trackable:
form.fields['install_into'].widget = HiddenInput()
if self.build and self.part:
available_items = self.build.getAvailableStockItems(part=self.part, output=self.output)

View File

@ -91,7 +91,7 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
class PurchaseOrderAttachmentCreate(AjaxCreateView):
"""
View for creating a new PurchaseOrderAtt
View for creating a new PurchaseOrderAttachment
"""
model = PurchaseOrderAttachment

View File

@ -32,11 +32,15 @@ function newBuildOrder(options={}) {
}
function makeBuildOutputActionButtons(output, buildId) {
function makeBuildOutputActionButtons(output, buildInfo) {
/* Generate action buttons for a build output.
*/
var outputId = output.pk;
var outputId = 'untracked';
if (output) {
outputId = output.pk;
}
var panel = `#allocation-panel-${outputId}`;
@ -58,16 +62,6 @@ function makeBuildOutputActionButtons(output, buildId) {
}
);
if (output.quantity > 1) {
html += makeIconButton(
'fa-random icon-blue', 'button-output-split', outputId,
'{% trans "Split build output into separate items" %}',
{
disabled: true
}
);
}
// Add a button to "complete" the particular build output
html += makeIconButton(
'fa-tools icon-green', 'button-output-complete', outputId,
@ -139,7 +133,7 @@ function makeBuildOutputActionButtons(output, buildId) {
}
function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
/*
* Load the "allocation table" for a particular build output.
*
@ -151,10 +145,25 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
* -- table: The #id of the table (will be auto-calculated if not provided)
*/
var outputId = output.pk;
var buildId = buildInfo.pk;
var partId = buildInfo.part;
var table = options.table || `#allocation-table-${outputId}`;
var outputId = null;
if (output) {
outputId = output.pk;
}
var table = options.table;
if (options.table == null) {
if (outputId != null) {
table = `#allocation-table-${outputId}`;
} else {
table = `#allocation-table-untracked`;
}
}
function reloadTable() {
// Reload the entire build allocation table
$(table).bootstrapTable('refresh');
@ -163,7 +172,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
function requiredQuantity(row) {
// Return the requied quantity for a given row
return row.quantity * output.quantity;
if (output) {
// Tracked stock allocated against a particular BuildOutput
return row.quantity * output.quantity;
} else {
// Untrack stock allocated against the build
return row.quantity * (buildInfo.quantity - buildInfo.completed);
}
}
function sumAllocations(row) {
@ -199,16 +215,33 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
install_into: outputId,
},
secondary: [
{
field: 'stock_item',
label: '{% trans "New Stock Item" %}',
title: '{% trans "Create new Stock Item" %}',
url: '{% url "stock-item-create" %}',
data: {
part: pk,
{
field: 'stock_item',
label: '{% trans "New Stock Item" %}',
title: '{% trans "Create new Stock Item" %}',
url: '{% url "stock-item-create" %}',
data: {
part: pk,
},
},
},
]
],
callback: [
{
field: 'stock_item',
action: function(value) {
inventreeGet(
`/api/stock/${value}/`, {},
{
success: function(response) {
var available = response.quantity - response.allocated;
console.log('available: ' + available);
}
}
)
}
}
]
});
});
@ -253,6 +286,7 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
queryParams: {
part: partId,
sub_part_detail: true,
trackable: outputId != null,
},
formatNoMatches: function() {
return '{% trans "No BOM items found" %}';
@ -262,6 +296,7 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
onPostBody: setupCallbacks,
onLoadSuccess: function(tableData) {
// Once the BOM data are loaded, request allocation data for this build output
inventreeGet('/api/build/item/',
{
build: buildId,
@ -293,9 +328,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
// Now update the allocations for each row in the table
for (var key in allocations) {
// Select the associated row in the table
var tableRow = $(table).bootstrapTable('getRowByUniqueId', key);
if (!tableRow) {
continue;
}
// Set the allocation list for that row
tableRow.allocations = allocations[key];
@ -303,8 +343,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
var allocatedQuantity = sumAllocations(tableRow);
// Is this line item fully allocated?
if (allocatedQuantity >= (tableRow.quantity * output.quantity)) {
allocatedLines += 1;
if (output) {
if (allocatedQuantity >= (tableRow.quantity * output.quantity)) {
allocatedLines += 1;
}
} else {
if (allocatedQuantity >= (tableRow.quantity * (buildInfo.quantity - buildInfo.completed))) {
allocatedLines += 1;
}
}
// Push the updated row back into the main table
@ -323,7 +369,7 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
// Update the available actions for this build output
makeBuildOutputActionButtons(output, buildId);
makeBuildOutputActionButtons(output, buildInfo);
}
}
);