diff --git a/CHANGELOG.md b/CHANGELOG.md index 735d14c54a..6837b6c75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Adds "Category" columns to BOM and Build Item tables and APIs in [#10722](https://github.com/inventree/InvenTree/pull/10772) + ### Changed ### Removed diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index d003dcaba0..3c94b75938 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,11 +1,15 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 422 +INVENTREE_API_VERSION = 423 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v423 -> 2025-11-05 : https://github.com/inventree/InvenTree/pull/10772 + - Adds "category_detail" field to BomItem API endpoints + - Adds "category_detail" field to BuildLine API endpoints + v422 -> 2025-11-03 : https://github.com/inventree/InvenTree/pull/10750 - Adds ability to search StockItem API by supplier SKU - Adds ability to search StockItem API by manufacturer MPN diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index a7332428ca..d254b5ab19 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -597,6 +597,7 @@ class BuildLineList( ordering_fields = [ 'part', 'allocated', + 'category', 'consumed', 'reference', 'quantity', @@ -613,6 +614,7 @@ class BuildLineList( 'part': 'bom_item__sub_part__name', 'reference': 'bom_item__reference', 'unit_quantity': 'bom_item__quantity', + 'category': 'bom_item__sub_part__category__name', 'consumable': 'bom_item__consumable', 'optional': 'bom_item__optional', 'trackable': 'bom_item__sub_part__trackable', diff --git a/src/backend/InvenTree/build/serializers.py b/src/backend/InvenTree/build/serializers.py index 7c2c6def2b..efac948b60 100644 --- a/src/backend/InvenTree/build/serializers.py +++ b/src/backend/InvenTree/build/serializers.py @@ -1339,6 +1339,7 @@ class BuildLineSerializer( 'bom_item_detail', 'assembly_detail', 'part_detail', + 'category_detail', 'build_detail', ] read_only_fields = ['build', 'bom_item', 'allocations'] @@ -1430,6 +1431,17 @@ class BuildLineSerializer( True, ) + category_detail = enable_filter( + part_serializers.CategorySerializer( + label=_('Category'), + source='bom_item.sub_part.category', + many=False, + read_only=True, + allow_null=True, + ), + False, + ) + build_detail = enable_filter( BuildSerializer( label=_('Build'), @@ -1505,6 +1517,7 @@ class BuildLineSerializer( 'bom_item', 'bom_item__part', 'bom_item__sub_part', + 'bom_item__sub_part__category', 'bom_item__sub_part__stock_items', 'bom_item__sub_part__stock_items__allocations', 'bom_item__sub_part__stock_items__sales_order_allocations', diff --git a/src/backend/InvenTree/part/api.py b/src/backend/InvenTree/part/api.py index 81826daaa9..2af9a7f05f 100644 --- a/src/backend/InvenTree/part/api.py +++ b/src/backend/InvenTree/part/api.py @@ -1672,6 +1672,7 @@ class BomList( ordering_fields = [ 'can_build', + 'category', 'quantity', 'setup_quantity', 'attrition', @@ -1692,6 +1693,7 @@ class BomList( ] ordering_field_aliases = { + 'category': 'sub_part__category__name', 'sub_part': 'sub_part__name', 'pricing_min': 'sub_part__pricing_data__overall_min', 'pricing_max': 'sub_part__pricing_data__overall_max', diff --git a/src/backend/InvenTree/part/serializers.py b/src/backend/InvenTree/part/serializers.py index e053c5f26b..87329781ed 100644 --- a/src/backend/InvenTree/part/serializers.py +++ b/src/backend/InvenTree/part/serializers.py @@ -1668,13 +1668,11 @@ class BomItemSerializer( 'rounding_multiple', 'note', 'pk', - 'part_detail', 'pricing_min', 'pricing_max', 'pricing_min_total', 'pricing_max_total', 'pricing_updated', - 'sub_part_detail', 'substitutes', 'validated', # Annotated fields describing available quantity @@ -1688,6 +1686,10 @@ class BomItemSerializer( 'building', # Annotate the total potential quantity we can build 'can_build', + # Optional detail fields + 'part_detail', + 'sub_part_detail', + 'category_detail', ] quantity = InvenTree.serializers.InvenTreeDecimalField(required=True) @@ -1744,6 +1746,17 @@ class BomItemSerializer( True, ) + category_detail = enable_filter( + CategorySerializer( + source='sub_part.category', + label=_('Category'), + many=False, + read_only=True, + allow_null=True, + ), + False, + ) + on_order = serializers.FloatField( label=_('On Order'), read_only=True, allow_null=True ) diff --git a/src/frontend/src/tables/bom/BomTable.tsx b/src/frontend/src/tables/bom/BomTable.tsx index 1f4694fff4..cc50be9764 100644 --- a/src/frontend/src/tables/bom/BomTable.tsx +++ b/src/frontend/src/tables/bom/BomTable.tsx @@ -42,6 +42,7 @@ import { useTable } from '../../hooks/UseTable'; import { useUserState } from '../../states/UserState'; import { BooleanColumn, + CategoryColumn, DescriptionColumn, NoteColumn, ReferenceColumn @@ -133,6 +134,13 @@ export function BomTable({ title: t`IPN`, sortable: true }, + CategoryColumn({ + accessor: 'category_detail', + defaultVisible: false, + switchable: true, + sortable: true, + ordering: 'category' + }), DescriptionColumn({ accessor: 'sub_part_detail.description' }), @@ -662,6 +670,7 @@ export function BomTable({ params: { ...params, part: partId, + category_detail: true, part_detail: true, sub_part_detail: true }, diff --git a/src/frontend/src/tables/build/BuildLineTable.tsx b/src/frontend/src/tables/build/BuildLineTable.tsx index dd59129759..03b1e37881 100644 --- a/src/frontend/src/tables/build/BuildLineTable.tsx +++ b/src/frontend/src/tables/build/BuildLineTable.tsx @@ -43,12 +43,14 @@ import { useTable } from '../../hooks/UseTable'; import { useUserState } from '../../states/UserState'; import { BooleanColumn, + CategoryColumn, DecimalColumn, DescriptionColumn, LocationColumn, PartColumn, RenderPartColumn } from '../ColumnRenderers'; +import { PartCategoryFilter } from '../Filter'; import { InvenTreeTable } from '../InvenTreeTable'; import RowExpansionIcon from '../RowExpansionIcon'; import { TableHoverCard } from '../TableHoverCard'; @@ -214,7 +216,8 @@ export default function BuildLineTable({ name: 'tracked', label: t`Tracked`, description: t`Show tracked lines` - } + }, + PartCategoryFilter() ]; }, []); @@ -327,6 +330,13 @@ export default function BuildLineTable({ sortable: false, title: t`IPN` }, + CategoryColumn({ + accessor: 'category_detail', + defaultVisible: false, + switchable: true, + sortable: true, + ordering: 'category' + }), DescriptionColumn({ accessor: 'part_detail.description' }), @@ -947,6 +957,7 @@ export default function BuildLineTable({ ...params, build: build.pk, assembly_detail: false, + category_detail: true, part_detail: true }, tableActions: tableActions,