mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
e07d7e3874
@ -11,6 +11,8 @@ from rest_framework import generics, permissions
|
|||||||
|
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
|
|
||||||
|
from InvenTree.helpers import str2bool
|
||||||
|
|
||||||
from .models import Company
|
from .models import Company
|
||||||
from .models import SupplierPart, SupplierPriceBreak
|
from .models import SupplierPart, SupplierPriceBreak
|
||||||
|
|
||||||
@ -84,6 +86,16 @@ class SupplierPartList(generics.ListCreateAPIView):
|
|||||||
'supplier',
|
'supplier',
|
||||||
'pricebreaks')
|
'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
|
serializer_class = SupplierPartSerializer
|
||||||
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
|
@ -64,6 +64,15 @@ class SupplierPartSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
pricing = serializers.CharField(source='unit_pricing', read_only=True)
|
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:
|
class Meta:
|
||||||
model = SupplierPart
|
model = SupplierPart
|
||||||
fields = [
|
fields = [
|
||||||
|
@ -47,10 +47,13 @@
|
|||||||
$("#part-table").bootstrapTable({
|
$("#part-table").bootstrapTable({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
pagination: true,
|
||||||
|
pageSize: 50,
|
||||||
formatNoMatches: function() { return "No supplier parts found for {{ company.name }}"; },
|
formatNoMatches: function() { return "No supplier parts found for {{ company.name }}"; },
|
||||||
queryParams: function(p) {
|
queryParams: function(p) {
|
||||||
return {
|
return {
|
||||||
supplier: {{ company.id }}
|
supplier: {{ company.id }},
|
||||||
|
part_detail: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
url: "{% url 'api-stock-list' %}",
|
url: "{% url 'api-stock-list' %}",
|
||||||
params: {
|
params: {
|
||||||
supplier: {{ company.id }},
|
supplier: {{ company.id }},
|
||||||
|
part_detail: true,
|
||||||
|
location_detail: true,
|
||||||
},
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
'#stock-options',
|
'#stock-options',
|
||||||
|
@ -45,6 +45,7 @@ InvenTree | Supplier List
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
|
pageSize: 50,
|
||||||
formatNoMatches: function() { return "No company information found"; },
|
formatNoMatches: function() { return "No company information found"; },
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@ from .serializers import CategorySerializer
|
|||||||
from .serializers import PartStarSerializer
|
from .serializers import PartStarSerializer
|
||||||
|
|
||||||
from InvenTree.views import TreeSerializer
|
from InvenTree.views import TreeSerializer
|
||||||
|
from InvenTree.helpers import str2bool
|
||||||
|
|
||||||
|
|
||||||
class PartCategoryTree(TreeSerializer):
|
class PartCategoryTree(TreeSerializer):
|
||||||
@ -206,6 +207,18 @@ class BomList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
serializer_class = BomItemSerializer
|
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):
|
def get_queryset(self):
|
||||||
queryset = BomItem.objects.all()
|
queryset = BomItem.objects.all()
|
||||||
queryset = self.get_serializer_class().setup_eager_loading(queryset)
|
queryset = self.get_serializer_class().setup_eager_loading(queryset)
|
||||||
|
@ -125,6 +125,21 @@ class BomItemSerializer(InvenTreeModelSerializer):
|
|||||||
sub_part_detail = PartBriefSerializer(source='sub_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)
|
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
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
queryset = queryset.prefetch_related('part')
|
queryset = queryset.prefetch_related('part')
|
||||||
|
@ -72,7 +72,8 @@
|
|||||||
editable: {{ editing_enabled }},
|
editable: {{ editing_enabled }},
|
||||||
bom_url: "{% url 'api-bom-list' %}",
|
bom_url: "{% url 'api-bom-list' %}",
|
||||||
part_url: "{% url 'api-part-list' %}",
|
part_url: "{% url 'api-part-list' %}",
|
||||||
parent_id: {{ part.id }}
|
parent_id: {{ part.id }} ,
|
||||||
|
sub_part_detail: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
{% if editing_enabled %}
|
{% if editing_enabled %}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
|
pageSize: 50,
|
||||||
queryParams: function(p) {
|
queryParams: function(p) {
|
||||||
return {
|
return {
|
||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
loadStockTable($("#stock-table"), {
|
loadStockTable($("#stock-table"), {
|
||||||
params: {
|
params: {
|
||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
|
location_detail: true,
|
||||||
|
part_detail: true,
|
||||||
},
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
'#stock-options',
|
'#stock-options',
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
formatNoMatches: function() { return "{{ part.full_name }} is not used to make any other parts"; },
|
formatNoMatches: function() { return "{{ part.full_name }} is not used to make any other parts"; },
|
||||||
queryParams: function(p) {
|
queryParams: function(p) {
|
||||||
return {
|
return {
|
||||||
sub_part: {{ part.id }}
|
sub_part: {{ part.id }},
|
||||||
|
part_detail: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
|
@ -121,7 +121,16 @@ function loadBomTable(table, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
},
|
||||||
|
footerFormatter: function(data) {
|
||||||
|
var quantity = 0;
|
||||||
|
|
||||||
|
data.forEach(function(item) {
|
||||||
|
quantity += item.quantity;
|
||||||
|
});
|
||||||
|
|
||||||
|
return quantity;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -190,20 +199,31 @@ function loadBomTable(table, options) {
|
|||||||
|
|
||||||
// Configure the table (bootstrap-table)
|
// 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({
|
table.bootstrapTable({
|
||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
formatNoMatches: function() { return "No BOM items found"; },
|
formatNoMatches: function() { return "No BOM items found"; },
|
||||||
clickToSelect: true,
|
clickToSelect: true,
|
||||||
|
showFooter: true,
|
||||||
queryParams: function(p) {
|
queryParams: function(p) {
|
||||||
return {
|
return params;
|
||||||
part: options.parent_id,
|
},
|
||||||
ordering: 'name',
|
columns: cols,
|
||||||
}
|
url: options.bom_url
|
||||||
},
|
});
|
||||||
columns: cols,
|
|
||||||
url: options.bom_url
|
|
||||||
});
|
|
||||||
|
|
||||||
// In editing mode, attached editables to the appropriate table elements
|
// In editing mode, attached editables to the appropriate table elements
|
||||||
if (options.editable) {
|
if (options.editable) {
|
||||||
|
@ -377,7 +377,7 @@ function loadStockTable(table, options) {
|
|||||||
search: true,
|
search: true,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
pagination: true,
|
pagination: true,
|
||||||
pageSize: 25,
|
pageSize: 50,
|
||||||
rememberOrder: true,
|
rememberOrder: true,
|
||||||
queryParams: options.params,
|
queryParams: options.params,
|
||||||
columns: [
|
columns: [
|
||||||
@ -392,25 +392,25 @@ function loadStockTable(table, options) {
|
|||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'part.full_name',
|
field: 'part_detail',
|
||||||
title: 'Part',
|
title: 'Part',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
formatter: function(value, row, index, field) {
|
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',
|
title: 'Description',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'location',
|
field: 'location_detail',
|
||||||
title: 'Location',
|
title: 'Location',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
if (row.location) {
|
if (value) {
|
||||||
return renderLink(row.location.pathstring, row.location.url);
|
return renderLink(value.pathstring, value.url);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return '<i>No stock location set</i>';
|
return '<i>No stock location set</i>';
|
||||||
@ -558,6 +558,7 @@ function loadStockTrackingTable(table, options) {
|
|||||||
queryParams: options.params,
|
queryParams: options.params,
|
||||||
columns: cols,
|
columns: cols,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
|
pageSize: 50,
|
||||||
url: options.url,
|
url: options.url,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ from .serializers import LocationSerializer
|
|||||||
from .serializers import StockTrackingSerializer
|
from .serializers import StockTrackingSerializer
|
||||||
|
|
||||||
from InvenTree.views import TreeSerializer
|
from InvenTree.views import TreeSerializer
|
||||||
|
from InvenTree.helpers import str2bool
|
||||||
|
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
@ -245,6 +246,17 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
- supplier: Filter by supplier
|
- 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):
|
def get_queryset(self):
|
||||||
"""
|
"""
|
||||||
If the query includes a particular location,
|
If the query includes a particular location,
|
||||||
|
@ -55,11 +55,11 @@ class StockItemSerializer(serializers.ModelSerializer):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
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)
|
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
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
queryset = queryset.prefetch_related('part')
|
queryset = queryset.prefetch_related('part')
|
||||||
@ -69,14 +69,29 @@ class StockItemSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
return queryset
|
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:
|
class Meta:
|
||||||
model = StockItem
|
model = StockItem
|
||||||
fields = [
|
fields = [
|
||||||
'pk',
|
'pk',
|
||||||
'url',
|
'url',
|
||||||
'part',
|
'part',
|
||||||
|
'part_detail',
|
||||||
'supplier_part',
|
'supplier_part',
|
||||||
'location',
|
'location',
|
||||||
|
'location_detail',
|
||||||
'in_stock',
|
'in_stock',
|
||||||
'quantity',
|
'quantity',
|
||||||
'serial',
|
'serial',
|
||||||
|
@ -141,6 +141,8 @@
|
|||||||
{% if location %}
|
{% if location %}
|
||||||
location: {{ location.id }},
|
location: {{ location.id }},
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
part_detail: true,
|
||||||
|
location_detail: true,
|
||||||
},
|
},
|
||||||
url: "{% url 'api-stock-list' %}",
|
url: "{% url 'api-stock-list' %}",
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user