2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-05-09 11:08:54 +00:00

BOM Ruleset (#11825)

* Add BOM role

* Adjust UI permissions

* Adjust docs

* Add data migratoin

* Specify role for BOM validation

* Tweak old migrati

* Fix role_required

* Update API version and CHANGELOG

Co-authored-by: Copilot <copilot@github.com>

* Update unit tests

Co-authored-by: Copilot <copilot@github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Oliver
2026-04-28 12:29:57 +10:00
committed by GitHub
parent 6e4ffcb6d2
commit 2b6952eabd
12 changed files with 107 additions and 34 deletions
+1
View File
@@ -5,6 +5,7 @@ import { t } from '@lingui/core/macro';
*/
export enum UserRoles {
admin = 'admin',
bom = 'bom',
build = 'build',
part = 'part',
part_category = 'part_category',
+12 -9
View File
@@ -164,6 +164,8 @@ function BomValidationInformation({
bomInformation: UseInstanceResult;
partId: number;
}) {
const user = useUserState();
const [taskId, setTaskId] = useState<string>('');
useBackgroundTask({
@@ -232,14 +234,15 @@ function BomValidationInformation({
<>
{validateBom.modal}
<Group gap='xs' justify='flex-end'>
{!bomInformation.instance?.bom_validated && (
<ActionButton
icon={<IconCircleCheck />}
color='green'
tooltip={t`Validate BOM`}
onClick={validateBom.open}
/>
)}
{!bomInformation.instance?.bom_validated &&
user.hasChangeRole(UserRoles.bom) && (
<ActionButton
icon={<IconCircleCheck />}
color='green'
tooltip={t`Validate BOM`}
onClick={validateBom.open}
/>
)}
<HoverCard position='bottom-end'>
<HoverCard.Target>
<ActionIcon
@@ -811,7 +814,7 @@ export default function PartDetail() {
/>
),
icon: <IconListTree />,
hidden: !part.assembly,
hidden: !part.assembly || !user.hasViewRole(UserRoles.bom),
content: part?.pk ? (
<Stack gap='xs'>
{bomInformation.isLoaded &&
+7 -7
View File
@@ -607,14 +607,14 @@ export function BomTable({
hidden:
partLocked ||
record.validated ||
!user.hasChangeRole(UserRoles.part),
!user.hasChangeRole(UserRoles.bom),
icon: <IconCircleCheck />,
onClick: () => {
validateBomItem(record);
}
},
RowEditAction({
hidden: partLocked || !user.hasChangeRole(UserRoles.part),
hidden: partLocked || !user.hasChangeRole(UserRoles.bom),
onClick: () => {
setSelectedBomItem(record);
editBomItem.open();
@@ -623,7 +623,7 @@ export function BomTable({
{
title: t`Edit Substitutes`,
color: 'blue',
hidden: partLocked || !user.hasAddRole(UserRoles.part),
hidden: partLocked || !user.hasAddRole(UserRoles.bom),
icon: <IconSwitch3 />,
onClick: () => {
setSelectedBomItem(record);
@@ -631,7 +631,7 @@ export function BomTable({
}
},
RowDeleteAction({
hidden: partLocked || !user.hasDeleteRole(UserRoles.part),
hidden: partLocked || !user.hasDeleteRole(UserRoles.bom),
onClick: () => {
setSelectedBomItem(record);
deleteBomItem.open();
@@ -649,7 +649,7 @@ export function BomTable({
tooltip={t`Add BOM Items`}
position='bottom-start'
icon={<IconPlus />}
hidden={!isEditing || partLocked || !user.hasAddRole(UserRoles.part)}
hidden={!isEditing || partLocked || !user.hasAddRole(UserRoles.bom)}
actions={[
{
name: t`Add BOM Item`,
@@ -667,7 +667,7 @@ export function BomTable({
/>,
<ActionButton
key='edit-bom'
hidden={partLocked || !user.hasChangeRole(UserRoles.part) || isEditing}
hidden={partLocked || !user.hasChangeRole(UserRoles.bom) || isEditing}
tooltip={t`Edit BOM`}
icon={<IconEdit />}
onClick={() => {
@@ -731,7 +731,7 @@ export function BomTable({
rowActions: isEditing ? rowActions : undefined,
enableSelection: isEditing && !partLocked,
enableBulkDelete:
isEditing && !partLocked && user.hasDeleteRole(UserRoles.part),
isEditing && !partLocked && user.hasDeleteRole(UserRoles.bom),
enableDownload: true,
rowExpansion: isEditing ? undefined : rowExpansion
}}