mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Allocate "non tracked" parts separately from tracked ones
This commit is contained in:
parent
7525bc2ead
commit
5e0d1fe25a
@ -25,29 +25,39 @@ InvenTree | Allocate Parts
|
|||||||
<table class='table table-striped table-condensed' id='build-item-list' data-toolbar='#build-item-toolbar'></table>
|
<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">
|
<div class="panel-group" id="build-output-accordion" role="tablist" aria-multiselectable="true">
|
||||||
{% for item in build.incomplete_outputs %}
|
{% include "build/allocation_card.html" %}
|
||||||
{% include "build/allocation_card.html" with item=item complete=False %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js_ready %}
|
{% block js_ready %}
|
||||||
{{ block.super }}
|
{{ 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
|
// Get the build output as a javascript object
|
||||||
inventreeGet('{% url 'api-stock-detail' item.pk %}', {},
|
inventreeGet('{% url 'api-stock-detail' item.pk %}', {},
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
loadBuildOutputAllocationTable(
|
loadBuildOutputAllocationTable(buildInfo, response);
|
||||||
{{ build.pk }},
|
|
||||||
{{ build.part.pk }},
|
|
||||||
response
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,33 +1,44 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
<div class="panel panel-default" id='allocation-panel-{{ item.pk }}'>
|
{% if item %}
|
||||||
<div class="panel-heading" role="tab" id="heading-{{ item.pk }}">
|
{% 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="panel-title">
|
||||||
<div class='row'>
|
<div class='row'>
|
||||||
<div class='col-sm-6'>
|
<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 }}
|
{{ item }}
|
||||||
|
{% else %}
|
||||||
|
{% trans "Untracked items" %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class='col-sm-3'>
|
<div class='col-sm-3'>
|
||||||
<div>
|
<div>
|
||||||
{% trans "Completed lines" %}:
|
{% trans "Completed lines" %}:
|
||||||
<div id='output-progress-{{ item.pk }}'>
|
<div id='output-progress-{{ pk }}'>
|
||||||
<span class='fas fa-spin fa-spinner'></span>
|
<span class='fas fa-spin fa-spinner'></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='col-sm-3'>
|
<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>
|
<span class='fas fa-spin fa-spinner'></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
@ -646,6 +646,16 @@ class BuildItemCreate(AjaxCreateView):
|
|||||||
"""
|
"""
|
||||||
pass
|
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
|
# If the output stock item is specified, hide the input field
|
||||||
output_id = form['install_into'].value()
|
output_id = form['install_into'].value()
|
||||||
|
|
||||||
@ -657,15 +667,10 @@ class BuildItemCreate(AjaxCreateView):
|
|||||||
except (ValueError, StockItem.DoesNotExist):
|
except (ValueError, StockItem.DoesNotExist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If the sub_part is supplied, limit to matching stock items
|
else:
|
||||||
part_id = self.get_param('part')
|
# 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:
|
||||||
if part_id:
|
form.fields['install_into'].widget = HiddenInput()
|
||||||
try:
|
|
||||||
self.part = Part.objects.get(pk=part_id)
|
|
||||||
|
|
||||||
except (ValueError, Part.DoesNotExist):
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.build and self.part:
|
if self.build and self.part:
|
||||||
available_items = self.build.getAvailableStockItems(part=self.part, output=self.output)
|
available_items = self.build.getAvailableStockItems(part=self.part, output=self.output)
|
||||||
|
@ -91,7 +91,7 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
|
|||||||
|
|
||||||
class PurchaseOrderAttachmentCreate(AjaxCreateView):
|
class PurchaseOrderAttachmentCreate(AjaxCreateView):
|
||||||
"""
|
"""
|
||||||
View for creating a new PurchaseOrderAtt
|
View for creating a new PurchaseOrderAttachment
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model = PurchaseOrderAttachment
|
model = PurchaseOrderAttachment
|
||||||
|
@ -32,11 +32,15 @@ function newBuildOrder(options={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function makeBuildOutputActionButtons(output, buildId) {
|
function makeBuildOutputActionButtons(output, buildInfo) {
|
||||||
/* Generate action buttons for a build output.
|
/* Generate action buttons for a build output.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var outputId = output.pk;
|
var outputId = 'untracked';
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
outputId = output.pk;
|
||||||
|
}
|
||||||
|
|
||||||
var panel = `#allocation-panel-${outputId}`;
|
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
|
// Add a button to "complete" the particular build output
|
||||||
html += makeIconButton(
|
html += makeIconButton(
|
||||||
'fa-tools icon-green', 'button-output-complete', outputId,
|
'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.
|
* Load the "allocation table" for a particular build output.
|
||||||
*
|
*
|
||||||
@ -151,9 +145,24 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
* -- table: The #id of the table (will be auto-calculated if not provided)
|
* -- 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() {
|
function reloadTable() {
|
||||||
// Reload the entire build allocation table
|
// Reload the entire build allocation table
|
||||||
@ -163,7 +172,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
function requiredQuantity(row) {
|
function requiredQuantity(row) {
|
||||||
// Return the requied quantity for a given 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) {
|
function sumAllocations(row) {
|
||||||
@ -199,16 +215,33 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
install_into: outputId,
|
install_into: outputId,
|
||||||
},
|
},
|
||||||
secondary: [
|
secondary: [
|
||||||
{
|
{
|
||||||
field: 'stock_item',
|
field: 'stock_item',
|
||||||
label: '{% trans "New Stock Item" %}',
|
label: '{% trans "New Stock Item" %}',
|
||||||
title: '{% trans "Create new Stock Item" %}',
|
title: '{% trans "Create new Stock Item" %}',
|
||||||
url: '{% url "stock-item-create" %}',
|
url: '{% url "stock-item-create" %}',
|
||||||
data: {
|
data: {
|
||||||
part: pk,
|
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: {
|
queryParams: {
|
||||||
part: partId,
|
part: partId,
|
||||||
sub_part_detail: true,
|
sub_part_detail: true,
|
||||||
|
trackable: outputId != null,
|
||||||
},
|
},
|
||||||
formatNoMatches: function() {
|
formatNoMatches: function() {
|
||||||
return '{% trans "No BOM items found" %}';
|
return '{% trans "No BOM items found" %}';
|
||||||
@ -262,6 +296,7 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
onPostBody: setupCallbacks,
|
onPostBody: setupCallbacks,
|
||||||
onLoadSuccess: function(tableData) {
|
onLoadSuccess: function(tableData) {
|
||||||
// Once the BOM data are loaded, request allocation data for this build output
|
// Once the BOM data are loaded, request allocation data for this build output
|
||||||
|
|
||||||
inventreeGet('/api/build/item/',
|
inventreeGet('/api/build/item/',
|
||||||
{
|
{
|
||||||
build: buildId,
|
build: buildId,
|
||||||
@ -293,9 +328,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
|
|
||||||
// Now update the allocations for each row in the table
|
// Now update the allocations for each row in the table
|
||||||
for (var key in allocations) {
|
for (var key in allocations) {
|
||||||
|
|
||||||
// Select the associated row in the table
|
// Select the associated row in the table
|
||||||
var tableRow = $(table).bootstrapTable('getRowByUniqueId', key);
|
var tableRow = $(table).bootstrapTable('getRowByUniqueId', key);
|
||||||
|
|
||||||
|
if (!tableRow) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the allocation list for that row
|
// Set the allocation list for that row
|
||||||
tableRow.allocations = allocations[key];
|
tableRow.allocations = allocations[key];
|
||||||
|
|
||||||
@ -303,8 +343,14 @@ function loadBuildOutputAllocationTable(buildId, partId, output, options={}) {
|
|||||||
var allocatedQuantity = sumAllocations(tableRow);
|
var allocatedQuantity = sumAllocations(tableRow);
|
||||||
|
|
||||||
// Is this line item fully allocated?
|
// Is this line item fully allocated?
|
||||||
if (allocatedQuantity >= (tableRow.quantity * output.quantity)) {
|
if (output) {
|
||||||
allocatedLines += 1;
|
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
|
// 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
|
// Update the available actions for this build output
|
||||||
|
|
||||||
makeBuildOutputActionButtons(output, buildId);
|
makeBuildOutputActionButtons(output, buildInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user