diff --git a/docs/docs/manufacturing/build.md b/docs/docs/manufacturing/build.md index 0b8ae2fb0c..ae4b9bf8e9 100644 --- a/docs/docs/manufacturing/build.md +++ b/docs/docs/manufacturing/build.md @@ -119,14 +119,33 @@ The *Build Details* panel provides an overview of the Build Order: {{ image ("build/build_panel_details.png", title="Build Details") }} -### Line Items +### Required Parts -The *Line Items* panel displays all the line items (as defined by the [bill of materials](./bom.md)) required to complete the build order. +The *Required Parts* panel displays all the line items (as defined by the [bill of materials](./bom.md)) required to complete the build order. {{ image("build/build_panel_line_items.png", title="Line Items") }} The allocation table (as shown above) provides an interface to allocate required stock, and also shows the stock allocation progress for each line item in the build. +### Allocated Stock + +The *Allocated Stock* tab displays all stock items which have been *allocated* to this build order. These stock items are reserved for this build, and will be consumed when the build is completed: + +{{ image("build/allocated_stock_table.png", title="Allocated Stock Table") }} + +!!! info "No BOM" + If the part being built does not have a BOM, then the *Allocated Stock* tab will not be displayed. + +### Consumed Stock + +The *Consumed Stock* tab displays all stock items which have been *consumed* by this build order. These stock items remain in the database after the build order has been completed, but are no longer available for use. + +- [Tracked stock items](./allocate.md#tracked-stock) are consumed by specific build outputs +- [Untracked stock items](./allocate.md#untracked-stock) are consumed by the build order + +!!! info "No BOM" + If the part being built does not have a BOM, then the *Consumed Stock* tab will not be displayed. + ### Incomplete Outputs The *Incomplete Outputs* panel shows the list of in-progress [build outputs](./output.md) (created stock items) associated with this build. @@ -144,19 +163,6 @@ The *Incomplete Outputs* panel shows the list of in-progress [build outputs](./o This panel displays all the completed build outputs (stock items) which have been created by this build order: -### Allocated Stock - -The *Allocated Stock* tab displays all stock items which have been *allocated* to this build order. These stock items are reserved for this build, and will be consumed when the build is completed: - -{{ image("build/allocated_stock_table.png", title="Allocated Stock Table") }} - -### Consumed Stock - -The *Consumed Stock* tab displays all stock items which have been *consumed* by this build order. These stock items remain in the database after the build order has been completed, but are no longer available for use. - -- [Tracked stock items](./allocate.md#tracked-stock) are consumed by specific build outputs -- [Untracked stock items](./allocate.md#untracked-stock) are consumed by the build order - ### Child Builds If there exist any build orders which are *children* of the selected build order, they are displayed in the *Child Builds* tab: diff --git a/src/backend/InvenTree/build/api.py b/src/backend/InvenTree/build/api.py index 42e5f4f1b2..ad0f229443 100644 --- a/src/backend/InvenTree/build/api.py +++ b/src/backend/InvenTree/build/api.py @@ -532,8 +532,10 @@ class BuildLineEndpoint: try: params = self.request.query_params + kwargs['bom_item_detail'] = str2bool(params.get('bom_item_detail', True)) kwargs['part_detail'] = str2bool(params.get('part_detail', True)) kwargs['build_detail'] = str2bool(params.get('build_detail', False)) + kwargs['allocations'] = str2bool(params.get('allocations', True)) except AttributeError: pass diff --git a/src/backend/InvenTree/build/serializers.py b/src/backend/InvenTree/build/serializers.py index b52192fa99..f16e029b91 100644 --- a/src/backend/InvenTree/build/serializers.py +++ b/src/backend/InvenTree/build/serializers.py @@ -1328,19 +1328,27 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali def __init__(self, *args, **kwargs): """Determine which extra details fields should be included.""" part_detail = kwargs.pop('part_detail', True) + bom_item_detail = kwargs.pop('bom_item_detail', True) build_detail = kwargs.pop('build_detail', True) + allocations = kwargs.pop('allocations', True) super().__init__(*args, **kwargs) if isGeneratingSchema(): return + if not bom_item_detail: + self.fields.pop('bom_item_detail', None) + if not part_detail: self.fields.pop('part_detail', None) if not build_detail: self.fields.pop('build_detail', None) + if not allocations: + self.fields.pop('allocations', None) + # Build info fields build_reference = serializers.CharField( source='build.reference', label=_('Build Reference'), read_only=True diff --git a/src/frontend/src/pages/build/BuildDetail.tsx b/src/frontend/src/pages/build/BuildDetail.tsx index ac850c4f54..646de48483 100644 --- a/src/frontend/src/pages/build/BuildDetail.tsx +++ b/src/frontend/src/pages/build/BuildDetail.tsx @@ -2,6 +2,7 @@ import { t } from '@lingui/core/macro'; import { Alert, Grid, Skeleton, Stack, Text } from '@mantine/core'; import { IconChecklist, + IconCircleCheck, IconClipboardCheck, IconClipboardList, IconInfoCircle, @@ -19,6 +20,7 @@ import { ModelType } from '@lib/enums/ModelType'; import { UserRoles } from '@lib/enums/Roles'; import { apiUrl } from '@lib/functions/Api'; import { getDetailUrl } from '@lib/functions/Navigation'; +import type { ApiFormFieldSet } from '@lib/types/Forms'; import AdminButton from '../../components/buttons/AdminButton'; import PrimaryActionButton from '../../components/buttons/PrimaryActionButton'; import { PrintingActions } from '../../components/buttons/PrintingActions'; @@ -130,6 +132,10 @@ export default function BuildDetail() { endpoint: ApiEndpoints.build_line_list, params: { build: id, + allocations: false, + part_detail: false, + build_detail: false, + bom_item_detail: false, limit: 1 }, disabled: !id, @@ -417,7 +423,8 @@ export default function BuildDetail() { icon: , hidden: build.status == buildStatus.COMPLETE || - build.status == buildStatus.CANCELLED, + build.status == buildStatus.CANCELLED || + (buildLineData?.count ?? 0) <= 0, // Hide if no required parts content: ( , + hidden: (buildLineData?.count ?? 0) <= 0, // Hide if no required parts content: ( { + const hasBom = (buildLineData?.count ?? 0) > 0; + + return { + accept_overallocated: { + hidden: !hasBom + }, + accept_unallocated: { + hidden: !hasBom + }, + accept_incomplete: {} + }; + }, [buildLineData.count]); + const completeOrder = useCreateApiFormModal({ url: apiUrl(ApiEndpoints.build_order_complete, build.pk), title: t`Complete Build Order`, onFormSuccess: refreshInstance, - preFormWarning: t`Mark this order as complete`, + preFormContent: ( + } + title={t`Mark this order as complete`} + /> + ), successMessage: t`Order completed`, - fields: { - accept_overallocated: {}, - accept_unallocated: {}, - accept_incomplete: {} - } + fields: completeOrderFields }); const buildActions = useMemo(() => {