diff --git a/src/components/Jodetail/JobPickExecution.tsx b/src/components/Jodetail/JobPickExecution.tsx index dc9cdc5..c3cd28e 100644 --- a/src/components/Jodetail/JobPickExecution.tsx +++ b/src/components/Jodetail/JobPickExecution.tsx @@ -526,7 +526,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { stockOutLineId: lot.stockOutLineId, stockOutLineStatus: lot.stockOutLineStatus, stockOutLineQty: lot.stockOutLineQty, - + suggestedPickLotId: lot.suggestedPickLotId, // Router info routerIndex: lot.routerIndex, secondQrScanStatus: lot.secondQrScanStatus, @@ -714,9 +714,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { setQrScanSuccess(true); setQrScanError(false); setQrScanInput(''); // Clear input after successful processing - setIsManualScanning(false); - stopScan(); - resetScan(); + } else { console.error(`❌ QR Code processing failed: ${errorCount} errors`); setQrScanError(true); @@ -759,48 +757,87 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { return; } - await confirmLotSubstitution({ + console.log("=== Lot Confirmation Debug ==="); + console.log("Selected Lot:", selectedLotForQr); + console.log("Pick Order Line ID:", selectedLotForQr.pickOrderLineId); + console.log("Stock Out Line ID:", selectedLotForQr.stockOutLineId); + console.log("Suggested Pick Lot ID:", selectedLotForQr.suggestedPickLotId); + console.log("Lot ID (fallback):", selectedLotForQr.lotId); + console.log("New Inventory Lot Line ID:", newLotLineId); + + // ✅ Call confirmLotSubstitution to update the suggested lot + const substitutionResult = await confirmLotSubstitution({ pickOrderLineId: selectedLotForQr.pickOrderLineId, stockOutLineId: selectedLotForQr.stockOutLineId, - originalSuggestedPickLotId: selectedLotForQr.suggestedPickLotId, + originalSuggestedPickLotId: selectedLotForQr.suggestedPickLotId || selectedLotForQr.lotId, newInventoryLotLineId: newLotLineId }); - - setQrScanError(false); - setQrScanSuccess(false); - setQrScanInput(''); - setProcessedQrCodes(new Set()); - setLastProcessedQr(''); + console.log("✅ Lot substitution result:", substitutionResult); + + // ✅ Update stock out line status to 'checked' after substitution if(selectedLotForQr?.stockOutLineId){ await updateStockOutLineStatus({ id: selectedLotForQr.stockOutLineId, status: 'checked', qty: 0 }); + console.log("✅ Stock out line status updated to 'checked'"); } + // ✅ Close modal and clean up state BEFORE refreshing setLotConfirmationOpen(false); setExpectedLotData(null); setScannedLotData(null); setSelectedLotForQr(null); + // ✅ Clear QR processing state but DON'T clear processedQrCodes yet + setQrScanError(false); + setQrScanSuccess(true); + setQrScanInput(''); + + // ✅ Set refreshing flag to prevent QR processing during refresh + setIsRefreshingData(true); + + // ✅ Refresh data to show updated lot + console.log("🔄 Refreshing job order data..."); await fetchJobOrderData(); console.log("✅ Lot substitution confirmed and data refreshed"); + + // ✅ Clear processed QR codes and flags immediately after refresh + // This allows new QR codes to be processed right away + setTimeout(() => { + console.log("✅ Clearing processed QR codes and resuming scan"); + setProcessedQrCodes(new Set()); + setLastProcessedQr(''); + setQrScanSuccess(false); + setIsRefreshingData(false); + }, 500); // ✅ Reduced from 3000ms to 500ms - just enough for UI update + } catch (error) { console.error("Error confirming lot substitution:", error); + setQrScanError(true); + setQrScanSuccess(false); + // ✅ Clear refresh flag on error + setIsRefreshingData(false); } finally { setIsConfirmingLot(false); } }, [expectedLotData, scannedLotData, selectedLotForQr, fetchJobOrderData]); const processOutsideQrCode = useCallback(async (latestQr: string) => { + // ✅ Don't process if confirmation modal is open + if (lotConfirmationOpen) { + console.log("⏸️ Confirmation modal is open, skipping QR processing"); + return; + } + let qrData: any = null; try { qrData = JSON.parse(latestQr); } catch { console.log("QR is not JSON format"); - // ✅ Handle non-JSON QR codes as direct lot numbers + // Handle non-JSON QR codes as direct lot numbers const directLotNo = latestQr.replace(/[{}]/g, ''); if (directLotNo) { console.log(`Processing direct lot number: ${directLotNo}`); @@ -891,6 +928,8 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { // Case 2: Same item, different lot - show confirmation modal console.log(`🔍 Lot mismatch: Expected ${expectedLot.lotNo}, Scanned ${scanned?.lotNo}`); + + // ✅ DON'T stop scanning - just pause QR processing by showing modal setSelectedLotForQr(expectedLot); handleLotMismatch( { @@ -912,7 +951,8 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { setQrScanSuccess(false); return; } - }, [combinedLotData, handleQrCodeSubmit, handleLotMismatch]); + }, [combinedLotData, handleQrCodeSubmit, handleLotMismatch, lotConfirmationOpen]); + const handleManualInputSubmit = useCallback(() => { if (qrScanInput.trim() !== '') { @@ -964,7 +1004,8 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { useEffect(() => { - if (qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData) { + // ✅ Add isManualScanning check + if (!isManualScanning || qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData || lotConfirmationOpen) { return; } @@ -982,7 +1023,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { processOutsideQrCode(latestQr); } - }, [qrValues, processedQrCodes, lastProcessedQr, isRefreshingData, processOutsideQrCode, combinedLotData]); + }, [qrValues, processedQrCodes, lastProcessedQr, isRefreshingData, processOutsideQrCode, combinedLotData, isManualScanning, lotConfirmationOpen]); const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => { if (value === '' || value === null || value === undefined) { @@ -1372,6 +1413,16 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { stopScan(); resetScan(); }, [stopScan, resetScan]); + useEffect(() => { + return () => { + // Cleanup when component unmounts (e.g., when switching tabs) + if (isManualScanning) { + console.log("🧹 Component unmounting, stopping QR scanner..."); + stopScan(); + resetScan(); + } + }; + }, [isManualScanning, stopScan, resetScan]); const getStatusMessage = useCallback((lot: any) => { switch (lot.stockOutLineStatus?.toLowerCase()) { @@ -1639,6 +1690,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { {/* ✅ QR Code Modal */} + {!lotConfirmationOpen && ( { @@ -1651,6 +1703,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { combinedLotData={combinedLotData} onQrCodeSubmit={handleQrCodeSubmitFromModal} /> + )} {/* ✅ Add Lot Confirmation Modal */} {lotConfirmationOpen && expectedLotData && scannedLotData && ( = ({ filterArgs }) => { setLotConfirmationOpen(false); setExpectedLotData(null); setScannedLotData(null); + setSelectedLotForQr(null); + }} onConfirm={handleLotConfirmation} expectedLot={expectedLotData} diff --git a/src/components/Jodetail/JobPickExecutionsecondscan.tsx b/src/components/Jodetail/JobPickExecutionsecondscan.tsx index 1f0b94e..349235e 100644 --- a/src/components/Jodetail/JobPickExecutionsecondscan.tsx +++ b/src/components/Jodetail/JobPickExecutionsecondscan.tsx @@ -614,7 +614,16 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { if (successCount > 0) { setQrScanSuccess(true); setQrScanError(false); + + // ✅ Set refreshing flag briefly to prevent duplicate processing + setIsRefreshingData(true); await fetchJobOrderData(); // Refresh data + + // ✅ Clear refresh flag and success message after a short delay + setTimeout(() => { + setQrScanSuccess(false); + setIsRefreshingData(false); + }, 500); } else { setQrScanError(true); setQrScanSuccess(false); @@ -626,52 +635,68 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { } }, [combinedLotData, fetchJobOrderData, processedQrCodes]); + useEffect(() => { - if (qrValues.length > 0 && combinedLotData.length > 0) { - const latestQr = qrValues[qrValues.length - 1]; - - // ✅ Check if this QR was already processed recently - if (processedQrCodes.has(latestQr) || lastProcessedQr === latestQr) { - console.log("⏭️ QR code already processed, skipping..."); - return; - } - - // ✅ Mark as processed - setProcessedQrCodes(prev => new Set(prev).add(latestQr)); - setLastProcessedQr(latestQr); - - // Extract lot number from QR code - let lotNo = ''; - try { - const qrData = JSON.parse(latestQr); - if (qrData.stockInLineId && qrData.itemId) { - // For JSON QR codes, we need to fetch the lot number - fetchStockInLineInfo(qrData.stockInLineId) - .then((stockInLineInfo) => { - console.log("Outside QR scan - Stock in line info:", stockInLineInfo); - const extractedLotNo = stockInLineInfo.lotNo; - if (extractedLotNo) { - console.log(`Outside QR scan detected (JSON): ${extractedLotNo}`); - handleQrCodeSubmit(extractedLotNo); - } - }) - .catch((error) => { - console.error("Outside QR scan - Error fetching stock in line info:", error); - }); - return; // Exit early for JSON QR codes - } - } catch (error) { - // Not JSON format, treat as direct lot number - lotNo = latestQr.replace(/[{}]/g, ''); - } - - // For direct lot number QR codes - if (lotNo) { - console.log(`Outside QR scan detected (direct): ${lotNo}`); - handleQrCodeSubmit(lotNo); + // ✅ Add isManualScanning and isRefreshingData checks + if (!isManualScanning || qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData) { + return; + } + + const latestQr = qrValues[qrValues.length - 1]; + + // ✅ Check if this QR was already processed recently + if (processedQrCodes.has(latestQr) || lastProcessedQr === latestQr) { + console.log("⏭️ QR code already processed, skipping..."); + return; + } + + // ✅ Mark as processed + setProcessedQrCodes(prev => new Set(prev).add(latestQr)); + setLastProcessedQr(latestQr); + + // Extract lot number from QR code + let lotNo = ''; + try { + const qrData = JSON.parse(latestQr); + if (qrData.stockInLineId && qrData.itemId) { + // For JSON QR codes, we need to fetch the lot number + fetchStockInLineInfo(qrData.stockInLineId) + .then((stockInLineInfo) => { + console.log("Outside QR scan - Stock in line info:", stockInLineInfo); + const extractedLotNo = stockInLineInfo.lotNo; + if (extractedLotNo) { + console.log(`Outside QR scan detected (JSON): ${extractedLotNo}`); + handleQrCodeSubmit(extractedLotNo); + } + }) + .catch((error) => { + console.error("Outside QR scan - Error fetching stock in line info:", error); + }); + return; // Exit early for JSON QR codes } + } catch (error) { + // Not JSON format, treat as direct lot number + lotNo = latestQr.replace(/[{}]/g, ''); + } + + // For direct lot number QR codes + if (lotNo) { + console.log(`Outside QR scan detected (direct): ${lotNo}`); + handleQrCodeSubmit(lotNo); } - }, [qrValues, combinedLotData, handleQrCodeSubmit, processedQrCodes, lastProcessedQr]); + }, [qrValues, combinedLotData, handleQrCodeSubmit, processedQrCodes, lastProcessedQr, isManualScanning, isRefreshingData]); + + // ✅ ADD THIS: Cleanup effect + useEffect(() => { + return () => { + // Cleanup when component unmounts (e.g., when switching tabs) + if (isManualScanning) { + console.log("🧹 Second scan component unmounting, stopping QR scanner..."); + stopScan(); + resetScan(); + } + }; + }, [isManualScanning, stopScan, resetScan]); const handleManualInputSubmit = useCallback(() => { if (qrScanInput.trim() !== '') { handleQrCodeSubmit(qrScanInput.trim()); @@ -721,42 +746,7 @@ const JobPickExecution: React.FC = ({ filterArgs }) => { }, [selectedLotForQr, fetchJobOrderData]); // ✅ Outside QR scanning - process QR codes from outside the page automatically - useEffect(() => { - if (qrValues.length > 0 && combinedLotData.length > 0) { - const latestQr = qrValues[qrValues.length - 1]; - - // Extract lot number from QR code - let lotNo = ''; - try { - const qrData = JSON.parse(latestQr); - if (qrData.stockInLineId && qrData.itemId) { - // For JSON QR codes, we need to fetch the lot number - fetchStockInLineInfo(qrData.stockInLineId) - .then((stockInLineInfo) => { - console.log("Outside QR scan - Stock in line info:", stockInLineInfo); - const extractedLotNo = stockInLineInfo.lotNo; - if (extractedLotNo) { - console.log(`Outside QR scan detected (JSON): ${extractedLotNo}`); - handleQrCodeSubmit(extractedLotNo); - } - }) - .catch((error) => { - console.error("Outside QR scan - Error fetching stock in line info:", error); - }); - return; // Exit early for JSON QR codes - } - } catch (error) { - // Not JSON format, treat as direct lot number - lotNo = latestQr.replace(/[{}]/g, ''); - } - - // For direct lot number QR codes - if (lotNo) { - console.log(`Outside QR scan detected (direct): ${lotNo}`); - handleQrCodeSubmit(lotNo); - } - } - }, [qrValues, combinedLotData, handleQrCodeSubmit]); + const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => { if (value === '' || value === null || value === undefined) { @@ -993,7 +983,16 @@ const paginatedData = useMemo(() => { stopScan(); resetScan(); }, [stopScan, resetScan]); - + useEffect(() => { + return () => { + // Cleanup when component unmounts (e.g., when switching tabs) + if (isManualScanning) { + console.log("🧹 Second scan component unmounting, stopping QR scanner..."); + stopScan(); + resetScan(); + } + }; + }, [isManualScanning, stopScan, resetScan]); const getStatusMessage = useCallback((lot: any) => { switch (lot.stockOutLineStatus?.toLowerCase()) { case 'pending': @@ -1152,8 +1151,8 @@ const paginatedData = useMemo(() => { })()} - - {lot.stockOutLineStatus?.toLowerCase() !== 'pending' ? ( + + {lot.secondQrScanStatus?.toLowerCase() !== 'pending' ? ( { height: '100%' }}>