diff --git a/src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx b/src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx index 0d54f36..5ceec58 100644 --- a/src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx +++ b/src/components/DoWorkbench/WorkbenchGoodPickExecutionDetail.tsx @@ -692,6 +692,8 @@ const [pickOrderSwitching, setPickOrderSwitching] = useState(false); // Use refs for processed QR tracking to avoid useEffect dependency issues and delays const processedQrCodesRef = useRef>(new Set()); const lastProcessedQrRef = useRef(''); + /** Last qrValues.length handled; new pick on same QR requires a new scanner event (length increase). */ + const lastProcessedQrScanCountRef = useRef(0); const qrPickInFlightRef = useRef(false); // Store callbacks in refs to avoid useEffect dependency issues @@ -1518,14 +1520,9 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO const indexAccessTime = performance.now() - indexAccessStart; console.log(` [PERF] Index access time: ${indexAccessTime.toFixed(2)}ms`); - const maybeReleaseQrForNextSol = ( - itemId: number, - stockInLineId: number, - processedAfterMark: ProcessedStockOutLinesByItemId, - ) => { - if (hasPendingActiveRowForStockInLine(indexes, itemId, stockInLineId, processedAfterMark)) { - lastProcessedQrRef.current = ""; - processedQrCodesRef.current.delete(latestQr); + const recordHandledQrScanCount = (scanCount: number | undefined) => { + if (scanCount != null && scanCount > lastProcessedQrScanCountRef.current) { + lastProcessedQrScanCountRef.current = scanCount; } }; @@ -1812,7 +1809,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO expectedLot.stockOutLineId, ); setProcessedQrCombinations(nextProcessedNoActive); - maybeReleaseQrForNextSol(scannedItemId, scannedStockInLineId, nextProcessedNoActive); + recordHandledQrScanCount(qrScanCountAtInvoke); if (workbenchMode) { await refreshWorkbenchAfterScanPick(); @@ -1978,7 +1975,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO expectedLot.stockOutLineId, ); setProcessedQrCombinations(nextProcessedAuto); - maybeReleaseQrForNextSol(scannedItemId, scannedStockInLineId, nextProcessedAuto); + recordHandledQrScanCount(qrScanCountAtInvoke); if (workbenchMode) { await refreshWorkbenchAfterScanPick(); } @@ -2077,7 +2074,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO exactMatch.stockOutLineId, ); setProcessedQrCombinations(nextProcessedExact); - maybeReleaseQrForNextSol(scannedItemId, scannedStockInLineId, nextProcessedExact); + recordHandledQrScanCount(qrScanCountAtInvoke); const markProcessedTime = performance.now() - markProcessedStartTime; console.log(` [PERF] Mark processed time: ${markProcessedTime.toFixed(2)}ms`); @@ -2279,7 +2276,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO expectedLot.stockOutLineId, ); setProcessedQrCombinations(nextProcessedMismatch); - maybeReleaseQrForNextSol(scannedItemId, scannedStockInLineId, nextProcessedMismatch); + recordHandledQrScanCount(qrScanCountAtInvoke); if (workbenchMode) { await refreshWorkbenchAfterScanPick(); @@ -2435,9 +2432,12 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO console.log(` [QR DETECTION] Detection time: ${new Date().toISOString()}`); console.log(` [QR DETECTION] Time since QR scanner set value: ${(qrDetectionStartTime - qrValuesChangeStartTime).toFixed(2)}ms`); + const scanCount = qrValues.length; const qrPayload = parseWorkbenchQrPayload(latestQr); + const isNewScanEvent = scanCount > lastProcessedQrScanCountRef.current; const canRetrySamePhysicalLot = qrPayload != null && + isNewScanEvent && hasPendingActiveRowForStockInLine( lotDataIndexes, qrPayload.itemId, @@ -2445,7 +2445,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO processedQrCombinations, ); - // Skip if already processed (allow same QR when another pending SOL needs this lot) + // Skip if already processed; same QR only retries on a new scanner event (qrValues.length increase) const checkProcessedStartTime = performance.now(); if ( (processedQrCodesRef.current.has(latestQr) || lastProcessedQrRef.current === latestQr) && @@ -2455,12 +2455,6 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO console.log(` [QR PROCESS] Already processed check time: ${checkTime.toFixed(2)}ms`); return; } - if (canRetrySamePhysicalLot) { - processedQrCodesRef.current.delete(latestQr); - if (lastProcessedQrRef.current === latestQr) { - lastProcessedQrRef.current = ""; - } - } const checkTime = performance.now() - checkProcessedStartTime; console.log(` [QR PROCESS] Not processed check time: ${checkTime.toFixed(2)}ms`); @@ -2495,7 +2489,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO } // Process new QR code immediately (background mode - no modal) - if (latestQr && (latestQr !== lastProcessedQrRef.current || canRetrySamePhysicalLot)) { + if (latestQr && (latestQr !== lastProcessedQrRef.current || isNewScanEvent)) { const processingStartTime = performance.now(); console.log(` [QR PROCESS] Starting processing at: ${new Date().toISOString()}`); console.log(` [QR PROCESS] Time since detection: ${(processingStartTime - qrDetectionStartTime).toFixed(2)}ms`);