From 0463edf16159395194e83fca4eab3c90f5ab65e7 Mon Sep 17 00:00:00 2001 From: druchniewicz Date: Thu, 9 Jul 2026 20:28:56 +0200 Subject: [PATCH] OBLS-853 Skip validation on staging location --- src/screens/Picking/PickingContext.tsx | 33 ++++++++++++- .../PickingPickStagingLocationScreen.tsx | 49 ++++++++++++++++++- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/screens/Picking/PickingContext.tsx b/src/screens/Picking/PickingContext.tsx index 19251fd6..3e26603e 100644 --- a/src/screens/Picking/PickingContext.tsx +++ b/src/screens/Picking/PickingContext.tsx @@ -44,8 +44,14 @@ type PickingContextType = { revalidateTasksForRequisition: (requisitionId: string | undefined, callback?: () => void) => void; /** Start the pick task (API call) */ startPickTask: (callback: (response: { errorMessage?: string }) => void) => void; - /** Drop the current pick task at the staging location */ + /** Drop the current pick task at the system-suggested staging location */ dropCurrentTask: (task: PickTask, callback?: (response: { errorMessage?: string }) => void) => void; + /** Drop the current pick task at the given staging location */ + dropCurrentTaskAtStagingLocation: ( + task: PickTask, + stagingLocationId: string, + callback?: (response: { errorMessage?: string }) => void + ) => void; /** Revalidates the current pick task details from the server */ revalidateCurrentTask: (callback?: (task: PickTask | undefined) => void) => void; /** Advances to the next task in the list */ @@ -216,6 +222,30 @@ export function PickingProvider({ children }: { children: React.ReactNode }) { dispatch(dropPickTaskAction(task.outboundContainer.id, task.stagingLocation.id, callback)); }; + // Like dropCurrentTask but drops at the given (scanned) staging location instead of the pick task's suggested one + const dropCurrentTaskAtStagingLocation = ( + task: PickTask, + stagingLocationId: string, + callback?: (response: { errorMessage?: string }) => void + ) => { + if (!task) { + Alert.alert('Task Missing', 'No current task to drop.'); + return; + } + + if (!stagingLocationId) { + Alert.alert('Missing Input', 'Please scan or enter a staging location.'); + return; + } + + if (!task.outboundContainer?.id) { + Alert.alert('Error', 'Current task does not have a valid Outbound Container.'); + return; + } + + dispatch(dropPickTaskAction(task.outboundContainer.id, stagingLocationId, callback)); + }; + const resetSession = () => { setTasks([]); setCurrentTaskIndex(0); @@ -237,6 +267,7 @@ export function PickingProvider({ children }: { children: React.ReactNode }) { revalidateTasksForRequisition, startPickTask, dropCurrentTask, + dropCurrentTaskAtStagingLocation, revalidateCurrentTask, goToNextTask }} diff --git a/src/screens/Picking/PickingPickStagingLocationScreen.tsx b/src/screens/Picking/PickingPickStagingLocationScreen.tsx index 5c144eff..aea73acf 100644 --- a/src/screens/Picking/PickingPickStagingLocationScreen.tsx +++ b/src/screens/Picking/PickingPickStagingLocationScreen.tsx @@ -12,8 +12,13 @@ import { parseFromISODateToLocaleString } from '../../utils/utils'; import { usePickingContext } from './PickingContext'; import styles from './styles'; +// Lets the user stage at any scanned location. Set to false to require the scanned location to +// match the one suggested by the pick task. +const SKIP_STAGING_LOCATION_VALIDATION = true; + export default function PickingPickStagingLocationScreen() { - const { tasks, dropCurrentTask, resetSession, setCurrentTaskIndex } = usePickingContext(); + const { tasks, dropCurrentTask, dropCurrentTaskAtStagingLocation, resetSession, setCurrentTaskIndex } = + usePickingContext(); const [stagingLocationNumber, setStagingLocationNumber] = React.useState(EMPTY_STRING); const [currentUniqueIndex, setCurrentUniqueIndex] = React.useState(0); const { isSearchOpen, searchButtonProps } = useSearchButton({ onSelect: setStagingLocationNumber }); @@ -35,6 +40,7 @@ export default function PickingPickStagingLocationScreen() { } }, [currentTask, tasks.length, setCurrentTaskIndex, uniqueTasks.length, tasks]); + // Requires the scanned location to match the one suggested by the task. Used when SKIP_STAGING_LOCATION_VALIDATION is false. function handleScan(locationId: string) { const expected = currentTask.stagingLocation?.locationNumber; @@ -79,6 +85,45 @@ export default function PickingPickStagingLocationScreen() { }); } + // Drops at whatever location the user scans, without checking it against the task's suggestion. + // Used when SKIP_STAGING_LOCATION_VALIDATION is true. + function handleScanWithoutValidation(locationId: string) { + if (!locationId) { + return; + } + + dropCurrentTaskAtStagingLocation(currentTask, locationId, (response) => { + if (response.errorMessage) { + Alert.alert('Error', response.errorMessage); + setStagingLocationNumber(EMPTY_STRING); + return; + } + + const nextIndex = currentUniqueIndex + 1; + if (nextIndex < uniqueTasks.length) { + Alert.alert('Success', 'Staging Location confirmed. Proceeding to the next container.', [ + { + text: 'OK', + onPress: () => { + setCurrentUniqueIndex(nextIndex); + setStagingLocationNumber(EMPTY_STRING); + } + } + ]); + } else { + Alert.alert('Picking Session Complete', 'You have completed all staging confirmations.', [ + { + text: 'OK', + onPress: () => { + resetSession(); + resetToRoutes([{ name: 'Drawer', params: { screen: 'Dashboard' } }, { name: 'PickingPickType' }]); + } + } + ]); + } + }); + } + // If no task is selected yet, return null to avoid rendering // ProductDetails with undefined data while useEffect runs if (!currentTask) { @@ -150,7 +195,7 @@ export default function PickingPickStagingLocationScreen() { value={stagingLocationNumber} isEnabled={!isSearchOpen} onChange={setStagingLocationNumber} - onSubmit={handleScan} + onSubmit={SKIP_STAGING_LOCATION_VALIDATION ? handleScanWithoutValidation : handleScan} />