Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-05-23 23:24:11 +10:00
commit e07d7e3874
16 changed files with 133 additions and 23 deletions

View File

@ -11,6 +11,8 @@ from rest_framework import generics, permissions
from django.conf.urls import url, include
from InvenTree.helpers import str2bool
from .models import Company
from .models import SupplierPart, SupplierPriceBreak
@ -84,6 +86,16 @@ class SupplierPartList(generics.ListCreateAPIView):
'supplier',
'pricebreaks')
def get_serializer(self, *args, **kwargs):
# Do we wish to include extra detail?
part_detail = str2bool(self.request.GET.get('part_detail', None))
kwargs['part_detail'] = part_detail
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
serializer_class = SupplierPartSerializer
permission_classes = [

View File

@ -64,6 +64,15 @@ class SupplierPartSerializer(serializers.ModelSerializer):
pricing = serializers.CharField(source='unit_pricing', read_only=True)
def __init__(self, *args, **kwargs):
part_detail = kwargs.pop('part_detail', False)
super(SupplierPartSerializer, self).__init__(*args, **kwargs)
if part_detail is not True:
self.fields.pop('part_detail')
class Meta:
model = SupplierPart
fields = [

View File

@ -47,10 +47,13 @@
$("#part-table").bootstrapTable({
sortable: true,
search: true,
pagination: true,
pageSize: 50,
formatNoMatches: function() { return "No supplier parts found for {{ company.name }}"; },
queryParams: function(p) {
return {
supplier: {{ company.id }}
supplier: {{ company.id }},
part_detail: true,
}
},
columns: [

View File

@ -17,6 +17,8 @@
url: "{% url 'api-stock-list' %}",
params: {
supplier: {{ company.id }},
part_detail: true,
location_detail: true,
},
buttons: [
'#stock-options',

View File

@ -45,6 +45,7 @@ InvenTree | Supplier List
sortable: true,
search: true,
pagination: true,
pageSize: 50,
formatNoMatches: function() { return "No company information found"; },
columns: [
{

View File

@ -22,6 +22,7 @@ from .serializers import CategorySerializer
from .serializers import PartStarSerializer
from InvenTree.views import TreeSerializer
from InvenTree.helpers import str2bool
class PartCategoryTree(TreeSerializer):
@ -206,6 +207,18 @@ class BomList(generics.ListCreateAPIView):
serializer_class = BomItemSerializer
def get_serializer(self, *args, **kwargs):
# Do we wish to include extra detail?
part_detail = str2bool(self.request.GET.get('part_detail', None))
sub_part_detail = str2bool(self.request.GET.get('sub_part_detail', None))
kwargs['part_detail'] = part_detail
kwargs['sub_part_detail'] = sub_part_detail
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
def get_queryset(self):
queryset = BomItem.objects.all()
queryset = self.get_serializer_class().setup_eager_loading(queryset)

View File

@ -125,6 +125,21 @@ class BomItemSerializer(InvenTreeModelSerializer):
sub_part_detail = PartBriefSerializer(source='sub_part', many=False, read_only=True)
price_range = serializers.CharField(read_only=True)
def __init__(self, *args, **kwargs):
# part_detail and sub_part_detail serializers are only included if requested.
# This saves a bunch of database requests
part_detail = kwargs.pop('part_detail', False)
sub_part_detail = kwargs.pop('sub_part_detail', False)
super(BomItemSerializer, self).__init__(*args, **kwargs)
if part_detail is not True:
self.fields.pop('part_detail')
if sub_part_detail is not True:
self.fields.pop('sub_part_detail')
@staticmethod
def setup_eager_loading(queryset):
queryset = queryset.prefetch_related('part')

View File

@ -72,7 +72,8 @@
editable: {{ editing_enabled }},
bom_url: "{% url 'api-bom-list' %}",
part_url: "{% url 'api-part-list' %}",
parent_id: {{ part.id }}
parent_id: {{ part.id }} ,
sub_part_detail: true,
});
{% if editing_enabled %}

View File

@ -35,6 +35,7 @@
sortable: true,
search: true,
pagination: true,
pageSize: 50,
queryParams: function(p) {
return {
part: {{ part.id }},

View File

@ -37,6 +37,8 @@
loadStockTable($("#stock-table"), {
params: {
part: {{ part.id }},
location_detail: true,
part_detail: true,
},
buttons: [
'#stock-options',

View File

@ -30,7 +30,8 @@
formatNoMatches: function() { return "{{ part.full_name }} is not used to make any other parts"; },
queryParams: function(p) {
return {
sub_part: {{ part.id }}
sub_part: {{ part.id }},
part_detail: true,
}
},
columns: [

View File

@ -121,7 +121,16 @@ function loadBomTable(table, options) {
}
return text;
}
},
footerFormatter: function(data) {
var quantity = 0;
data.forEach(function(item) {
quantity += item.quantity;
});
return quantity;
},
}
);
@ -190,16 +199,27 @@ function loadBomTable(table, options) {
// Configure the table (bootstrap-table)
var params = {
part: options.parent_id,
ordering: 'name',
}
if (options.part_detail) {
params.part_detail = true;
}
if (options.sub_part_detail) {
params.sub_part_detail = true;
}
table.bootstrapTable({
sortable: true,
search: true,
formatNoMatches: function() { return "No BOM items found"; },
clickToSelect: true,
showFooter: true,
queryParams: function(p) {
return {
part: options.parent_id,
ordering: 'name',
}
return params;
},
columns: cols,
url: options.bom_url

View File

@ -377,7 +377,7 @@ function loadStockTable(table, options) {
search: true,
method: 'get',
pagination: true,
pageSize: 25,
pageSize: 50,
rememberOrder: true,
queryParams: options.params,
columns: [
@ -392,25 +392,25 @@ function loadStockTable(table, options) {
visible: false,
},
{
field: 'part.full_name',
field: 'part_detail',
title: 'Part',
sortable: true,
formatter: function(value, row, index, field) {
return imageHoverIcon(row.part.image_url) + renderLink(value, row.part.url + 'stock/');
return imageHoverIcon(value.image_url) + renderLink(value.full_name, value.url + 'stock/');
}
},
{
field: 'part.description',
field: 'part_detail.description',
title: 'Description',
sortable: true,
},
{
field: 'location',
field: 'location_detail',
title: 'Location',
sortable: true,
formatter: function(value, row, index, field) {
if (row.location) {
return renderLink(row.location.pathstring, row.location.url);
if (value) {
return renderLink(value.pathstring, value.url);
}
else {
return '<i>No stock location set</i>';
@ -558,6 +558,7 @@ function loadStockTrackingTable(table, options) {
queryParams: options.params,
columns: cols,
pagination: true,
pageSize: 50,
url: options.url,
});

View File

@ -18,6 +18,7 @@ from .serializers import LocationSerializer
from .serializers import StockTrackingSerializer
from InvenTree.views import TreeSerializer
from InvenTree.helpers import str2bool
from rest_framework.serializers import ValidationError
from rest_framework.views import APIView
@ -245,6 +246,17 @@ class StockList(generics.ListCreateAPIView):
- supplier: Filter by supplier
"""
def get_serializer(self, *args, **kwargs):
part_detail = str2bool(self.request.GET.get('part_detail', None))
location_detail = str2bool(self.request.GET.get('location_detail', None))
kwargs['part_detail'] = part_detail
kwargs['location_detail'] = location_detail
kwargs['context'] = self.get_serializer_context()
return self.serializer_class(*args, **kwargs)
def get_queryset(self):
"""
If the query includes a particular location,

View File

@ -55,11 +55,11 @@ class StockItemSerializer(serializers.ModelSerializer):
"""
url = serializers.CharField(source='get_absolute_url', read_only=True)
part = PartBriefSerializer(many=False, read_only=True)
location = LocationBriefSerializer(many=False, read_only=True)
status_text = serializers.CharField(source='get_status_display', read_only=True)
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
location_detail = LocationBriefSerializer(source='location', many=False, read_only=True)
@staticmethod
def setup_eager_loading(queryset):
queryset = queryset.prefetch_related('part')
@ -69,14 +69,29 @@ class StockItemSerializer(serializers.ModelSerializer):
return queryset
def __init__(self, *args, **kwargs):
part_detail = kwargs.pop('part_detail', False)
location_detail = kwargs.pop('location_detail', False)
super(StockItemSerializer, self).__init__(*args, **kwargs)
if part_detail is not True:
self.fields.pop('part_detail')
if location_detail is not True:
self.fields.pop('location_detail')
class Meta:
model = StockItem
fields = [
'pk',
'url',
'part',
'part_detail',
'supplier_part',
'location',
'location_detail',
'in_stock',
'quantity',
'serial',

View File

@ -141,6 +141,8 @@
{% if location %}
location: {{ location.id }},
{% endif %}
part_detail: true,
location_detail: true,
},
url: "{% url 'api-stock-list' %}",
});