mirror of
https://github.com/inventree/InvenTree.git
synced 2025-09-13 22:21:37 +00:00
Virtual parts enhancements (#10257)
* Prevent virtual parts from being linked in a BuildOrder * Hide "stock" tab for virtual parts * Filter out virtual parts when creating a new stock item * Support virtual parts in sales orders * Add 'virtual' filter for BomItem * Hide stock badges for virtual parts * Tweak PartDetail page * docs * Adjust completion logic for SalesOrder * Fix backend filter * Remove restriction * Adjust table * Fix for "pending_line_items" * Hide more panels for "Virtual" part * Add badge for "virtual" part * Bump API version * Fix docs link
This commit is contained in:
@@ -103,6 +103,7 @@ export function useStockFields({
|
||||
value: partId || partInstance?.pk,
|
||||
disabled: !create,
|
||||
filters: {
|
||||
virtual: false,
|
||||
active: create ? true : undefined
|
||||
},
|
||||
onValueChange: (value, record) => {
|
||||
|
@@ -532,7 +532,8 @@ export default function PartDetail() {
|
||||
type: 'number',
|
||||
name: 'total_in_stock',
|
||||
unit: part.units,
|
||||
label: t`In Stock`
|
||||
label: t`In Stock`,
|
||||
hidden: part.virtual
|
||||
},
|
||||
{
|
||||
type: 'progressbar',
|
||||
@@ -540,7 +541,7 @@ export default function PartDetail() {
|
||||
total: data.total_in_stock,
|
||||
progress: data.unallocated,
|
||||
label: t`Available Stock`,
|
||||
hidden: data.total_in_stock == data.unallocated
|
||||
hidden: part.virtual || data.total_in_stock == data.unallocated
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
@@ -803,6 +804,7 @@ export default function PartDetail() {
|
||||
name: 'stock',
|
||||
label: t`Stock`,
|
||||
icon: <IconPackages />,
|
||||
hidden: part.virtual || !user.hasViewRole(UserRoles.stock),
|
||||
content: part.pk ? (
|
||||
<StockItemTable
|
||||
tableName='part-stock'
|
||||
@@ -828,7 +830,7 @@ export default function PartDetail() {
|
||||
name: 'allocations',
|
||||
label: t`Allocations`,
|
||||
icon: <IconBookmarks />,
|
||||
hidden: !part.component && !part.salable,
|
||||
hidden: (!part.component && !part.salable) || part.virtual,
|
||||
content: part.pk ? <PartAllocationPanel part={part} /> : <Skeleton />
|
||||
},
|
||||
{
|
||||
@@ -915,6 +917,8 @@ export default function PartDetail() {
|
||||
<Skeleton />
|
||||
),
|
||||
hidden:
|
||||
part.virtual ||
|
||||
!user.hasViewRole(UserRoles.stock) ||
|
||||
!globalSettings.isSet('STOCKTAKE_ENABLE') ||
|
||||
!userSettings.isSet('DISPLAY_STOCKTAKE_TAB')
|
||||
},
|
||||
@@ -973,7 +977,7 @@ export default function PartDetail() {
|
||||
? 'green'
|
||||
: 'orange'
|
||||
}
|
||||
visible={partRequirements.total_stock > 0}
|
||||
visible={!part.virtual && partRequirements.total_stock > 0}
|
||||
key='in_stock'
|
||||
/>,
|
||||
<DetailsBadge
|
||||
@@ -981,13 +985,14 @@ export default function PartDetail() {
|
||||
color='yellow'
|
||||
key='available_stock'
|
||||
visible={
|
||||
!part.virtual &&
|
||||
partRequirements.unallocated_stock != partRequirements.total_stock
|
||||
}
|
||||
/>,
|
||||
<DetailsBadge
|
||||
label={t`No Stock`}
|
||||
color='orange'
|
||||
visible={partRequirements.total_stock == 0}
|
||||
visible={!part.virtual && partRequirements.total_stock == 0}
|
||||
key='no_stock'
|
||||
/>,
|
||||
<DetailsBadge
|
||||
@@ -1013,6 +1018,12 @@ export default function PartDetail() {
|
||||
color='red'
|
||||
visible={!part.active}
|
||||
key='inactive'
|
||||
/>,
|
||||
<DetailsBadge
|
||||
label={t`Virtual Part`}
|
||||
color='cyan.4'
|
||||
visible={part.virtual}
|
||||
key='virtual'
|
||||
/>
|
||||
];
|
||||
}, [partRequirements, partRequirementsQuery.isFetching, part]);
|
||||
@@ -1143,6 +1154,7 @@ export default function PartDetail() {
|
||||
<ActionDropdown
|
||||
tooltip={t`Stock Actions`}
|
||||
icon={<IconPackages />}
|
||||
hidden={part.virtual || !user.hasViewRole(UserRoles.stock)}
|
||||
actions={[
|
||||
...stockAdjustActions.menuActions,
|
||||
{
|
||||
|
@@ -137,6 +137,11 @@ export function BomTable({
|
||||
DescriptionColumn({
|
||||
accessor: 'sub_part_detail.description'
|
||||
}),
|
||||
BooleanColumn({
|
||||
accessor: 'sub_part_detail.virtual',
|
||||
defaultVisible: false,
|
||||
title: t`Virtual Part`
|
||||
}),
|
||||
ReferenceColumn({
|
||||
switchable: true
|
||||
}),
|
||||
@@ -404,6 +409,11 @@ export function BomTable({
|
||||
label: t`Assembled Part`,
|
||||
description: t`Show assembled items`
|
||||
},
|
||||
{
|
||||
name: 'sub_part_virtual',
|
||||
label: t`Virtual Part`,
|
||||
description: t`Show virtual items`
|
||||
},
|
||||
{
|
||||
name: 'available_stock',
|
||||
label: t`Available Stock`,
|
||||
|
@@ -82,10 +82,12 @@ export default function SalesOrderLineItemTable({
|
||||
render: (record: any) => {
|
||||
return (
|
||||
<Group wrap='nowrap'>
|
||||
<RowExpansionIcon
|
||||
enabled={record.allocated}
|
||||
expanded={table.isRowExpanded(record.pk)}
|
||||
/>
|
||||
{record.part_detail?.virtual || (
|
||||
<RowExpansionIcon
|
||||
enabled={record.allocated}
|
||||
expanded={table.isRowExpanded(record.pk)}
|
||||
/>
|
||||
)}
|
||||
<RenderPartColumn part={record.part_detail} />
|
||||
</Group>
|
||||
);
|
||||
@@ -133,6 +135,10 @@ export default function SalesOrderLineItemTable({
|
||||
accessor: 'stock',
|
||||
title: t`Available Stock`,
|
||||
render: (record: any) => {
|
||||
if (record.part_detail?.virtual) {
|
||||
return <Text size='sm' fs='italic'>{t`Virtual part`}</Text>;
|
||||
}
|
||||
|
||||
const part_stock = record?.available_stock ?? 0;
|
||||
const variant_stock = record?.available_variant_stock ?? 0;
|
||||
const available = part_stock + variant_stock;
|
||||
@@ -186,24 +192,36 @@ export default function SalesOrderLineItemTable({
|
||||
{
|
||||
accessor: 'allocated',
|
||||
sortable: true,
|
||||
render: (record: any) => (
|
||||
<ProgressBar
|
||||
progressLabel={true}
|
||||
value={record.allocated}
|
||||
maximum={record.quantity}
|
||||
/>
|
||||
)
|
||||
render: (record: any) => {
|
||||
if (record.part_detail?.virtual) {
|
||||
return <Text size='sm' fs='italic'>{t`Virtual part`}</Text>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ProgressBar
|
||||
progressLabel={true}
|
||||
value={record.allocated}
|
||||
maximum={record.quantity}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
accessor: 'shipped',
|
||||
sortable: true,
|
||||
render: (record: any) => (
|
||||
<ProgressBar
|
||||
progressLabel={true}
|
||||
value={record.shipped}
|
||||
maximum={record.quantity}
|
||||
/>
|
||||
)
|
||||
render: (record: any) => {
|
||||
if (record.part_detail?.virtual) {
|
||||
return <Text size='sm' fs='italic'>{t`Virtual part`}</Text>;
|
||||
}
|
||||
|
||||
return (
|
||||
<ProgressBar
|
||||
progressLabel={true}
|
||||
value={record.shipped}
|
||||
maximum={record.quantity}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
accessor: 'notes'
|
||||
@@ -371,6 +389,7 @@ export default function SalesOrderLineItemTable({
|
||||
const rowActions = useCallback(
|
||||
(record: any): RowAction[] => {
|
||||
const allocated = (record?.allocated ?? 0) > (record?.quantity ?? 0);
|
||||
const virtual = record?.part_detail?.virtual ?? false;
|
||||
|
||||
return [
|
||||
RowViewAction({
|
||||
@@ -383,6 +402,7 @@ export default function SalesOrderLineItemTable({
|
||||
{
|
||||
hidden:
|
||||
allocated ||
|
||||
virtual ||
|
||||
!editable ||
|
||||
!user.hasChangeRole(UserRoles.sales_order),
|
||||
title: t`Allocate Stock`,
|
||||
@@ -397,6 +417,7 @@ export default function SalesOrderLineItemTable({
|
||||
hidden:
|
||||
!record?.part_detail?.trackable ||
|
||||
allocated ||
|
||||
virtual ||
|
||||
!editable ||
|
||||
!user.hasChangeRole(UserRoles.sales_order),
|
||||
title: t`Allocate serials`,
|
||||
@@ -414,6 +435,7 @@ export default function SalesOrderLineItemTable({
|
||||
{
|
||||
hidden:
|
||||
allocated ||
|
||||
virtual ||
|
||||
!user.hasAddRole(UserRoles.build) ||
|
||||
!record?.part_detail?.assembly,
|
||||
title: t`Build stock`,
|
||||
@@ -431,6 +453,7 @@ export default function SalesOrderLineItemTable({
|
||||
{
|
||||
hidden:
|
||||
allocated ||
|
||||
virtual ||
|
||||
!user.hasAddRole(UserRoles.purchase_order) ||
|
||||
!record?.part_detail?.purchaseable,
|
||||
title: t`Order stock`,
|
||||
@@ -472,6 +495,9 @@ export default function SalesOrderLineItemTable({
|
||||
return {
|
||||
allowMultiple: true,
|
||||
expandable: ({ record }: { record: any }) => {
|
||||
if (record?.part_detail?.virtual) {
|
||||
return false;
|
||||
}
|
||||
return table.isRowExpanded(record.pk) || record.allocated > 0;
|
||||
},
|
||||
content: ({ record }: { record: any }) => {
|
||||
|
Reference in New Issue
Block a user