mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	[UI] Fix serial and batch code generators (#9772)
* Tweak stock item form - Fix batch code placeholder - Fix serial number placeholder * Tweak build output form * More cleanup * Fix for PurchaseOrderForm * Refactoring placeholder values
This commit is contained in:
		| @@ -197,7 +197,6 @@ Configuration of stock item options | |||||||
| | Name | Description | Default | Units | | | Name | Description | Default | Units | | ||||||
| | ---- | ----------- | ------- | ----- | | | ---- | ----------- | ------- | ----- | | ||||||
| {{ globalsetting("SERIAL_NUMBER_GLOBALLY_UNIQUE") }} | {{ globalsetting("SERIAL_NUMBER_GLOBALLY_UNIQUE") }} | ||||||
| {{ globalsetting("SERIAL_NUMBER_AUTOFILL") }} |  | ||||||
| {{ globalsetting("STOCK_DELETE_DEPLETED_DEFAULT") }} | {{ globalsetting("STOCK_DELETE_DEPLETED_DEFAULT") }} | ||||||
| {{ globalsetting("STOCK_BATCH_CODE_TEMPLATE") }} | {{ globalsetting("STOCK_BATCH_CODE_TEMPLATE") }} | ||||||
| {{ globalsetting("STOCK_ENABLE_EXPIRY") }} | {{ globalsetting("STOCK_ENABLE_EXPIRY") }} | ||||||
|   | |||||||
| @@ -640,12 +640,6 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = { | |||||||
|         'default': False, |         'default': False, | ||||||
|         'validator': bool, |         'validator': bool, | ||||||
|     }, |     }, | ||||||
|     'SERIAL_NUMBER_AUTOFILL': { |  | ||||||
|         'name': _('Autofill Serial Numbers'), |  | ||||||
|         'description': _('Autofill serial numbers in forms'), |  | ||||||
|         'default': False, |  | ||||||
|         'validator': bool, |  | ||||||
|     }, |  | ||||||
|     'STOCK_DELETE_DEPLETED_DEFAULT': { |     'STOCK_DELETE_DEPLETED_DEFAULT': { | ||||||
|         'name': _('Delete Depleted Stock'), |         'name': _('Delete Depleted Stock'), | ||||||
|         'description': _('Determines default behavior when a stock item is depleted'), |         'description': _('Determines default behavior when a stock item is depleted'), | ||||||
|   | |||||||
| @@ -25,8 +25,10 @@ import { | |||||||
| import { ProgressBar } from '../components/items/ProgressBar'; | import { ProgressBar } from '../components/items/ProgressBar'; | ||||||
| import { StatusRenderer } from '../components/render/StatusRenderer'; | import { StatusRenderer } from '../components/render/StatusRenderer'; | ||||||
| import { useCreateApiFormModal } from '../hooks/UseForm'; | import { useCreateApiFormModal } from '../hooks/UseForm'; | ||||||
| import { useBatchCodeGenerator } from '../hooks/UseGenerator'; | import { | ||||||
| import { useSerialNumberPlaceholder } from '../hooks/UsePlaceholder'; |   useBatchCodeGenerator, | ||||||
|  |   useSerialNumberGenerator | ||||||
|  | } from '../hooks/UseGenerator'; | ||||||
| import { useGlobalSettingsState } from '../states/SettingsState'; | import { useGlobalSettingsState } from '../states/SettingsState'; | ||||||
| import { PartColumn } from '../tables/ColumnRenderers'; | import { PartColumn } from '../tables/ColumnRenderers'; | ||||||
|  |  | ||||||
| @@ -44,9 +46,9 @@ export function useBuildOrderFields({ | |||||||
|  |  | ||||||
|   const [batchCode, setBatchCode] = useState<string>(''); |   const [batchCode, setBatchCode] = useState<string>(''); | ||||||
|  |  | ||||||
|   const batchGenerator = useBatchCodeGenerator((value: any) => { |   const batchGenerator = useBatchCodeGenerator({ | ||||||
|     if (!batchCode) { |     onGenerate: (value: any) => { | ||||||
|       setBatchCode(value); |       setBatchCode((batch: any) => batch || value); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -96,6 +98,9 @@ export function useBuildOrderFields({ | |||||||
|         icon: <IconTruckDelivery /> |         icon: <IconTruckDelivery /> | ||||||
|       }, |       }, | ||||||
|       batch: { |       batch: { | ||||||
|  |         placeholder: | ||||||
|  |           batchGenerator.result && | ||||||
|  |           `${t`Next batch code`}: ${batchGenerator.result}`, | ||||||
|         value: batchCode, |         value: batchCode, | ||||||
|         onValueChange: (value: any) => setBatchCode(value) |         onValueChange: (value: any) => setBatchCode(value) | ||||||
|       }, |       }, | ||||||
| @@ -143,7 +148,7 @@ export function useBuildOrderFields({ | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     return fields; |     return fields; | ||||||
|   }, [create, destination, batchCode, globalSettings]); |   }, [create, destination, batchCode, batchGenerator.result, globalSettings]); | ||||||
| } | } | ||||||
|  |  | ||||||
| export function useBuildOrderOutputFields({ | export function useBuildOrderOutputFields({ | ||||||
| @@ -170,10 +175,17 @@ export function useBuildOrderOutputFields({ | |||||||
|     setQuantity(Math.max(0, build_quantity - build_complete)); |     setQuantity(Math.max(0, build_quantity - build_complete)); | ||||||
|   }, [build]); |   }, [build]); | ||||||
|  |  | ||||||
|   const serialPlaceholder = useSerialNumberPlaceholder({ |   const serialGenerator = useSerialNumberGenerator({ | ||||||
|     partId: build.part_detail?.pk, |     initialQuery: { | ||||||
|     key: 'build-output', |       part: build.part || build.part_detail?.pk | ||||||
|     enabled: build.part_detail?.trackable |     } | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const batchGenerator = useBatchCodeGenerator({ | ||||||
|  |     initialQuery: { | ||||||
|  |       part: build.part || build.part_detail?.pk, | ||||||
|  |       quantity: build.quantity | ||||||
|  |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   return useMemo(() => { |   return useMemo(() => { | ||||||
| @@ -186,9 +198,15 @@ export function useBuildOrderOutputFields({ | |||||||
|       }, |       }, | ||||||
|       serial_numbers: { |       serial_numbers: { | ||||||
|         hidden: !trackable, |         hidden: !trackable, | ||||||
|         placeholder: serialPlaceholder |         placeholder: | ||||||
|  |           serialGenerator.result && | ||||||
|  |           `${t`Next serial number`}: ${serialGenerator.result}` | ||||||
|  |       }, | ||||||
|  |       batch_code: { | ||||||
|  |         placeholder: | ||||||
|  |           batchGenerator.result && | ||||||
|  |           `${t`Next batch code`}: ${batchGenerator.result}` | ||||||
|       }, |       }, | ||||||
|       batch_code: {}, |  | ||||||
|       location: { |       location: { | ||||||
|         value: location, |         value: location, | ||||||
|         onValueChange: (value: any) => { |         onValueChange: (value: any) => { | ||||||
| @@ -199,7 +217,7 @@ export function useBuildOrderOutputFields({ | |||||||
|         hidden: !trackable |         hidden: !trackable | ||||||
|       } |       } | ||||||
|     }; |     }; | ||||||
|   }, [quantity, serialPlaceholder, trackable]); |   }, [quantity, batchGenerator.result, serialGenerator.result, trackable]); | ||||||
| } | } | ||||||
|  |  | ||||||
| function BuildOutputFormRow({ | function BuildOutputFormRow({ | ||||||
|   | |||||||
| @@ -295,16 +295,20 @@ function LineItemFormRow({ | |||||||
|   }, [record.destination]); |   }, [record.destination]); | ||||||
|  |  | ||||||
|   // Batch code generator |   // Batch code generator | ||||||
|   const batchCodeGenerator = useBatchCodeGenerator((value: any) => { |   const batchCodeGenerator = useBatchCodeGenerator({ | ||||||
|     if (value) { |     onGenerate: (value: any) => { | ||||||
|       props.changeFn(props.idx, 'batch_code', value); |       if (value) { | ||||||
|  |         props.changeFn(props.idx, 'batch_code', value); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // Serial number generator |   // Serial number generator | ||||||
|   const serialNumberGenerator = useSerialNumberGenerator((value: any) => { |   const serialNumberGenerator = useSerialNumberGenerator({ | ||||||
|     if (value) { |     onGenerate: (value: any) => { | ||||||
|       props.changeFn(props.idx, 'serial_numbers', value); |       if (value) { | ||||||
|  |         props.changeFn(props.idx, 'serial_numbers', value); | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -478,8 +482,10 @@ function LineItemFormRow({ | |||||||
|             fieldDefinition={{ |             fieldDefinition={{ | ||||||
|               field_type: 'number', |               field_type: 'number', | ||||||
|               value: props.item.quantity, |               value: props.item.quantity, | ||||||
|               onValueChange: (value) => |               onValueChange: (value) => { | ||||||
|                 props.changeFn(props.idx, 'quantity', value) |                 props.changeFn(props.idx, 'quantity', value); | ||||||
|  |                 serialNumberGenerator.update({ quantity: value }); | ||||||
|  |               } | ||||||
|             }} |             }} | ||||||
|             error={props.rowErrors?.quantity?.message} |             error={props.rowErrors?.quantity?.message} | ||||||
|           /> |           /> | ||||||
|   | |||||||
| @@ -56,7 +56,6 @@ import { | |||||||
|   useBatchCodeGenerator, |   useBatchCodeGenerator, | ||||||
|   useSerialNumberGenerator |   useSerialNumberGenerator | ||||||
| } from '../hooks/UseGenerator'; | } from '../hooks/UseGenerator'; | ||||||
| import { useSerialNumberPlaceholder } from '../hooks/UsePlaceholder'; |  | ||||||
| import { useGlobalSettingsState } from '../states/SettingsState'; | import { useGlobalSettingsState } from '../states/SettingsState'; | ||||||
| import { StatusFilterOptions } from '../tables/Filter'; | import { StatusFilterOptions } from '../tables/Filter'; | ||||||
|  |  | ||||||
| @@ -79,35 +78,20 @@ export function useStockFields({ | |||||||
|  |  | ||||||
|   const [supplierPart, setSupplierPart] = useState<number | null>(null); |   const [supplierPart, setSupplierPart] = useState<number | null>(null); | ||||||
|  |  | ||||||
|   const [nextBatchCode, setNextBatchCode] = useState<string>(''); |  | ||||||
|   const [nextSerialNumber, setNextSerialNumber] = useState<string>(''); |  | ||||||
|  |  | ||||||
|   const [expiryDate, setExpiryDate] = useState<string | null>(null); |   const [expiryDate, setExpiryDate] = useState<string | null>(null); | ||||||
|  |  | ||||||
|   const batchGenerator = useBatchCodeGenerator((value: any) => { |   const batchGenerator = useBatchCodeGenerator({ | ||||||
|     if (value) { |     initialQuery: { | ||||||
|       setNextBatchCode(`${t`Next batch code`}: ${value}`); |       part: partInstance?.pk || partId | ||||||
|     } else { |  | ||||||
|       setNextBatchCode(''); |  | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   const serialGenerator = useSerialNumberGenerator((value: any) => { |   const serialGenerator = useSerialNumberGenerator({ | ||||||
|     if (value) { |     initialQuery: { | ||||||
|       setNextSerialNumber(`${t`Next serial number`}: ${value}`); |       part: partInstance?.pk || partId | ||||||
|     } else { |  | ||||||
|       setNextSerialNumber(''); |  | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   useEffect(() => { |  | ||||||
|     if (partInstance?.pk) { |  | ||||||
|       // Update the generators whenever the part ID changes |  | ||||||
|       batchGenerator.update({ part: partInstance.pk }); |  | ||||||
|       serialGenerator.update({ part: partInstance.pk }); |  | ||||||
|     } |  | ||||||
|   }, [partInstance.pk]); |  | ||||||
|  |  | ||||||
|   return useMemo(() => { |   return useMemo(() => { | ||||||
|     const fields: ApiFormFieldSet = { |     const fields: ApiFormFieldSet = { | ||||||
|       part: { |       part: { | ||||||
| @@ -181,16 +165,23 @@ export function useStockFields({ | |||||||
|         description: t`Enter serial numbers for new stock (or leave blank)`, |         description: t`Enter serial numbers for new stock (or leave blank)`, | ||||||
|         required: false, |         required: false, | ||||||
|         hidden: !create, |         hidden: !create, | ||||||
|         placeholder: nextSerialNumber |         placeholder: | ||||||
|  |           serialGenerator.result && | ||||||
|  |           `${t`Next serial number`}: ${serialGenerator.result}` | ||||||
|       }, |       }, | ||||||
|       serial: { |       serial: { | ||||||
|  |         placeholder: | ||||||
|  |           serialGenerator.result && | ||||||
|  |           `${t`Next serial number`}: ${serialGenerator.result}`, | ||||||
|         hidden: |         hidden: | ||||||
|           create || |           create || | ||||||
|           partInstance.trackable == false || |           partInstance.trackable == false || | ||||||
|           (stockItem?.quantity != undefined && stockItem?.quantity != 1) |           (stockItem?.quantity != undefined && stockItem?.quantity != 1) | ||||||
|       }, |       }, | ||||||
|       batch: { |       batch: { | ||||||
|         placeholder: nextBatchCode |         placeholder: | ||||||
|  |           batchGenerator.result && | ||||||
|  |           `${t`Next batch code`}: ${batchGenerator.result}` | ||||||
|       }, |       }, | ||||||
|       status_custom_key: { |       status_custom_key: { | ||||||
|         label: t`Stock Status` |         label: t`Stock Status` | ||||||
| @@ -234,8 +225,8 @@ export function useStockFields({ | |||||||
|     partId, |     partId, | ||||||
|     globalSettings, |     globalSettings, | ||||||
|     supplierPart, |     supplierPart, | ||||||
|     nextSerialNumber, |     serialGenerator.result, | ||||||
|     nextBatchCode, |     batchGenerator.result, | ||||||
|     create |     create | ||||||
|   ]); |   ]); | ||||||
| } | } | ||||||
| @@ -332,21 +323,23 @@ export function useStockItemSerializeFields({ | |||||||
|   partId: number; |   partId: number; | ||||||
|   trackable: boolean; |   trackable: boolean; | ||||||
| }) { | }) { | ||||||
|   const snPlaceholder = useSerialNumberPlaceholder({ |   const serialGenerator = useSerialNumberGenerator({ | ||||||
|     partId: partId, |     initialQuery: { | ||||||
|     key: 'stock-item-serialize', |       part: partId | ||||||
|     enabled: trackable |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   return useMemo(() => { |   return useMemo(() => { | ||||||
|     return { |     return { | ||||||
|       quantity: {}, |       quantity: {}, | ||||||
|       serial_numbers: { |       serial_numbers: { | ||||||
|         placeholder: snPlaceholder |         placeholder: | ||||||
|  |           serialGenerator.result && | ||||||
|  |           `${t`Next serial number`}: ${serialGenerator.result}` | ||||||
|       }, |       }, | ||||||
|       destination: {} |       destination: {} | ||||||
|     }; |     }; | ||||||
|   }, [snPlaceholder]); |   }, [serialGenerator.result]); | ||||||
| } | } | ||||||
|  |  | ||||||
| function StockItemDefaultMove({ | function StockItemDefaultMove({ | ||||||
|   | |||||||
| @@ -6,6 +6,13 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints'; | |||||||
| import { apiUrl } from '@lib/functions/Api'; | import { apiUrl } from '@lib/functions/Api'; | ||||||
| import { api } from '../App'; | import { api } from '../App'; | ||||||
|  |  | ||||||
|  | export type GeneratorProps = { | ||||||
|  |   endpoint: ApiEndpoints; | ||||||
|  |   key: string; | ||||||
|  |   initialQuery?: Record<string, any>; | ||||||
|  |   onGenerate?: (value: any) => void; | ||||||
|  | }; | ||||||
|  |  | ||||||
| export type GeneratorState = { | export type GeneratorState = { | ||||||
|   query: Record<string, any>; |   query: Record<string, any>; | ||||||
|   result: any; |   result: any; | ||||||
| @@ -17,11 +24,7 @@ export type GeneratorState = { | |||||||
|  * We can pass additional parameters to the query, and update the query as needed. |  * We can pass additional parameters to the query, and update the query as needed. | ||||||
|  * Each update calls a new query to the API, and the result is stored in the state. |  * Each update calls a new query to the API, and the result is stored in the state. | ||||||
|  */ |  */ | ||||||
| export function useGenerator( | export function useGenerator(props: GeneratorProps): GeneratorState { | ||||||
|   endpoint: ApiEndpoints, |  | ||||||
|   key: string, |  | ||||||
|   onGenerate?: (value: any) => void |  | ||||||
| ): GeneratorState { |  | ||||||
|   // Track the result |   // Track the result | ||||||
|   const [result, setResult] = useState<any>(null); |   const [result, setResult] = useState<any>(null); | ||||||
|  |  | ||||||
| @@ -29,7 +32,7 @@ export function useGenerator( | |||||||
|   const [query, setQuery] = useState<Record<string, any>>({}); |   const [query, setQuery] = useState<Record<string, any>>({}); | ||||||
|  |  | ||||||
|   // Prevent rapid updates |   // Prevent rapid updates | ||||||
|   const [debouncedQuery] = useDebouncedValue<Record<string, any>>(query, 250); |   const [debouncedQuery] = useDebouncedValue<Record<string, any>>(query, 100); | ||||||
|  |  | ||||||
|   // Callback to update the generator query |   // Callback to update the generator query | ||||||
|   const update = useCallback( |   const update = useCallback( | ||||||
| @@ -42,27 +45,44 @@ export function useGenerator( | |||||||
|           ...params |           ...params | ||||||
|         })); |         })); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       queryGenerator.refetch(); |  | ||||||
|     }, |     }, | ||||||
|     [] |     [] | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   // API query handler |   // API query handler | ||||||
|   const queryGenerator = useQuery({ |   const queryGenerator = useQuery({ | ||||||
|     enabled: false, |     enabled: true, | ||||||
|     queryKey: ['generator', key, endpoint, debouncedQuery], |     queryKey: [ | ||||||
|  |       'generator', | ||||||
|  |       props.key, | ||||||
|  |       props.endpoint, | ||||||
|  |       props.initialQuery, | ||||||
|  |       debouncedQuery | ||||||
|  |     ], | ||||||
|  |     refetchOnMount: false, | ||||||
|  |     refetchOnWindowFocus: false, | ||||||
|     queryFn: async () => { |     queryFn: async () => { | ||||||
|       return api.post(apiUrl(endpoint), debouncedQuery).then((response) => { |       const generatorQuery = { | ||||||
|         const value = response?.data[key]; |         ...debouncedQuery, | ||||||
|         setResult(value); |         ...(props.initialQuery ?? {}) | ||||||
|  |       }; | ||||||
|  |  | ||||||
|         if (onGenerate) { |       return api | ||||||
|           onGenerate(value); |         .post(apiUrl(props.endpoint), generatorQuery) | ||||||
|         } |         .then((response) => { | ||||||
|  |           const value = response?.data[props.key]; | ||||||
|  |           setResult(value); | ||||||
|  |  | ||||||
|         return response; |           props.onGenerate?.(value); | ||||||
|       }); |  | ||||||
|  |           return response; | ||||||
|  |         }) | ||||||
|  |         .catch((error) => { | ||||||
|  |           console.error( | ||||||
|  |             `Error generating ${props.key} @ ${props.endpoint}:`, | ||||||
|  |             error | ||||||
|  |           ); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -74,19 +94,33 @@ export function useGenerator( | |||||||
| } | } | ||||||
|  |  | ||||||
| // Generate a batch code with provided data | // Generate a batch code with provided data | ||||||
| export function useBatchCodeGenerator(onGenerate: (value: any) => void) { | export function useBatchCodeGenerator({ | ||||||
|   return useGenerator( |   initialQuery, | ||||||
|     ApiEndpoints.generate_batch_code, |   onGenerate | ||||||
|     'batch_code', | }: { | ||||||
|     onGenerate |   initialQuery?: Record<string, any>; | ||||||
|   ); |   onGenerate?: (value: any) => void; | ||||||
|  | }): GeneratorState { | ||||||
|  |   return useGenerator({ | ||||||
|  |     endpoint: ApiEndpoints.generate_batch_code, | ||||||
|  |     key: 'batch_code', | ||||||
|  |     initialQuery: initialQuery, | ||||||
|  |     onGenerate: onGenerate | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Generate a serial number with provided data | // Generate a serial number with provided data | ||||||
| export function useSerialNumberGenerator(onGenerate: (value: any) => void) { | export function useSerialNumberGenerator({ | ||||||
|   return useGenerator( |   initialQuery, | ||||||
|     ApiEndpoints.generate_serial_number, |   onGenerate | ||||||
|     'serial_number', | }: { | ||||||
|     onGenerate |   initialQuery?: Record<string, any>; | ||||||
|   ); |   onGenerate?: (value: any) => void; | ||||||
|  | }): GeneratorState { | ||||||
|  |   return useGenerator({ | ||||||
|  |     endpoint: ApiEndpoints.generate_serial_number, | ||||||
|  |     key: 'serial_number', | ||||||
|  |     initialQuery: initialQuery, | ||||||
|  |     onGenerate: onGenerate | ||||||
|  |   }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,66 +0,0 @@ | |||||||
| import { t } from '@lingui/core/macro'; |  | ||||||
| import { useQuery } from '@tanstack/react-query'; |  | ||||||
| import { useMemo } from 'react'; |  | ||||||
|  |  | ||||||
| import { ApiEndpoints } from '@lib/enums/ApiEndpoints'; |  | ||||||
| import { apiUrl } from '@lib/functions/Api'; |  | ||||||
| import { api } from '../App'; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Hook for generating a placeholder text for a serial number input |  | ||||||
|  * |  | ||||||
|  * This hook fetches the latest serial number information for a given part and generates a placeholder string. |  | ||||||
|  * |  | ||||||
|  * @param partId The ID of the part to fetch serial number information for |  | ||||||
|  * @param key A unique key to identify the query |  | ||||||
|  * @param enabled Whether the query should be enabled |  | ||||||
|  */ |  | ||||||
| export function useSerialNumberPlaceholder({ |  | ||||||
|   partId, |  | ||||||
|   key, |  | ||||||
|   enabled = true |  | ||||||
| }: { |  | ||||||
|   partId: number; |  | ||||||
|   key: string; |  | ||||||
|   enabled?: boolean; |  | ||||||
| }): string | undefined { |  | ||||||
|   // Fetch serial number information (if available) |  | ||||||
|   const snQuery = useQuery({ |  | ||||||
|     queryKey: ['serial-placeholder', key, partId], |  | ||||||
|     enabled: enabled ?? true, |  | ||||||
|     queryFn: async () => { |  | ||||||
|       if (!partId) { |  | ||||||
|         return null; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       const url = apiUrl(ApiEndpoints.part_serial_numbers, partId); |  | ||||||
|  |  | ||||||
|       return api |  | ||||||
|         .get(url) |  | ||||||
|         .then((response) => { |  | ||||||
|           if (response.status === 200) { |  | ||||||
|             return response.data; |  | ||||||
|           } else { |  | ||||||
|             return null; |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|         .catch(() => { |  | ||||||
|           return null; |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|  |  | ||||||
|   const placeholder = useMemo(() => { |  | ||||||
|     if (!enabled) { |  | ||||||
|       return undefined; |  | ||||||
|     } else if (snQuery.data?.next) { |  | ||||||
|       return `${t`Next serial number`}: ${snQuery.data.next}`; |  | ||||||
|     } else if (snQuery.data?.latest) { |  | ||||||
|       return `${t`Latest serial number`}: ${snQuery.data.latest}`; |  | ||||||
|     } else { |  | ||||||
|       return undefined; |  | ||||||
|     } |  | ||||||
|   }, [enabled, snQuery.data]); |  | ||||||
|  |  | ||||||
|   return placeholder; |  | ||||||
| } |  | ||||||
| @@ -222,7 +222,6 @@ export default function SystemSettings() { | |||||||
|           <GlobalSettingList |           <GlobalSettingList | ||||||
|             keys={[ |             keys={[ | ||||||
|               'SERIAL_NUMBER_GLOBALLY_UNIQUE', |               'SERIAL_NUMBER_GLOBALLY_UNIQUE', | ||||||
|               'SERIAL_NUMBER_AUTOFILL', |  | ||||||
|               'STOCK_DELETE_DEPLETED_DEFAULT', |               'STOCK_DELETE_DEPLETED_DEFAULT', | ||||||
|               'STOCK_BATCH_CODE_TEMPLATE', |               'STOCK_BATCH_CODE_TEMPLATE', | ||||||
|               'STOCK_ENABLE_EXPIRY', |               'STOCK_ENABLE_EXPIRY', | ||||||
|   | |||||||
| @@ -167,6 +167,8 @@ test('Build Order - Build Outputs', async ({ browser }) => { | |||||||
|     .getByLabel('text-field-serial_numbers') |     .getByLabel('text-field-serial_numbers') | ||||||
|     .getAttribute('placeholder'); |     .getAttribute('placeholder'); | ||||||
|  |  | ||||||
|  |   expect(placeholder).toContain('Next serial number'); | ||||||
|  |  | ||||||
|   let sn = 1; |   let sn = 1; | ||||||
|  |  | ||||||
|   if (!!placeholder && placeholder.includes('Next serial number')) { |   if (!!placeholder && placeholder.includes('Next serial number')) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user