Display a sub-list of stock items which are allocated to a SalseOrderLineItem

This commit is contained in:
Oliver Walters 2020-04-21 21:38:04 +10:00
parent b40234e403
commit cb636e000d
5 changed files with 93 additions and 5 deletions

View File

@ -158,6 +158,15 @@
background-color: #ebf4f4;
}
.sub-table {
margin-left: 25px;
margin-right: 25px;
}
.detail-icon .glyphicon {
color: #98d296;
}
/* Force select2 elements in modal forms to be full width */
.select-full-width {
width: 100%;

View File

@ -221,7 +221,6 @@ function loadBomTable(table, options) {
}
}
});
}
// Part notes

View File

@ -44,6 +44,67 @@ $("#so-lines-table").inventreeTable({
part_detail: true,
},
url: "{% url 'api-so-line-list' %}",
detailView: true,
detailFilter: function(index, row) {
return row.allocated > 0;
},
detailFormatter: function(index, row, element) {
inventreeGet("{% url 'api-stock-list' %}",
{
location_detail: true,
sales_order_line: row.pk,
},
{
success: function(response) {
var html = `<div class='sub-table'><table class='table table-striped table-condensed' id='allocation-table-${row.pk}'></table></div>`;
element.html(html);
$(`#allocation-table-${row.pk}`).bootstrapTable({
data: response,
showHeader: false,
columns: [
{
width: '50%',
field: 'quantity',
title: 'Quantity',
formatter: function(value, row, index, field) {
var html = '';
if (row.serial && row.quantity == 1) {
html = `Serial Number: ${row.serial}`;
} else {
html = `Quantity: ${row.quantity}`;
}
return renderLink(html, `/stock/item/${row.pk}/`);
},
},
{
field: 'location',
title: 'Location',
formatter: function(value, row, index, field) {
return renderLink(row.location_detail.pathstring, `/stock/location/${row.location}/`);
},
},
{
field: 'buttons',
title: 'Actions',
formatter: function(value, row, index, field) {
return '';
},
},
],
});
},
error: function(response) {
console.log("An error!");
},
}
);
return "{% trans 'Loading data' %}";
},
columns: [
{
field: 'pk',
@ -73,12 +134,29 @@ $("#so-lines-table").inventreeTable({
title: 'Quantity',
formatter: function(value, row, index, field) {
return makeProgressBar(row.allocated, row.quantity);
},
sorter: function(valA, valB, rowA, rowB) {
if (rowA.allocated == 0 && rowB.allocated == 0) {
return (rowA.quantity > rowB.quantity) ? 1 : -1;
}
var progressA = rowA.allocated / rowA.quantity;
var progressB = rowB.allocated / rowA.quantity;
return (progressA < progressB) ? 1 : -1;
}
},
{
field: 'notes',
title: 'Notes',
},
{
field: 'buttons',
formatter: function(value, row, index, field) {
return '-';
}
},
],
});

View File

@ -233,9 +233,11 @@ class PartStarSerializer(InvenTreeModelSerializer):
class BomItemSerializer(InvenTreeModelSerializer):
""" Serializer for BomItem object """
price_range = serializers.CharField(read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
sub_part_detail = PartBriefSerializer(source='sub_part', many=False, read_only=True)
price_range = serializers.CharField(read_only=True)
validated = serializers.BooleanField(read_only=True, source='is_line_valid')
def __init__(self, *args, **kwargs):

View File

@ -5,10 +5,10 @@
{% load i18n %}
{% block content %}
{% if item.sales_order %}
{% if item.sales_order_line %}
<div class='alert alert-block alert-info'>
{% trans "This stock item is allocated to " %}
<a href="{% url 'so-detail' item.sales_order.order.id %}"><b>{{ item.sales_order.order }}</b></a>
{% trans "This stock item is allocated to Sales Order" %}
<a href="{% url 'so-detail' item.sales_order_line.order.id %}"><b>{{ item.sales_order_line.order }}</b></a>
</div>
{% endif %}