2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-18 02:36:31 +00:00

[UI] Build page tweak (#10027)

* Hide "consumed stock" panel if not required

* Docs updates

* Hide allocation fields if the build has no required parts

* Additional serializer options
This commit is contained in:
Oliver
2025-07-15 18:27:09 +10:00
committed by GitHub
parent 42abc61494
commit 75ab57bc0b
4 changed files with 62 additions and 22 deletions

View File

@@ -119,14 +119,33 @@ The *Build Details* panel provides an overview of the Build Order:
{{ image ("build/build_panel_details.png", title="Build Details") }} {{ 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") }} {{ 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. 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 ### Incomplete Outputs
The *Incomplete Outputs* panel shows the list of in-progress [build outputs](./output.md) (created stock items) associated with this build. 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: 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 ### Child Builds
If there exist any build orders which are *children* of the selected build order, they are displayed in the *Child Builds* tab: If there exist any build orders which are *children* of the selected build order, they are displayed in the *Child Builds* tab:

View File

@@ -532,8 +532,10 @@ class BuildLineEndpoint:
try: try:
params = self.request.query_params 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['part_detail'] = str2bool(params.get('part_detail', True))
kwargs['build_detail'] = str2bool(params.get('build_detail', False)) kwargs['build_detail'] = str2bool(params.get('build_detail', False))
kwargs['allocations'] = str2bool(params.get('allocations', True))
except AttributeError: except AttributeError:
pass pass

View File

@@ -1328,19 +1328,27 @@ class BuildLineSerializer(DataImportExportSerializerMixin, InvenTreeModelSeriali
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
"""Determine which extra details fields should be included.""" """Determine which extra details fields should be included."""
part_detail = kwargs.pop('part_detail', True) part_detail = kwargs.pop('part_detail', True)
bom_item_detail = kwargs.pop('bom_item_detail', True)
build_detail = kwargs.pop('build_detail', True) build_detail = kwargs.pop('build_detail', True)
allocations = kwargs.pop('allocations', True)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if isGeneratingSchema(): if isGeneratingSchema():
return return
if not bom_item_detail:
self.fields.pop('bom_item_detail', None)
if not part_detail: if not part_detail:
self.fields.pop('part_detail', None) self.fields.pop('part_detail', None)
if not build_detail: if not build_detail:
self.fields.pop('build_detail', None) self.fields.pop('build_detail', None)
if not allocations:
self.fields.pop('allocations', None)
# Build info fields # Build info fields
build_reference = serializers.CharField( build_reference = serializers.CharField(
source='build.reference', label=_('Build Reference'), read_only=True source='build.reference', label=_('Build Reference'), read_only=True

View File

@@ -2,6 +2,7 @@ import { t } from '@lingui/core/macro';
import { Alert, Grid, Skeleton, Stack, Text } from '@mantine/core'; import { Alert, Grid, Skeleton, Stack, Text } from '@mantine/core';
import { import {
IconChecklist, IconChecklist,
IconCircleCheck,
IconClipboardCheck, IconClipboardCheck,
IconClipboardList, IconClipboardList,
IconInfoCircle, IconInfoCircle,
@@ -19,6 +20,7 @@ import { ModelType } from '@lib/enums/ModelType';
import { UserRoles } from '@lib/enums/Roles'; import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api'; import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import type { ApiFormFieldSet } from '@lib/types/Forms';
import AdminButton from '../../components/buttons/AdminButton'; import AdminButton from '../../components/buttons/AdminButton';
import PrimaryActionButton from '../../components/buttons/PrimaryActionButton'; import PrimaryActionButton from '../../components/buttons/PrimaryActionButton';
import { PrintingActions } from '../../components/buttons/PrintingActions'; import { PrintingActions } from '../../components/buttons/PrintingActions';
@@ -130,6 +132,10 @@ export default function BuildDetail() {
endpoint: ApiEndpoints.build_line_list, endpoint: ApiEndpoints.build_line_list,
params: { params: {
build: id, build: id,
allocations: false,
part_detail: false,
build_detail: false,
bom_item_detail: false,
limit: 1 limit: 1
}, },
disabled: !id, disabled: !id,
@@ -417,7 +423,8 @@ export default function BuildDetail() {
icon: <IconList />, icon: <IconList />,
hidden: hidden:
build.status == buildStatus.COMPLETE || build.status == buildStatus.COMPLETE ||
build.status == buildStatus.CANCELLED, build.status == buildStatus.CANCELLED ||
(buildLineData?.count ?? 0) <= 0, // Hide if no required parts
content: ( content: (
<BuildAllocationsPanel <BuildAllocationsPanel
build={build} build={build}
@@ -430,6 +437,7 @@ export default function BuildDetail() {
name: 'consumed-stock', name: 'consumed-stock',
label: t`Consumed Stock`, label: t`Consumed Stock`,
icon: <IconListCheck />, icon: <IconListCheck />,
hidden: (buildLineData?.count ?? 0) <= 0, // Hide if no required parts
content: ( content: (
<StockItemTable <StockItemTable
allowAdd={false} allowAdd={false}
@@ -590,17 +598,33 @@ export default function BuildDetail() {
successMessage: t`Order issued` successMessage: t`Order issued`
}); });
const completeOrderFields: ApiFormFieldSet = useMemo(() => {
const hasBom = (buildLineData?.count ?? 0) > 0;
return {
accept_overallocated: {
hidden: !hasBom
},
accept_unallocated: {
hidden: !hasBom
},
accept_incomplete: {}
};
}, [buildLineData.count]);
const completeOrder = useCreateApiFormModal({ const completeOrder = useCreateApiFormModal({
url: apiUrl(ApiEndpoints.build_order_complete, build.pk), url: apiUrl(ApiEndpoints.build_order_complete, build.pk),
title: t`Complete Build Order`, title: t`Complete Build Order`,
onFormSuccess: refreshInstance, onFormSuccess: refreshInstance,
preFormWarning: t`Mark this order as complete`, preFormContent: (
<Alert
color='green'
icon={<IconCircleCheck />}
title={t`Mark this order as complete`}
/>
),
successMessage: t`Order completed`, successMessage: t`Order completed`,
fields: { fields: completeOrderFields
accept_overallocated: {},
accept_unallocated: {},
accept_incomplete: {}
}
}); });
const buildActions = useMemo(() => { const buildActions = useMemo(() => {