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:
@@ -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' } }
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
Reference in New Issue
Block a user