mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-07 06:00:57 +00:00
[UI] Location filter (#9939)
* Filter incomplete outputs by location * Filter build allocated stock by location * Filter sales order allocations by location * Bump API version * Fix API version * Fix annotations
This commit is contained in:
@ -1,12 +1,16 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 361
|
INVENTREE_API_VERSION = 362
|
||||||
|
|
||||||
"""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 = """
|
||||||
|
|
||||||
|
v362 -> 2025-07-02 : https://github.com/inventree/InvenTree/pull/9939
|
||||||
|
- Allow filtering of BuildItem API by "location" of StockItem
|
||||||
|
- Allow filtering of SalesOrderAllocation API by "location" of StockItem
|
||||||
|
|
||||||
v361 -> 2025-07-03 : https://github.com/inventree/InvenTree/pull/9944
|
v361 -> 2025-07-03 : https://github.com/inventree/InvenTree/pull/9944
|
||||||
- Enable SalesOrderAllocation list to be filtered by part IPN value
|
- Enable SalesOrderAllocation list to be filtered by part IPN value
|
||||||
- Enable SalesOrderAllocation list to be ordered by part MPN value
|
- Enable SalesOrderAllocation list to be ordered by part MPN value
|
||||||
|
@ -16,6 +16,7 @@ from rest_framework.response import Response
|
|||||||
import build.serializers
|
import build.serializers
|
||||||
import common.models
|
import common.models
|
||||||
import part.models as part_models
|
import part.models as part_models
|
||||||
|
import stock.models as stock_models
|
||||||
import stock.serializers
|
import stock.serializers
|
||||||
from build.models import Build, BuildItem, BuildLine
|
from build.models import Build, BuildItem, BuildLine
|
||||||
from build.status_codes import BuildStatus, BuildStatusGroups
|
from build.status_codes import BuildStatus, BuildStatusGroups
|
||||||
@ -830,6 +831,18 @@ class BuildItemFilter(rest_filters.FilterSet):
|
|||||||
return queryset.exclude(install_into=None)
|
return queryset.exclude(install_into=None)
|
||||||
return queryset.filter(install_into=None)
|
return queryset.filter(install_into=None)
|
||||||
|
|
||||||
|
location = rest_filters.ModelChoiceFilter(
|
||||||
|
queryset=stock_models.StockLocation.objects.all(),
|
||||||
|
label=_('Location'),
|
||||||
|
method='filter_location',
|
||||||
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(serializers.IntegerField(help_text=_('Location')))
|
||||||
|
def filter_location(self, queryset, name, location):
|
||||||
|
"""Filter the queryset based on the specified location."""
|
||||||
|
locations = location.get_descendants(include_self=True)
|
||||||
|
return queryset.filter(stock_item__location__in=locations)
|
||||||
|
|
||||||
|
|
||||||
class BuildItemList(DataExportViewMixin, BulkDeleteMixin, ListCreateAPI):
|
class BuildItemList(DataExportViewMixin, BulkDeleteMixin, ListCreateAPI):
|
||||||
"""API endpoint for accessing a list of BuildItem objects.
|
"""API endpoint for accessing a list of BuildItem objects.
|
||||||
|
@ -23,6 +23,7 @@ import build.models
|
|||||||
import common.models
|
import common.models
|
||||||
import common.settings
|
import common.settings
|
||||||
import company.models
|
import company.models
|
||||||
|
import stock.models as stock_models
|
||||||
from data_exporter.mixins import DataExportViewMixin
|
from data_exporter.mixins import DataExportViewMixin
|
||||||
from generic.states.api import StatusView
|
from generic.states.api import StatusView
|
||||||
from InvenTree.api import BulkUpdateMixin, ListCreateDestroyAPIView, MetadataView
|
from InvenTree.api import BulkUpdateMixin, ListCreateDestroyAPIView, MetadataView
|
||||||
@ -1178,6 +1179,20 @@ class SalesOrderAllocationFilter(rest_filters.FilterSet):
|
|||||||
return queryset.exclude(shipment=None)
|
return queryset.exclude(shipment=None)
|
||||||
return queryset.filter(shipment=None)
|
return queryset.filter(shipment=None)
|
||||||
|
|
||||||
|
location = rest_filters.ModelChoiceFilter(
|
||||||
|
queryset=stock_models.StockLocation.objects.all(),
|
||||||
|
label=_('Location'),
|
||||||
|
method='filter_location',
|
||||||
|
)
|
||||||
|
|
||||||
|
@extend_schema_field(
|
||||||
|
rest_framework.serializers.IntegerField(help_text=_('Location'))
|
||||||
|
)
|
||||||
|
def filter_location(self, queryset, name, location):
|
||||||
|
"""Filter by the location of the allocated StockItem."""
|
||||||
|
locations = location.get_descendants(include_self=True)
|
||||||
|
return queryset.filter(item__location__in=locations)
|
||||||
|
|
||||||
|
|
||||||
class SalesOrderAllocationMixin:
|
class SalesOrderAllocationMixin:
|
||||||
"""Mixin class for SalesOrderAllocation endpoints."""
|
"""Mixin class for SalesOrderAllocation endpoints."""
|
||||||
|
@ -350,3 +350,14 @@ export function PartCategoryFilter(): TableFilter {
|
|||||||
modelRenderer: (instance: any) => instance.name
|
modelRenderer: (instance: any) => instance.name
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function StockLocationFilter(): TableFilter {
|
||||||
|
return {
|
||||||
|
name: 'location',
|
||||||
|
label: t`Location`,
|
||||||
|
description: t`Filter by stock location`,
|
||||||
|
apiUrl: apiUrl(ApiEndpoints.stock_location_list),
|
||||||
|
model: ModelType.stocklocation,
|
||||||
|
modelRenderer: (instance: any) => instance.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
ReferenceColumn,
|
ReferenceColumn,
|
||||||
StatusColumn
|
StatusColumn
|
||||||
} from '../ColumnRenderers';
|
} from '../ColumnRenderers';
|
||||||
|
import { StockLocationFilter } from '../Filter';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
|
|
||||||
@ -69,6 +70,8 @@ export default function BuildAllocatedStockTable({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filters.push(StockLocationFilter());
|
||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
}, [partId]);
|
}, [partId]);
|
||||||
|
|
||||||
|
@ -57,7 +57,8 @@ import {
|
|||||||
SerialFilter,
|
SerialFilter,
|
||||||
SerialGTEFilter,
|
SerialGTEFilter,
|
||||||
SerialLTEFilter,
|
SerialLTEFilter,
|
||||||
StatusFilterOptions
|
StatusFilterOptions,
|
||||||
|
StockLocationFilter
|
||||||
} from '../Filter';
|
} from '../Filter';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { type RowAction, RowEditAction, RowViewAction } from '../RowActions';
|
import { type RowAction, RowEditAction, RowViewAction } from '../RowActions';
|
||||||
@ -363,6 +364,7 @@ export default function BuildOutputTable({
|
|||||||
description: t`Filter by stock status`,
|
description: t`Filter by stock status`,
|
||||||
choiceFunction: StatusFilterOptions(ModelType.stockitem)
|
choiceFunction: StatusFilterOptions(ModelType.stockitem)
|
||||||
},
|
},
|
||||||
|
StockLocationFilter(),
|
||||||
HasBatchCodeFilter(),
|
HasBatchCodeFilter(),
|
||||||
BatchFilter(),
|
BatchFilter(),
|
||||||
IsSerializedFilter(),
|
IsSerializedFilter(),
|
||||||
|
@ -27,6 +27,7 @@ import {
|
|||||||
ReferenceColumn,
|
ReferenceColumn,
|
||||||
StatusColumn
|
StatusColumn
|
||||||
} from '../ColumnRenderers';
|
} from '../ColumnRenderers';
|
||||||
|
import { StockLocationFilter } from '../Filter';
|
||||||
import { InvenTreeTable } from '../InvenTreeTable';
|
import { InvenTreeTable } from '../InvenTreeTable';
|
||||||
import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
import { type RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
|
||||||
|
|
||||||
@ -84,7 +85,8 @@ export default function SalesOrderAllocationTable({
|
|||||||
name: 'assigned_to_shipment',
|
name: 'assigned_to_shipment',
|
||||||
label: t`Assigned to Shipment`,
|
label: t`Assigned to Shipment`,
|
||||||
description: t`Show allocations assigned to a shipment`
|
description: t`Show allocations assigned to a shipment`
|
||||||
}
|
},
|
||||||
|
StockLocationFilter()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!!partId) {
|
if (!!partId) {
|
||||||
|
@ -486,7 +486,7 @@ export function StockItemTable({
|
|||||||
[showLocation, showPricing]
|
[showLocation, showPricing]
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableFilters = useMemo(
|
const tableFilters: TableFilter[] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
stockItemTableFilters({
|
stockItemTableFilters({
|
||||||
enableExpiry: stockExpiryEnabled
|
enableExpiry: stockExpiryEnabled
|
||||||
|
Reference in New Issue
Block a user