mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-02 05:26:45 +00:00
Default location column (#7587)
* Add "default_location_detail" serializer to part API * Add column to CUI table * Implement in PUI part table * Update API version
This commit is contained in:
parent
189948be06
commit
1017ff0605
@ -1,12 +1,15 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 213
|
INVENTREE_API_VERSION = 214
|
||||||
|
|
||||||
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
|
||||||
|
|
||||||
|
|
||||||
INVENTREE_API_TEXT = """
|
INVENTREE_API_TEXT = """
|
||||||
|
v214 - 2024-07-08 : https://github.com/inventree/InvenTree/pull/7587
|
||||||
|
- Adds "default_location_detail" field to the Part API
|
||||||
|
|
||||||
v213 - 2024-07-06 : https://github.com/inventree/InvenTree/pull/7527
|
v213 - 2024-07-06 : https://github.com/inventree/InvenTree/pull/7527
|
||||||
- Adds 'locked' field to Part API
|
- Adds 'locked' field to Part API
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ from sql_util.utils import SubqueryCount
|
|||||||
from taggit.serializers import TagListSerializerField
|
from taggit.serializers import TagListSerializerField
|
||||||
|
|
||||||
import part.filters
|
import part.filters
|
||||||
|
import part.serializers as part_serializers
|
||||||
from importer.mixins import DataImportExportSerializerMixin
|
from importer.mixins import DataImportExportSerializerMixin
|
||||||
from importer.registry import register_importer
|
from importer.registry import register_importer
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
@ -22,7 +23,6 @@ from InvenTree.serializers import (
|
|||||||
NotesFieldMixin,
|
NotesFieldMixin,
|
||||||
RemoteImageMixin,
|
RemoteImageMixin,
|
||||||
)
|
)
|
||||||
from part.serializers import PartBriefSerializer
|
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Address,
|
Address,
|
||||||
@ -254,7 +254,9 @@ class ManufacturerPartSerializer(
|
|||||||
if prettify is not True:
|
if prettify is not True:
|
||||||
self.fields.pop('pretty_name', None)
|
self.fields.pop('pretty_name', None)
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
part_detail = part_serializers.PartBriefSerializer(
|
||||||
|
source='part', many=False, read_only=True
|
||||||
|
)
|
||||||
|
|
||||||
manufacturer_detail = CompanyBriefSerializer(
|
manufacturer_detail = CompanyBriefSerializer(
|
||||||
source='manufacturer', many=False, read_only=True
|
source='manufacturer', many=False, read_only=True
|
||||||
@ -387,7 +389,9 @@ class SupplierPartSerializer(
|
|||||||
|
|
||||||
pack_quantity_native = serializers.FloatField(read_only=True)
|
pack_quantity_native = serializers.FloatField(read_only=True)
|
||||||
|
|
||||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
part_detail = part_serializers.PartBriefSerializer(
|
||||||
|
source='part', many=False, read_only=True
|
||||||
|
)
|
||||||
|
|
||||||
supplier_detail = CompanyBriefSerializer(
|
supplier_detail = CompanyBriefSerializer(
|
||||||
source='supplier', many=False, read_only=True
|
source='supplier', many=False, read_only=True
|
||||||
|
@ -1204,6 +1204,7 @@ class PartMixin:
|
|||||||
|
|
||||||
kwargs['parameters'] = str2bool(params.get('parameters', None))
|
kwargs['parameters'] = str2bool(params.get('parameters', None))
|
||||||
kwargs['category_detail'] = str2bool(params.get('category_detail', False))
|
kwargs['category_detail'] = str2bool(params.get('category_detail', False))
|
||||||
|
kwargs['location_detail'] = str2bool(params.get('location_detail', False))
|
||||||
kwargs['path_detail'] = str2bool(params.get('path_detail', False))
|
kwargs['path_detail'] = str2bool(params.get('path_detail', False))
|
||||||
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -1354,6 +1355,7 @@ class PartList(PartMixin, DataExportViewMixin, ListCreateAPI):
|
|||||||
'total_in_stock',
|
'total_in_stock',
|
||||||
'unallocated_stock',
|
'unallocated_stock',
|
||||||
'category',
|
'category',
|
||||||
|
'default_location',
|
||||||
'last_stocktake',
|
'last_stocktake',
|
||||||
'units',
|
'units',
|
||||||
'pricing_min',
|
'pricing_min',
|
||||||
|
@ -591,6 +591,21 @@ class InitialSupplierSerializer(serializers.Serializer):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultLocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
|
||||||
|
"""Brief serializer for a StockLocation object.
|
||||||
|
|
||||||
|
Defined here, rather than stock.serializers, to negotiate circular imports.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options."""
|
||||||
|
|
||||||
|
import stock.models as stock_models
|
||||||
|
|
||||||
|
model = stock_models.StockLocation
|
||||||
|
fields = ['pk', 'name', 'pathstring']
|
||||||
|
|
||||||
|
|
||||||
@register_importer()
|
@register_importer()
|
||||||
class PartSerializer(
|
class PartSerializer(
|
||||||
DataImportExportSerializerMixin,
|
DataImportExportSerializerMixin,
|
||||||
@ -623,6 +638,7 @@ class PartSerializer(
|
|||||||
'creation_user',
|
'creation_user',
|
||||||
'default_expiry',
|
'default_expiry',
|
||||||
'default_location',
|
'default_location',
|
||||||
|
'default_location_detail',
|
||||||
'default_supplier',
|
'default_supplier',
|
||||||
'description',
|
'description',
|
||||||
'full_name',
|
'full_name',
|
||||||
@ -687,6 +703,7 @@ class PartSerializer(
|
|||||||
"""
|
"""
|
||||||
self.starred_parts = kwargs.pop('starred_parts', [])
|
self.starred_parts = kwargs.pop('starred_parts', [])
|
||||||
category_detail = kwargs.pop('category_detail', False)
|
category_detail = kwargs.pop('category_detail', False)
|
||||||
|
location_detail = kwargs.pop('location_detail', False)
|
||||||
parameters = kwargs.pop('parameters', False)
|
parameters = kwargs.pop('parameters', False)
|
||||||
create = kwargs.pop('create', False)
|
create = kwargs.pop('create', False)
|
||||||
pricing = kwargs.pop('pricing', True)
|
pricing = kwargs.pop('pricing', True)
|
||||||
@ -697,6 +714,9 @@ class PartSerializer(
|
|||||||
if not category_detail:
|
if not category_detail:
|
||||||
self.fields.pop('category_detail', None)
|
self.fields.pop('category_detail', None)
|
||||||
|
|
||||||
|
if not location_detail:
|
||||||
|
self.fields.pop('default_location_detail', None)
|
||||||
|
|
||||||
if not parameters:
|
if not parameters:
|
||||||
self.fields.pop('parameters', None)
|
self.fields.pop('parameters', None)
|
||||||
|
|
||||||
@ -740,6 +760,8 @@ class PartSerializer(
|
|||||||
|
|
||||||
Performing database queries as efficiently as possible, to reduce database trips.
|
Performing database queries as efficiently as possible, to reduce database trips.
|
||||||
"""
|
"""
|
||||||
|
queryset = queryset.prefetch_related('category', 'default_location')
|
||||||
|
|
||||||
# Annotate with the total number of stock items
|
# Annotate with the total number of stock items
|
||||||
queryset = queryset.annotate(stock_item_count=SubqueryCount('stock_items'))
|
queryset = queryset.annotate(stock_item_count=SubqueryCount('stock_items'))
|
||||||
|
|
||||||
@ -833,6 +855,10 @@ class PartSerializer(
|
|||||||
child=serializers.DictField(), source='category.get_path', read_only=True
|
child=serializers.DictField(), source='category.get_path', read_only=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
default_location_detail = DefaultLocationSerializer(
|
||||||
|
source='default_location', many=False, read_only=True
|
||||||
|
)
|
||||||
|
|
||||||
category_name = serializers.CharField(
|
category_name = serializers.CharField(
|
||||||
source='category.name', read_only=True, label=_('Category Name')
|
source='category.name', read_only=True, label=_('Category Name')
|
||||||
)
|
)
|
||||||
|
@ -17,19 +17,19 @@ from taggit.serializers import TagListSerializerField
|
|||||||
|
|
||||||
import build.models
|
import build.models
|
||||||
import company.models
|
import company.models
|
||||||
|
import company.serializers as company_serializers
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
import InvenTree.serializers
|
import InvenTree.serializers
|
||||||
import order.models
|
import order.models
|
||||||
import part.filters as part_filters
|
import part.filters as part_filters
|
||||||
import part.models as part_models
|
import part.models as part_models
|
||||||
|
import part.serializers as part_serializers
|
||||||
import stock.filters
|
import stock.filters
|
||||||
import stock.status_codes
|
import stock.status_codes
|
||||||
from common.settings import get_global_setting
|
from common.settings import get_global_setting
|
||||||
from company.serializers import SupplierPartSerializer
|
|
||||||
from importer.mixins import DataImportExportSerializerMixin
|
from importer.mixins import DataImportExportSerializerMixin
|
||||||
from importer.registry import register_importer
|
from importer.registry import register_importer
|
||||||
from InvenTree.serializers import InvenTreeCurrencySerializer, InvenTreeDecimalField
|
from InvenTree.serializers import InvenTreeCurrencySerializer, InvenTreeDecimalField
|
||||||
from part.serializers import PartBriefSerializer, PartTestTemplateSerializer
|
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
StockItem,
|
StockItem,
|
||||||
@ -233,7 +233,9 @@ class StockItemTestResultSerializer(
|
|||||||
label=_('Test template for this result'),
|
label=_('Test template for this result'),
|
||||||
)
|
)
|
||||||
|
|
||||||
template_detail = PartTestTemplateSerializer(source='template', read_only=True)
|
template_detail = part_serializers.PartTestTemplateSerializer(
|
||||||
|
source='template', read_only=True
|
||||||
|
)
|
||||||
|
|
||||||
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
attachment = InvenTree.serializers.InvenTreeAttachmentSerializerField(
|
||||||
required=False
|
required=False
|
||||||
@ -560,7 +562,7 @@ class StockItemSerializer(
|
|||||||
sku = serializers.CharField(source='supplier_part.SKU', read_only=True)
|
sku = serializers.CharField(source='supplier_part.SKU', read_only=True)
|
||||||
|
|
||||||
# Optional detail fields, which can be appended via query parameters
|
# Optional detail fields, which can be appended via query parameters
|
||||||
supplier_part_detail = SupplierPartSerializer(
|
supplier_part_detail = company_serializers.SupplierPartSerializer(
|
||||||
source='supplier_part',
|
source='supplier_part',
|
||||||
supplier_detail=False,
|
supplier_detail=False,
|
||||||
manufacturer_detail=False,
|
manufacturer_detail=False,
|
||||||
@ -568,7 +570,9 @@ class StockItemSerializer(
|
|||||||
many=False,
|
many=False,
|
||||||
read_only=True,
|
read_only=True,
|
||||||
)
|
)
|
||||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
part_detail = part_serializers.PartBriefSerializer(
|
||||||
|
source='part', many=False, read_only=True
|
||||||
|
)
|
||||||
|
|
||||||
location_detail = LocationBriefSerializer(
|
location_detail = LocationBriefSerializer(
|
||||||
source='location', many=False, read_only=True
|
source='location', many=False, read_only=True
|
||||||
|
@ -2276,6 +2276,7 @@ function loadPartTable(table, url, options={}) {
|
|||||||
|
|
||||||
// Ensure category detail is included
|
// Ensure category detail is included
|
||||||
options.params['category_detail'] = true;
|
options.params['category_detail'] = true;
|
||||||
|
options.params['location_detail'] = true;
|
||||||
|
|
||||||
let filters = {};
|
let filters = {};
|
||||||
|
|
||||||
@ -2389,6 +2390,19 @@ function loadPartTable(table, url, options={}) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
columns.push({
|
||||||
|
field: 'default_location',
|
||||||
|
title: '{% trans "Default Location" %}',
|
||||||
|
sortable: true,
|
||||||
|
formatter: function(value, row) {
|
||||||
|
if (row.default_location && row.default_location_detail) {
|
||||||
|
let text = shortenString(row.default_location_detail.pathstring);
|
||||||
|
return withTitle(renderLink(text, `/stock/location/${row.default_location}/`), row.default_location_detail.pathstring);
|
||||||
|
} else {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
columns.push({
|
columns.push({
|
||||||
field: 'total_in_stock',
|
field: 'total_in_stock',
|
||||||
|
@ -44,6 +44,11 @@ function partTableColumns(): TableColumn[] {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
render: (record: any) => record.category_detail?.pathstring
|
render: (record: any) => record.category_detail?.pathstring
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
accessor: 'default_location',
|
||||||
|
sortable: true,
|
||||||
|
render: (record: any) => record.default_location_detail?.pathstring
|
||||||
|
},
|
||||||
{
|
{
|
||||||
accessor: 'total_in_stock',
|
accessor: 'total_in_stock',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
@ -327,7 +332,8 @@ export function PartListTable({ props }: { props: InvenTreeTableProps }) {
|
|||||||
tableActions: tableActions,
|
tableActions: tableActions,
|
||||||
params: {
|
params: {
|
||||||
...props.params,
|
...props.params,
|
||||||
category_detail: true
|
category_detail: true,
|
||||||
|
location_detail: true
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user