diff --git a/src/backend/InvenTree/order/serializers.py b/src/backend/InvenTree/order/serializers.py
index ea65d1c9be..feeb649d53 100644
--- a/src/backend/InvenTree/order/serializers.py
+++ b/src/backend/InvenTree/order/serializers.py
@@ -845,6 +845,20 @@ class PurchaseOrderLineItemReceiveSerializer(serializers.Serializer):
except DjangoValidationError as e:
raise ValidationError({'serial_numbers': e.messages})
+ invalid_serials = []
+
+ # Check the serial numbers are valid
+ for serial in data['serials']:
+ try:
+ base_part.validate_serial_number(serial, raise_error=True)
+ except (ValidationError, DjangoValidationError):
+ invalid_serials.append(serial)
+
+ if len(invalid_serials) > 0:
+ msg = _('The following serial numbers already exist or are invalid')
+ msg += ': ' + ', '.join(invalid_serials)
+ raise ValidationError({'serial_numbers': msg})
+
return data
diff --git a/src/backend/InvenTree/templates/js/translated/purchase_order.js b/src/backend/InvenTree/templates/js/translated/purchase_order.js
index 170234b6bb..2ddfc71359 100644
--- a/src/backend/InvenTree/templates/js/translated/purchase_order.js
+++ b/src/backend/InvenTree/templates/js/translated/purchase_order.js
@@ -259,6 +259,7 @@ function poLineItemFields(options={}) {
part: {
icon: 'fa-shapes',
filters: {
+ active: true,
part_detail: true,
supplier_detail: true,
supplier: options.supplier,
diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx
index e0f6b77c91..add7d92414 100644
--- a/src/frontend/src/forms/PurchaseOrderForms.tsx
+++ b/src/frontend/src/forms/PurchaseOrderForms.tsx
@@ -237,6 +237,12 @@ function LineItemFormRow({
onClose: () => props.changeFn(props.idx, 'location', undefined)
});
+ // Is this a trackable part?
+ const trackable: boolean = useMemo(
+ () => record.part_detail?.trackable ?? false,
+ [record]
+ );
+
useEffect(() => {
if (!!record.destination) {
props.changeFn(props.idx, 'location', record.destination);
@@ -303,6 +309,14 @@ function LineItemFormRow({
props.changeFn(props.idx, 'barcode', barcode);
}, [barcode]);
+ const batchToolTip: string = useMemo(() => {
+ if (trackable) {
+ return t`Assign Batch Code and Serial Numbers`;
+ } else {
+ return t`Assign Batch Code`;
+ }
+ }, [trackable]);
+
// Update location field description on state change
useEffect(() => {
if (!opened) {
@@ -418,9 +432,7 @@ function LineItemFormRow({
size="sm"
onClick={() => batchHandlers.toggle()}
icon={}
- tooltip={t`Assign Batch Code${
- record.trackable && ' and Serial Numbers'
- }`}
+ tooltip={batchToolTip}
tooltipAlignment="top"
variant={batchOpen ? 'filled' : 'transparent'}
/>
@@ -552,18 +564,20 @@ function LineItemFormRow({
fieldDefinition={{
field_type: 'string',
label: t`Batch Code`,
+ description: t`Enter batch code for received items`,
value: props.item.batch_code
}}
error={props.rowErrors?.batch_code?.message}
/>
props.changeFn(props.idx, 'serial_numbers', value)
}
fieldDefinition={{
field_type: 'string',
- label: t`Serial numbers`,
+ label: t`Serial Numbers`,
+ description: t`Enter serial numbers for received items`,
value: props.item.serial_numbers
}}
error={props.rowErrors?.serial_numbers?.message}
diff --git a/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx b/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx
index 02ffe97978..9a97a4c961 100644
--- a/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx
+++ b/src/frontend/src/tables/purchasing/PurchaseOrderLineItemTable.tsx
@@ -302,6 +302,10 @@ export function PurchaseOrderLineItemTable({
);
}, [order, poStatus]);
+ const orderPlaced: boolean = useMemo(() => {
+ return order.status == poStatus.PLACED;
+ }, [order, poStatus]);
+
const rowActions = useCallback(
(record: any): RowAction[] => {
let received = (record?.received ?? 0) >= (record?.quantity ?? 0);
@@ -370,10 +374,10 @@ export function PurchaseOrderLineItemTable({
icon={}
onClick={() => receiveLineItems.open()}
disabled={table.selectedRecords.length === 0}
- hidden={!orderOpen || !user.hasChangeRole(UserRoles.purchase_order)}
+ hidden={!orderPlaced || !user.hasChangeRole(UserRoles.purchase_order)}
/>
];
- }, [orderId, user, table, orderOpen]);
+ }, [orderId, user, table, orderOpen, orderPlaced]);
return (
<>