2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-24 18:07:38 +00:00

Partial build output complete (#10499)

* Handle partial completion of build output

* Add 'quantity' field to BuildOutputComplete API endpoint

* Allow partial scrapping of build outputs

* Adjust column text

* Adjust "complete build output" form

* Change order of operations when completing build output

- Run validation checks *before* potentially splitting stock item

* Extract quantity from serializer

* Documentation

- Update screenshots
- Add note on partial completion
- Add note on partial scrapping

* Update CHANGELOG.md

* Update API version

* Add unit test for partial scrapping

* Tweak text

* Unit test for partial output completion

* Fix validation check for quantity field

* Adjust playwright tests
This commit is contained in:
Oliver
2025-10-06 14:30:07 +11:00
committed by GitHub
parent 946418e175
commit 5743e22501
11 changed files with 215 additions and 25 deletions

View File

@@ -236,7 +236,7 @@ function BuildOutputFormRow({
props: TableFieldRowProps;
record: any;
}>) {
const serial = useMemo(() => {
const stockItemColumn = useMemo(() => {
if (record.serial) {
return `# ${record.serial}`;
} else {
@@ -244,15 +244,39 @@ function BuildOutputFormRow({
}
}, [record]);
const quantityColumn = useMemo(() => {
// Serialized output - quantity cannot be changed
if (record.serial) {
return '1';
}
// Non-serialized output - quantity can be changed
return (
<StandaloneField
fieldName='quantity'
fieldDefinition={{
field_type: 'number',
required: true,
value: props.item.quantity,
onValueChange: (value: any) => {
props.changeFn(props.idx, 'quantity', value);
}
}}
error={props.rowErrors?.quantity?.message}
/>
);
}, [props, record]);
return (
<>
<Table.Tr>
<Table.Td>
<RenderPartColumn part={record.part_detail} />
</Table.Td>
<Table.Td>{stockItemColumn}</Table.Td>
<Table.Td>
<TableFieldErrorWrapper props={props} errorKey='output'>
{serial}
{quantityColumn}
</TableFieldErrorWrapper>
</Table.Td>
<Table.Td>{record.batch}</Table.Td>
@@ -297,7 +321,8 @@ export function useCompleteBuildOutputsForm({
field_type: 'table',
value: outputs.map((output: any) => {
return {
output: output.pk
output: output.pk,
quantity: output.quantity
};
}),
modelRenderer: (row: TableFieldRowProps) => {
@@ -309,6 +334,7 @@ export function useCompleteBuildOutputsForm({
headers: [
{ title: t`Part` },
{ title: t`Build Output` },
{ title: t`Quantity to Complete`, style: { width: '200px' } },
{ title: t`Batch` },
{ title: t`Status` },
{ title: '', style: { width: '50px' } }
@@ -382,7 +408,8 @@ export function useScrapBuildOutputsForm({
},
headers: [
{ title: t`Part` },
{ title: t`Stock Item` },
{ title: t`Build Output` },
{ title: t`Quantity to Scrap`, style: { width: '200px' } },
{ title: t`Batch` },
{ title: t`Status` },
{ title: '', style: { width: '50px' } }

View File

@@ -206,7 +206,8 @@ test('Build Order - Build Outputs', async ({ browser }) => {
await page.getByLabel('text-field-batch_code').fill('BATCH12345');
await page.getByLabel('related-field-location').click();
await page.getByText('Reel Storage').click();
await page.getByLabel('related-field-location').fill('Reel');
await page.getByText('- Electronics Lab/Reel Storage').click();
await page.getByRole('button', { name: 'Submit' }).click();
// Should be an error as the number of serial numbers doesn't match the quantity
@@ -246,6 +247,20 @@ test('Build Order - Build Outputs', async ({ browser }) => {
await page.waitForTimeout(250);
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByText('Build outputs have been completed').waitFor();
// Check for expected UI elements in the "scrap output" dialog
const cell3 = await page.getByRole('cell', { name: '16' });
const row3 = await getRowFromCell(cell3);
await row3.getByLabel(/row-action-menu-/i).click();
await page.getByRole('menuitem', { name: 'Scrap' }).click();
await page
.getByText(
'Selected build outputs will be completed, but marked as scrapped'
)
.waitFor();
await page.getByRole('cell', { name: 'Quantity: 16' }).waitFor();
await page.getByRole('button', { name: 'Cancel', exact: true }).click();
});
test('Build Order - Allocation', async ({ browser }) => {