mirror of
https://github.com/inventree/InvenTree.git
synced 2026-07-17 20:23:50 +00:00
[feature] Consumable part (#12295)
* Add "consumable" field to the Part model * Add frontend integration * Add badge * Add docs * Updated docs * Add API filtering for new field * Adjust API filters * Update backend logic * Adjust frontend * Additional unit tests * Update API version * update test * Add consumable icon --------- Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
@@ -103,6 +103,9 @@ export function usePartFields({
|
||||
setVirtual(value);
|
||||
}
|
||||
},
|
||||
consumable: {
|
||||
default: false
|
||||
},
|
||||
locked: {},
|
||||
active: {},
|
||||
starred: {
|
||||
|
||||
@@ -83,6 +83,7 @@ import {
|
||||
type IconProps,
|
||||
IconQrcode,
|
||||
IconQuestionMark,
|
||||
IconRecycle,
|
||||
IconRefresh,
|
||||
IconRulerMeasure,
|
||||
IconSearch,
|
||||
@@ -207,6 +208,7 @@ const icons: InvenTreeIconType = {
|
||||
purchaseable: IconShoppingCart,
|
||||
saleable: IconCurrencyDollar,
|
||||
virtual: IconWorldCode,
|
||||
consumable: IconRecycle,
|
||||
inactive: IconX,
|
||||
part: IconBox,
|
||||
supplier_part: IconPackageImport,
|
||||
|
||||
@@ -549,6 +549,11 @@ export default function PartDetail() {
|
||||
name: 'virtual',
|
||||
label: t`Virtual Part`
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'consumable',
|
||||
label: t`Consumable Part`
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'starred',
|
||||
@@ -1002,10 +1007,16 @@ export default function PartDetail() {
|
||||
key='inactive'
|
||||
/>,
|
||||
<DetailsBadge
|
||||
label={t`Virtual Part`}
|
||||
label={t`Virtual`}
|
||||
color='cyan.4'
|
||||
visible={part.virtual}
|
||||
key='virtual'
|
||||
/>,
|
||||
<DetailsBadge
|
||||
label={t`Consumable`}
|
||||
color='cyan.4'
|
||||
visible={part.consumable}
|
||||
key='consumable'
|
||||
/>
|
||||
];
|
||||
}, [partRequirements, partRequirementsQuery.isFetching, part]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ActionButton } from '@lib/components/ActionButton';
|
||||
import { ProgressBar } from '@lib/components/ProgressBar';
|
||||
import { RowEditAction, RowViewAction } from '@lib/components/RowActions';
|
||||
import { YesNoButton } from '@lib/components/YesNoButton';
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
@@ -10,7 +11,7 @@ import useTable from '@lib/hooks/UseTable';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import type { RowAction, TableColumn } from '@lib/types/Tables';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { Alert, Group, Paper, Text } from '@mantine/core';
|
||||
import { Alert, Center, Group, Paper, Text } from '@mantine/core';
|
||||
import {
|
||||
IconArrowRight,
|
||||
IconCircleCheck,
|
||||
@@ -54,6 +55,16 @@ import { InvenTreeTable } from '../InvenTreeTable';
|
||||
import RowExpansionIcon from '../RowExpansionIcon';
|
||||
import { TableHoverCard } from '../TableHoverCard';
|
||||
|
||||
/**
|
||||
* Return true if the given build line record is "effectively consumable" -
|
||||
* i.e. either the BOM line itself, or the underlying part, is marked as consumable.
|
||||
*/
|
||||
function isLineConsumable(record: any): boolean {
|
||||
return (
|
||||
!!record?.bom_item_detail?.consumable || !!record?.part_detail?.consumable
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a sub-table of allocated stock against a particular build line.
|
||||
*
|
||||
@@ -366,7 +377,12 @@ export default function BuildLineTable({
|
||||
ordering: 'consumable',
|
||||
filter: 'consumable',
|
||||
hidden: hasOutput,
|
||||
defaultVisible: false
|
||||
defaultVisible: false,
|
||||
render: (record: any) => (
|
||||
<Center>
|
||||
<YesNoButton value={isLineConsumable(record)} />
|
||||
</Center>
|
||||
)
|
||||
}),
|
||||
BooleanColumn({
|
||||
accessor: 'bom_item_detail.allow_variants',
|
||||
@@ -499,7 +515,7 @@ export default function BuildLineTable({
|
||||
hidden: !isActive,
|
||||
minWidth: 125,
|
||||
render: (record: any) => {
|
||||
if (record?.bom_item_detail?.consumable) {
|
||||
if (isLineConsumable(record)) {
|
||||
return (
|
||||
<Text
|
||||
size='sm'
|
||||
@@ -545,7 +561,7 @@ export default function BuildLineTable({
|
||||
hidden: !!output?.pk,
|
||||
minWidth: 125,
|
||||
render: (record: any) => {
|
||||
return record?.bom_item_detail?.consumable ? (
|
||||
return isLineConsumable(record) ? (
|
||||
<Text
|
||||
size='sm'
|
||||
style={{ fontStyle: 'italic' }}
|
||||
@@ -747,7 +763,7 @@ export default function BuildLineTable({
|
||||
(record: any): RowAction[] => {
|
||||
const part = record.part_detail ?? {};
|
||||
const in_production = build.status == buildStatus.PRODUCTION;
|
||||
const consumable: boolean = record.bom_item_detail?.consumable ?? false;
|
||||
const consumable: boolean = isLineConsumable(record);
|
||||
const trackable: boolean = part?.trackable ?? false;
|
||||
|
||||
const hasOutput: boolean = !!output?.pk;
|
||||
@@ -907,7 +923,7 @@ export default function BuildLineTable({
|
||||
onClick={() => {
|
||||
let rows = table.selectedRecords
|
||||
.filter((r) => r.allocatedQuantity < r.requiredQuantity)
|
||||
.filter((r) => !r.bom_item_detail?.consumable);
|
||||
.filter((r) => !isLineConsumable(r));
|
||||
|
||||
if (hasOutput) {
|
||||
rows = rows.filter((r) => r.trackable);
|
||||
|
||||
@@ -216,6 +216,10 @@ function partTableColumns(): TableColumn[] {
|
||||
accessor: 'virtual',
|
||||
defaultVisible: false
|
||||
}),
|
||||
BooleanColumn({
|
||||
accessor: 'consumable',
|
||||
defaultVisible: false
|
||||
}),
|
||||
LinkColumn({})
|
||||
];
|
||||
}
|
||||
|
||||
@@ -104,6 +104,12 @@ export function PartTableFilters(): TableFilter[] {
|
||||
description: t`Filter by parts which are virtual`,
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'consumable',
|
||||
label: t`Consumable`,
|
||||
description: t`Filter by parts which are consumable`,
|
||||
type: 'boolean'
|
||||
},
|
||||
{
|
||||
name: 'is_template',
|
||||
label: t`Is Template`,
|
||||
|
||||
Reference in New Issue
Block a user