2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 11:36:44 +00:00

[PUI] BOM table updates (#7561)

* Update BOM table for PUI

- Display "validated" column
- Allow ordering by "validated" column

* Update table rowActions

* Add row action to validate BOM line

* Enable bulk deletion of BOM items
This commit is contained in:
Oliver 2024-07-05 16:39:54 +10:00 committed by GitHub
parent 13dbfd0b14
commit 58f12f5ce5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 41 deletions

View File

@ -1872,6 +1872,7 @@ class BomList(BomMixin, ListCreateDestroyAPIView):
'inherited',
'optional',
'consumable',
'validated',
'pricing_min',
'pricing_max',
'pricing_min_total',

View File

@ -1458,7 +1458,7 @@ class BomItemSerializer(InvenTree.serializers.InvenTreeModelSerializer):
- This saves a bunch of database requests
"""
part_detail = kwargs.pop('part_detail', False)
sub_part_detail = kwargs.pop('sub_part_detail', False)
sub_part_detail = kwargs.pop('sub_part_detail', True)
pricing = kwargs.pop('pricing', True)
super().__init__(*args, **kwargs)

View File

@ -60,6 +60,7 @@ export enum ApiEndpoints {
build_line_list = 'build/line/',
bom_list = 'bom/',
bom_item_validate = 'bom/:id/validate/',
// Part API endpoints
part_list = 'part/',

View File

@ -478,8 +478,8 @@ export function InvenTreeTable<T = any>({
}, [data]);
// Callback function to delete the selected records in the table
const deleteSelectedRecords = useCallback(() => {
if (tableState.selectedRecords.length == 0) {
const deleteSelectedRecords = useCallback((ids: number[]) => {
if (ids.length == 0) {
// Ignore if no records are selected
return;
}
@ -502,15 +502,10 @@ export function InvenTreeTable<T = any>({
color: 'red'
},
onConfirm: () => {
// Delete the selected records
let selection = tableState.selectedRecords.map(
(record) => record.pk ?? record.id
);
api
.delete(url, {
data: {
items: selection
items: ids
}
})
.then((_response) => {
@ -535,7 +530,7 @@ export function InvenTreeTable<T = any>({
});
}
});
}, [tableState.selectedRecords]);
}, []);
// Callback when a row is clicked
const handleRowClick = useCallback(
@ -609,7 +604,7 @@ export function InvenTreeTable<T = any>({
icon={<IconTrash />}
color="red"
tooltip={t`Delete selected records`}
onClick={deleteSelectedRecords}
onClick={() => deleteSelectedRecords(tableState.selectedIds)}
/>
)}
{tableProps.tableActions?.map((group, idx) => (

View File

@ -1,5 +1,6 @@
import { t } from '@lingui/macro';
import { Group, Text } from '@mantine/core';
import { showNotification } from '@mantine/notifications';
import {
IconArrowRight,
IconCircleCheck,
@ -8,6 +9,7 @@ import {
import { ReactNode, useCallback, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { api } from '../../App';
import { AddItemButton } from '../../components/buttons/AddItemButton';
import { YesNoButton } from '../../components/buttons/YesNoButton';
import { Thumbnail } from '../../components/images/Thumbnail';
@ -33,7 +35,7 @@ import {
} from '../ColumnRenderers';
import { TableFilter } from '../Filter';
import { InvenTreeTable } from '../InvenTreeTable';
import { RowAction, RowDeleteAction, RowEditAction } from '../RowActions';
import { RowDeleteAction, RowEditAction } from '../RowActions';
import { TableHoverCard } from '../TableHoverCard';
// Calculate the total stock quantity available for a given BomItem
@ -146,6 +148,9 @@ export function BomTable({
// TODO: Custom renderer for this column
// TODO: See bom.js for existing implementation
}),
BooleanColumn({
accessor: 'validated'
}),
{
accessor: 'price_range',
title: t`Unit Price`,
@ -339,6 +344,29 @@ export function BomTable({
table: table
});
const validateBomItem = useCallback((record: any) => {
const url = apiUrl(ApiEndpoints.bom_item_validate, record.pk);
api
.patch(url, { valid: true })
.then((_response) => {
showNotification({
title: t`Success`,
message: t`BOM item validated`,
color: 'green'
});
table.refreshTable();
})
.catch((_error) => {
showNotification({
title: t`Error`,
message: t`Failed to validate BOM item`,
color: 'red'
});
});
}, []);
const rowActions = useCallback(
(record: any) => {
// If this BOM item is defined for a *different* parent, then it cannot be edited
@ -352,37 +380,27 @@ export function BomTable({
];
}
let actions: RowAction[] = [];
// TODO: Enable BomItem validation
actions.push({
title: t`Validate BOM line`,
color: 'green',
hidden: record.validated || !user.hasChangeRole(UserRoles.part),
icon: <IconCircleCheck />
});
// TODO: Enable editing of substitutes
actions.push({
title: t`Edit Substitutes`,
color: 'blue',
hidden: !user.hasChangeRole(UserRoles.part),
icon: <IconSwitch3 />
});
// Action on edit
actions.push(
return [
{
title: t`Validate BOM Line`,
color: 'green',
hidden: record.validated || !user.hasChangeRole(UserRoles.part),
icon: <IconCircleCheck />,
onClick: () => validateBomItem(record)
},
RowEditAction({
hidden: !user.hasChangeRole(UserRoles.part),
onClick: () => {
setSelectedBomItem(record.pk);
editBomItem.open();
}
})
);
// Action on delete
actions.push(
}),
{
title: t`Edit Substitutes`,
color: 'blue',
hidden: !user.hasChangeRole(UserRoles.part),
icon: <IconSwitch3 />
},
RowDeleteAction({
hidden: !user.hasDeleteRole(UserRoles.part),
onClick: () => {
@ -390,9 +408,7 @@ export function BomTable({
deleteBomItem.open();
}
})
);
return actions;
];
},
[partId, user]
);
@ -427,7 +443,9 @@ export function BomTable({
tableFilters: tableFilters,
modelType: ModelType.part,
modelField: 'sub_part',
rowActions: rowActions
rowActions: rowActions,
enableSelection: true,
enableBulkDelete: true
}}
/>
</>