Receive virtual parts (#11627)

* Handle receive of virtual parts

- Update line item quantity
- Do not add any stock

* Add unit test

* Additional unit test

* UI form improvements

* Add playwright test

* Updated playwright tests
This commit is contained in:
Oliver
2026-03-30 19:10:56 +11:00
committed by GitHub
parent b4f230753f
commit dab4319033
7 changed files with 145 additions and 30 deletions
+43 -8
View File
@@ -1,9 +1,12 @@
import { t } from '@lingui/core/macro';
import {
ActionIcon,
Alert,
Container,
Flex,
FocusTrap,
Group,
HoverCard,
Modal,
Table,
TextInput
@@ -15,6 +18,7 @@ import {
IconCoins,
IconCurrencyDollar,
IconHash,
IconInfoCircle,
IconLink,
IconList,
IconNotes,
@@ -488,6 +492,12 @@ function LineItemFormRow({
return text;
}, [location]);
// Handle virtual parts
const virtual = useMemo(
() => record.part_detail?.virtual ?? false,
[record.part_detail]
);
return (
<>
<Modal
@@ -506,14 +516,30 @@ function LineItemFormRow({
</Modal>
<Table.Tr>
<Table.Td>
<Flex gap='sm' align='center'>
<Thumbnail
size={40}
src={record.part_detail.thumbnail}
align='center'
/>
<div>{record.part_detail.name}</div>
</Flex>
<Group gap='xs' justify='space-between'>
<Group gap='xs' justify='left'>
<Thumbnail
size={40}
src={record.part_detail.thumbnail}
align='center'
/>
<div>{record.part_detail.name}</div>
</Group>
{virtual && (
<HoverCard>
<HoverCard.Target>
<ActionIcon color='blue' variant='transparent'>
<IconInfoCircle />
</ActionIcon>
</HoverCard.Target>
<HoverCard.Dropdown>
<Alert color='blue' title={t`Virtual Part`}>
{t`This part is virtual, no physical stock will be received.`}
</Alert>
</HoverCard.Dropdown>
</HoverCard>
)}
</Group>
</Table.Td>
<Table.Td>{record.supplier_part_detail.SKU}</Table.Td>
<Table.Td>
@@ -546,6 +572,7 @@ function LineItemFormRow({
tooltip={t`Set Location`}
tooltipAlignment='top'
variant={locationOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
<ActionButton
size='sm'
@@ -554,6 +581,7 @@ function LineItemFormRow({
tooltip={t`Assign Batch Code`}
tooltipAlignment='top'
variant={batchOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
{trackable && (
<ActionButton
@@ -563,6 +591,7 @@ function LineItemFormRow({
tooltip={t`Assign Serial Numbers`}
tooltipAlignment='top'
variant={serialOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
)}
@@ -574,6 +603,7 @@ function LineItemFormRow({
tooltip={t`Set Expiry Date`}
tooltipAlignment='top'
variant={expiryDateOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
)}
<ActionButton
@@ -583,6 +613,7 @@ function LineItemFormRow({
tooltipAlignment='top'
onClick={() => packagingHandlers.toggle()}
variant={packagingOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
<ActionButton
onClick={() => statusHandlers.toggle()}
@@ -590,6 +621,7 @@ function LineItemFormRow({
tooltip={t`Change Status`}
tooltipAlignment='top'
variant={statusOpen ? 'outline' : 'transparent'}
disabled={virtual}
/>
<ActionButton
icon={<InvenTreeIcon icon='note' />}
@@ -597,6 +629,7 @@ function LineItemFormRow({
tooltipAlignment='top'
variant={noteOpen ? 'outline' : 'transparent'}
onClick={() => noteHandlers.toggle()}
disabled={virtual}
/>
{barcode ? (
<ActionButton
@@ -606,6 +639,7 @@ function LineItemFormRow({
variant='filled'
color='red'
onClick={() => setBarcode(undefined)}
disabled={virtual}
/>
) : (
<ActionButton
@@ -614,6 +648,7 @@ function LineItemFormRow({
tooltipAlignment='top'
variant='transparent'
onClick={() => open()}
disabled={virtual}
/>
)}
</Flex>