From df00bfb1d33dd1319f7b7b36c9d8377101309dce Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sun, 28 Jun 2026 05:49:44 +0000 Subject: [PATCH] Fix useReceiveLineItems --- src/frontend/src/forms/PurchaseOrderForms.tsx | 82 +++++++++++-------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx index 50824f9a13..d60bb0c36d 100644 --- a/src/frontend/src/forms/PurchaseOrderForms.tsx +++ b/src/frontend/src/forms/PurchaseOrderForms.tsx @@ -349,11 +349,11 @@ function LineItemFormRow({ }>) { // Barcode Modal state const [opened, { open, close }] = useDisclosure(false, { - onClose: () => props.changeFn(props.idx, 'barcode', undefined) + onClose: () => props.changeFn(props.rowId, 'barcode', undefined) }); const [locationOpen, locationHandlers] = useDisclosure(false, { - onClose: () => props.changeFn(props.idx, 'location', undefined) + onClose: () => props.changeFn(props.rowId, 'location', undefined) }); // Is this a trackable part? @@ -366,7 +366,7 @@ function LineItemFormRow({ useEffect(() => { if (!!record.destination) { - props.changeFn(props.idx, 'location', record.destination); + props.changeFn(props.rowId, 'location', record.destination); locationHandlers.open(); } }, [record.destination]); @@ -376,7 +376,7 @@ function LineItemFormRow({ isEnabled: () => batchOpen, onGenerate: (value: any) => { if (value) { - props.changeFn(props.idx, 'batch_code', value); + props.changeFn(props.rowId, 'batch_code', value); } } }); @@ -388,19 +388,19 @@ function LineItemFormRow({ const [packagingOpen, packagingHandlers] = useDisclosure(false, { onClose: () => { - props.changeFn(props.idx, 'packaging', undefined); + props.changeFn(props.rowId, 'packaging', undefined); } }); const [noteOpen, noteHandlers] = useDisclosure(false, { onClose: () => { - props.changeFn(props.idx, 'note', undefined); + props.changeFn(props.rowId, 'note', undefined); } }); const [batchOpen, batchHandlers] = useDisclosure(false, { onClose: () => { - props.changeFn(props.idx, 'batch_code', undefined); + props.changeFn(props.rowId, 'batch_code', undefined); }, onOpen: () => { // Generate a new batch code @@ -413,7 +413,7 @@ function LineItemFormRow({ const [serialOpen, serialHandlers] = useDisclosure(false, { onClose: () => { - props.changeFn(props.idx, 'serial_numbers', undefined); + props.changeFn(props.rowId, 'serial_numbers', undefined); }, onOpen: () => { // Generate new serial numbers @@ -423,7 +423,7 @@ function LineItemFormRow({ quantity: props.item.quantity }); } else { - props.changeFn(props.idx, 'serial_numbers', undefined); + props.changeFn(props.rowId, 'serial_numbers', undefined); } } }); @@ -434,20 +434,20 @@ function LineItemFormRow({ const defaultExpiry = record.part_detail?.default_expiry; if (defaultExpiry !== undefined && defaultExpiry > 0) { props.changeFn( - props.idx, + props.rowId, 'expiry_date', dayjs().add(defaultExpiry, 'day').format('YYYY-MM-DD') ); } }, onClose: () => { - props.changeFn(props.idx, 'expiry_date', undefined); + props.changeFn(props.rowId, 'expiry_date', undefined); } }); // Status value const [statusOpen, statusHandlers] = useDisclosure(false, { - onClose: () => props.changeFn(props.idx, 'status', undefined) + onClose: () => props.changeFn(props.rowId, 'status', undefined) }); // Barcode value @@ -456,7 +456,7 @@ function LineItemFormRow({ // Change form value when state is altered useEffect(() => { - props.changeFn(props.idx, 'barcode', barcode); + props.changeFn(props.rowId, 'barcode', barcode); }, [barcode]); // Update location field description on state change @@ -591,7 +591,7 @@ function LineItemFormRow({ nextValue = Number.isFinite(parsed) ? parsed : ''; } - props.changeFn(props.idx, 'quantity', nextValue); + props.changeFn(props.rowId, 'quantity', nextValue); serialNumberGenerator.update({ quantity: nextValue === '' ? undefined : nextValue }); @@ -690,7 +690,7 @@ function LineItemFormRow({ - props.removeFn(props.idx)} /> + props.removeFn(props.rowId)} /> {locationOpen && ( @@ -709,7 +709,7 @@ function LineItemFormRow({ structural: false }, onValueChange: (value) => { - props.changeFn(props.idx, 'location', value); + props.changeFn(props.rowId, 'location', value); }, description: locationDescription, value: props.item.location, @@ -731,7 +731,7 @@ function LineItemFormRow({ tooltip={t`Store at default location`} onClick={() => props.changeFn( - props.idx, + props.rowId, 'location', record.part_detail?.default_location ?? record.part_detail?.category_default_location @@ -745,7 +745,11 @@ function LineItemFormRow({ icon={} tooltip={t`Store at line item destination `} onClick={() => - props.changeFn(props.idx, 'location', record.destination) + props.changeFn( + props.rowId, + 'location', + record.destination + ) } tooltipAlignment='top' /> @@ -758,7 +762,7 @@ function LineItemFormRow({ tooltip={t`Store with already received stock`} onClick={() => props.changeFn( - props.idx, + props.rowId, 'location', record.destination_detail.pk ) @@ -774,7 +778,7 @@ function LineItemFormRow({ { - props.changeFn(props.idx, 'batch_code', value); + props.changeFn(props.rowId, 'batch_code', value); }} fieldName='batch_code' fieldDefinition={{ @@ -788,7 +792,7 @@ function LineItemFormRow({ - props.changeFn(props.idx, 'serial_numbers', value) + props.changeFn(props.rowId, 'serial_numbers', value) } fieldName='serial_numbers' fieldDefinition={{ @@ -806,7 +810,7 @@ function LineItemFormRow({ - props.changeFn(props.idx, 'expiry_date', value) + props.changeFn(props.rowId, 'expiry_date', value) } fieldName='expiry_date' fieldDefinition={{ @@ -820,7 +824,9 @@ function LineItemFormRow({ )} props.changeFn(props.idx, 'packaging', value)} + onValueChange={(value) => + props.changeFn(props.rowId, 'packaging', value) + } fieldName='packaging' fieldDefinition={{ field_type: 'string', @@ -833,7 +839,7 @@ function LineItemFormRow({ visible={statusOpen} defaultValue={10} fieldName='status' - onValueChange={(value) => props.changeFn(props.idx, 'status', value)} + onValueChange={(value) => props.changeFn(props.rowId, 'status', value)} fieldDefinition={{ field_type: 'choice', api_url: apiUrl(ApiEndpoints.stock_status), @@ -845,7 +851,7 @@ function LineItemFormRow({ props.changeFn(props.idx, 'note', value)} + onValueChange={(value) => props.changeFn(props.rowId, 'note', value)} fieldDefinition={{ field_type: 'string', label: t`Note` @@ -874,13 +880,20 @@ export function useReceiveLineItems(props: LineItemsForm) { [] ); - const records = Object.fromEntries( - props.items.map((item) => [item.pk, item]) - ); + const records = useMemo(() => { + return Object.fromEntries(props.items.map((item) => [item.pk, item])); + }, [props.items]); - const filteredItems = props.items.filter( - (elem) => elem.quantity !== elem.received - ); + const filteredItems = useMemo(() => { + return props.items + .filter((elem) => elem.quantity !== elem.received) + .map((elem) => { + return { + id: elem.pk, + ...elem + }; + }); + }, [props.items]); const fields: ApiFormFieldSet = useMemo(() => { return { @@ -890,8 +903,9 @@ export function useReceiveLineItems(props: LineItemsForm) { }, items: { field_type: 'table', - value: filteredItems.map((elem, idx) => { + value: filteredItems.map((elem) => { return { + id: elem.pk, line_item: elem.pk, location: elem.destination ?? elem.destination_detail?.pk ?? null, quantity: elem.quantity - elem.received, @@ -914,7 +928,7 @@ export function useReceiveLineItems(props: LineItemsForm) { props={row} record={record} statuses={stockStatusCodes} - key={record.pk} + key={row.rowId} /> ); }, @@ -933,7 +947,7 @@ export function useReceiveLineItems(props: LineItemsForm) { } } }; - }, [filteredItems, props, stockStatusCodes]); + }, [filteredItems, records, props, stockStatusCodes]); return useCreateApiFormModal({ ...props.formProps,