| @@ -1767,6 +1767,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO | |||
| const byLotId = new Map<number, any>(); | |||
| const byLotNo = new Map<string, any[]>(); | |||
| const byStockInLineId = new Map<number, any[]>(); | |||
| // Cache active lots separately to avoid filtering on every scan | |||
| const activeLotsByItemId = new Map<number, any[]>(); | |||
| const rejectedStatuses = new Set(['rejected']); | |||
| @@ -1838,6 +1839,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO | |||
| const processOutsideQrCode = useCallback(async (latestQr: string, qrScanCountAtInvoke?: number) => { | |||
| const totalStartTime = performance.now(); | |||
| console.log(` [PROCESS OUTSIDE QR START] QR: ${latestQr.substring(0, 50)}...`); | |||
| console.log(` Start time: ${new Date().toISOString()}`); | |||
| @@ -1855,6 +1857,9 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO | |||
| qrData = JSON.parse(latestQr); | |||
| parseTime = performance.now() - parseStartTime; | |||
| console.log(` [PERF] JSON parse time: ${parseTime.toFixed(2)}ms`); | |||
| console.log("[QR DEBUG] qrData:", qrData); | |||
| console.log("[QR DEBUG] typeof itemId:", typeof qrData?.itemId, "value:", qrData?.itemId); | |||
| console.log("[QR DEBUG] typeof stockInLineId:", typeof qrData?.stockInLineId, "value:", qrData?.stockInLineId); | |||
| } catch { | |||
| console.log("QR content is not JSON; skipping lotNo direct submit to avoid false matches."); | |||
| startTransition(() => { | |||
| @@ -1875,11 +1880,32 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO | |||
| return; | |||
| } | |||
| const validationTime = performance.now() - validationStartTime; | |||
| console.log(` [PERF] Validation time: ${validationTime.toFixed(2)}ms`); | |||
| console.log("[QR DEBUG] raw latestQr:", latestQr); | |||
| console.log("[QR DEBUG] qrData:", qrData); | |||
| console.log("[QR DEBUG] typeof qrData.itemId:", typeof qrData?.itemId, "value:", qrData?.itemId); | |||
| console.log("[QR DEBUG] typeof qrData.stockInLineId:", typeof qrData?.stockInLineId, "value:", qrData?.stockInLineId); | |||
| const scannedItemId = qrData.itemId; | |||
| const scannedStockInLineId = qrData.stockInLineId; | |||
| console.log("[QR DEBUG] combinedLotData.length:", combinedLotData?.length); | |||
| const directBySil = (combinedLotData || []).find( | |||
| (l: any) => String(l?.stockInLineId) === String(scannedStockInLineId) | |||
| ); | |||
| console.log("[QR DEBUG] direct match by stockInLineId:", directBySil); | |||
| const sample0: any = combinedLotData?.[0]; | |||
| if (sample0) { | |||
| console.log("[QR DEBUG] combinedLotData[0] id fields:", { | |||
| itemId: sample0.itemId, | |||
| stockInLineId: sample0.stockInLineId, | |||
| tItemId: typeof sample0.itemId, | |||
| tStockInLineId: typeof sample0.stockInLineId, | |||
| lotNo: sample0.lotNo, | |||
| lotId: sample0.lotId, | |||
| }); | |||
| } else { | |||
| console.log("[QR DEBUG] combinedLotData[0] is empty/undefined"); | |||
| } | |||
| // ✅ Check if this combination was already processed | |||
| const duplicateCheckStartTime = performance.now(); | |||
| const itemProcessedSet = processedQrCombinations.get(scannedItemId); | |||
| @@ -1894,8 +1920,14 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO | |||
| // ✅ OPTIMIZATION: Use cached active lots directly (no filtering needed) | |||
| const lookupStartTime = performance.now(); | |||
| const activeSuggestedLots = indexes.activeLotsByItemId.get(scannedItemId) || []; | |||
| console.log("[QR DEBUG] byItemId.has(num):", indexes.byItemId.has(Number(scannedItemId))); | |||
| //console.log("[QR DEBUG] byItemId.has(str):", indexes.byItemId.has(String(scannedItemId))); | |||
| console.log("[QR DEBUG] byStockInLineId.has(num):", indexes.byStockInLineId.has(Number(scannedStockInLineId))); | |||
| //console.log("[QR DEBUG] byStockInLineId.has(str):", indexes.byStockInLineId.has(String(scannedStockInLineId))); | |||
| // ✅ Also get all lots for this item (not just active ones) to allow lot switching even when all lots are rejected | |||
| const allLotsForItem = indexes.byItemId.get(scannedItemId) || []; | |||
| const lookupTime = performance.now() - lookupStartTime; | |||
| console.log(` [PERF] Index lookup time: ${lookupTime.toFixed(2)}ms, found ${activeSuggestedLots.length} active lots, ${allLotsForItem.length} total lots`); | |||