|
|
|
@@ -19,6 +19,7 @@ import { |
|
|
|
TablePagination, |
|
|
|
Modal, |
|
|
|
} from "@mui/material"; |
|
|
|
import { fetchLotDetail } from "@/app/api/inventory/actions"; |
|
|
|
import { useCallback, useEffect, useState, useRef, useMemo } from "react"; |
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
import { useRouter } from "next/navigation"; |
|
|
|
@@ -26,6 +27,7 @@ import { |
|
|
|
fetchALLPickOrderLineLotDetails, |
|
|
|
updateStockOutLineStatus, |
|
|
|
createStockOutLine, |
|
|
|
updateStockOutLine, |
|
|
|
recordPickExecutionIssue, |
|
|
|
fetchFGPickOrders, // ✅ Add this import |
|
|
|
FGPickOrderResponse, |
|
|
|
@@ -33,8 +35,14 @@ import { |
|
|
|
AutoAssignReleaseResponse, |
|
|
|
checkPickOrderCompletion, |
|
|
|
PickOrderCompletionResponse, |
|
|
|
checkAndCompletePickOrderByConsoCode |
|
|
|
checkAndCompletePickOrderByConsoCode, |
|
|
|
updateSuggestedLotLineId, |
|
|
|
confirmLotSubstitution |
|
|
|
} from "@/app/api/pickOrder/actions"; |
|
|
|
|
|
|
|
import LotConfirmationModal from "./LotConfirmationModal"; |
|
|
|
//import { fetchItem } from "@/app/api/settings/item"; |
|
|
|
import { updateInventoryLotLineStatus, analyzeQrCode } from "@/app/api/inventory/actions"; |
|
|
|
import { fetchNameList, NameList } from "@/app/api/user/actions"; |
|
|
|
import { |
|
|
|
FormProvider, |
|
|
|
@@ -344,7 +352,10 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
// ✅ Add QR modal states |
|
|
|
const [qrModalOpen, setQrModalOpen] = useState(false); |
|
|
|
const [selectedLotForQr, setSelectedLotForQr] = useState<any | null>(null); |
|
|
|
|
|
|
|
const [lotConfirmationOpen, setLotConfirmationOpen] = useState(false); |
|
|
|
const [expectedLotData, setExpectedLotData] = useState<any>(null); |
|
|
|
const [scannedLotData, setScannedLotData] = useState<any>(null); |
|
|
|
const [isConfirmingLot, setIsConfirmingLot] = useState(false); |
|
|
|
// ✅ Add GoodPickExecutionForm states |
|
|
|
const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false); |
|
|
|
const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState<any | null>(null); |
|
|
|
@@ -399,6 +410,12 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
// TODO: Implement QR code functionality |
|
|
|
}; |
|
|
|
|
|
|
|
const handleLotMismatch = useCallback((expectedLot: any, scannedLot: any) => { |
|
|
|
console.log("Lot mismatch detected:", { expectedLot, scannedLot }); |
|
|
|
setExpectedLotData(expectedLot); |
|
|
|
setScannedLotData(scannedLot); |
|
|
|
setLotConfirmationOpen(true); |
|
|
|
}, []); |
|
|
|
|
|
|
|
const fetchAllCombinedLotData = useCallback(async (userId?: number) => { |
|
|
|
setCombinedDataLoading(true); |
|
|
|
@@ -427,32 +444,38 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
setCombinedDataLoading(false); |
|
|
|
} |
|
|
|
}, [currentUserId]); |
|
|
|
|
|
|
|
// ✅ Only fetch existing data when session is ready, no auto-assignment |
|
|
|
useEffect(() => { |
|
|
|
if (session && currentUserId && !initializationRef.current) { |
|
|
|
console.log("✅ Session loaded, initializing pick order..."); |
|
|
|
initializationRef.current = true; |
|
|
|
|
|
|
|
// ✅ Only fetch existing data, no auto-assignment |
|
|
|
fetchAllCombinedLotData(); |
|
|
|
const handleLotConfirmation = useCallback(async () => { |
|
|
|
if (!expectedLotData || !scannedLotData || !selectedLotForQr) return; |
|
|
|
setIsConfirmingLot(true); |
|
|
|
try { |
|
|
|
let newLotLineId = scannedLotData?.inventoryLotLineId; |
|
|
|
if (!newLotLineId && scannedLotData?.stockInLineId) { |
|
|
|
const ld = await fetchLotDetail(scannedLotData.stockInLineId); |
|
|
|
newLotLineId = ld.inventoryLotLineId; |
|
|
|
} |
|
|
|
if (!newLotLineId) { |
|
|
|
console.error("No inventory lot line id for scanned lot"); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
await confirmLotSubstitution({ |
|
|
|
pickOrderLineId: selectedLotForQr.pickOrderLineId, |
|
|
|
stockOutLineId: selectedLotForQr.stockOutLineId, |
|
|
|
originalSuggestedPickLotId: selectedLotForQr.suggestedPickLotId, |
|
|
|
newInventoryLotLineId: newLotLineId |
|
|
|
}); |
|
|
|
|
|
|
|
setLotConfirmationOpen(false); |
|
|
|
setExpectedLotData(null); |
|
|
|
setScannedLotData(null); |
|
|
|
setSelectedLotForQr(null); |
|
|
|
await fetchAllCombinedLotData(); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error confirming lot substitution:", error); |
|
|
|
} finally { |
|
|
|
setIsConfirmingLot(false); |
|
|
|
} |
|
|
|
}, [session, currentUserId, fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
// ✅ Add event listener for manual assignment |
|
|
|
useEffect(() => { |
|
|
|
const handlePickOrderAssigned = () => { |
|
|
|
console.log("🔄 Pick order assigned event received, refreshing data..."); |
|
|
|
fetchAllCombinedLotData(); |
|
|
|
}; |
|
|
|
|
|
|
|
window.addEventListener('pickOrderAssigned', handlePickOrderAssigned); |
|
|
|
|
|
|
|
return () => { |
|
|
|
window.removeEventListener('pickOrderAssigned', handlePickOrderAssigned); |
|
|
|
}; |
|
|
|
}, [fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
}, [expectedLotData, scannedLotData, selectedLotForQr, fetchAllCombinedLotData]); |
|
|
|
const handleQrCodeSubmit = useCallback(async (lotNo: string) => { |
|
|
|
console.log(`✅ Processing QR Code for lot: ${lotNo}`); |
|
|
|
|
|
|
|
@@ -469,6 +492,8 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
console.error(`❌ Lot not found: ${lotNo}`); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
const availableLotNos = currentLotData.map(lot => lot.lotNo).join(', '); |
|
|
|
console.log(`❌ QR Code "${lotNo}" does not match any expected lots. Available lots: ${availableLotNos}`); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -483,38 +508,55 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
console.log(`🔄 Processing pick order line ${matchingLot.pickOrderLineId} for lot ${lotNo}`); |
|
|
|
|
|
|
|
if (matchingLot.stockOutLineId) { |
|
|
|
// ✅ FIXED: Only update status to 'checked', keep qty at 0 |
|
|
|
const stockOutLineUpdate = await updateStockOutLineStatus({ |
|
|
|
id: matchingLot.stockOutLineId, |
|
|
|
status: 'checked', |
|
|
|
qty: 0 // ✅ Keep qty at 0 until user actually submits |
|
|
|
qty: 0 |
|
|
|
}); |
|
|
|
console.log(`Update stock out line result for line ${matchingLot.pickOrderLineId}:`, stockOutLineUpdate); |
|
|
|
|
|
|
|
if (stockOutLineUpdate && stockOutLineUpdate.code === "SUCCESS") { |
|
|
|
console.log(`✅ Stock out line updated successfully for line ${matchingLot.pickOrderLineId}`); |
|
|
|
successCount++; |
|
|
|
} else { |
|
|
|
console.error(`❌ Failed to update stock out line for line ${matchingLot.pickOrderLineId}:`, stockOutLineUpdate); |
|
|
|
errorCount++; |
|
|
|
} |
|
|
|
} else { |
|
|
|
// ✅ If no stock out line exists, create one with qty = 0 |
|
|
|
const createStockOutLineData = { |
|
|
|
consoCode: matchingLot.pickOrderConsoCode, |
|
|
|
pickOrderLineId: matchingLot.pickOrderLineId, |
|
|
|
inventoryLotLineId: matchingLot.lotId, |
|
|
|
qty: 0 // ✅ Create with qty = 0 |
|
|
|
qty: 0 |
|
|
|
}; |
|
|
|
|
|
|
|
const createResult = await createStockOutLine(createStockOutLineData); |
|
|
|
console.log(`Create stock out line result for line ${matchingLot.pickOrderLineId}:`, createResult); |
|
|
|
|
|
|
|
if (createResult && createResult.code === "SUCCESS") { |
|
|
|
console.log(`✅ Stock out line created successfully for line ${matchingLot.pickOrderLineId}`); |
|
|
|
successCount++; |
|
|
|
// Immediately set status to checked for new line |
|
|
|
let newSolId: number | undefined; |
|
|
|
const anyRes: any = createResult as any; |
|
|
|
if (typeof anyRes?.id === 'number') { |
|
|
|
newSolId = anyRes.id; |
|
|
|
} else if (anyRes?.entity) { |
|
|
|
newSolId = Array.isArray(anyRes.entity) ? anyRes.entity[0]?.id : anyRes.entity?.id; |
|
|
|
} |
|
|
|
|
|
|
|
if (newSolId) { |
|
|
|
const setChecked = await updateStockOutLineStatus({ |
|
|
|
id: newSolId, |
|
|
|
status: 'checked', |
|
|
|
qty: 0 |
|
|
|
}); |
|
|
|
if (setChecked && setChecked.code === "SUCCESS") { |
|
|
|
successCount++; |
|
|
|
} else { |
|
|
|
errorCount++; |
|
|
|
} |
|
|
|
} else { |
|
|
|
console.warn("Created stock out line but no ID returned; cannot set to checked"); |
|
|
|
errorCount++; |
|
|
|
} |
|
|
|
} else { |
|
|
|
console.error(`❌ Failed to create stock out line for line ${matchingLot.pickOrderLineId}:`, createResult); |
|
|
|
errorCount++; |
|
|
|
} |
|
|
|
} |
|
|
|
@@ -531,18 +573,19 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
setQrScanInput(''); // Clear input after successful processing |
|
|
|
|
|
|
|
// ✅ Clear success state after a delay |
|
|
|
setTimeout(() => { |
|
|
|
setQrScanSuccess(false); |
|
|
|
}, 2000); |
|
|
|
|
|
|
|
//setTimeout(() => { |
|
|
|
//setQrScanSuccess(false); |
|
|
|
//}, 2000); |
|
|
|
} else { |
|
|
|
console.error(`❌ QR Code processing failed: ${errorCount} errors`); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
|
|
|
|
// ✅ Clear error state after a delay |
|
|
|
setTimeout(() => { |
|
|
|
setQrScanError(false); |
|
|
|
}, 3000); |
|
|
|
// setTimeout(() => { |
|
|
|
// setQrScanError(false); |
|
|
|
//}, 3000); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error processing QR code:", error); |
|
|
|
@@ -564,6 +607,152 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
}, 1000); |
|
|
|
} |
|
|
|
}, [combinedLotData, fetchAllCombinedLotData]); |
|
|
|
const processOutsideQrCode = useCallback(async (latestQr: string) => { |
|
|
|
// 1) Parse JSON safely |
|
|
|
let qrData: any = null; |
|
|
|
try { |
|
|
|
qrData = JSON.parse(latestQr); |
|
|
|
} catch { |
|
|
|
console.log("QR content is not JSON; skipping lotNo direct submit to avoid false matches."); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
// Only use the new API when we have JSON with stockInLineId + itemId |
|
|
|
if (!(qrData?.stockInLineId && qrData?.itemId)) { |
|
|
|
console.log("QR JSON missing required fields (itemId, stockInLineId)."); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Call new analyze-qr-code API |
|
|
|
const analysis = await analyzeQrCode({ |
|
|
|
itemId: qrData.itemId, |
|
|
|
stockInLineId: qrData.stockInLineId |
|
|
|
}); |
|
|
|
|
|
|
|
if (!analysis) { |
|
|
|
console.error("analyzeQrCode returned no data"); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const { |
|
|
|
itemId: analyzedItemId, |
|
|
|
itemCode: analyzedItemCode, |
|
|
|
itemName: analyzedItemName, |
|
|
|
scanned, |
|
|
|
} = analysis || {}; |
|
|
|
|
|
|
|
// 1) Find all lots for the same item from current expected list |
|
|
|
const sameItemLotsInExpected = combinedLotData.filter(l => |
|
|
|
(l.itemId && analyzedItemId && l.itemId === analyzedItemId) || |
|
|
|
(l.itemCode && analyzedItemCode && l.itemCode === analyzedItemCode) |
|
|
|
); |
|
|
|
|
|
|
|
if (!sameItemLotsInExpected || sameItemLotsInExpected.length === 0) { |
|
|
|
// Case 3: No item code match |
|
|
|
console.error("No item match in expected lots for scanned code"); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
|
|
|
|
return; |
|
|
|
} |
|
|
|
// 2) Check if scanned lot is exactly in expected lots |
|
|
|
const exactLotMatch = sameItemLotsInExpected.find(l => |
|
|
|
(scanned?.inventoryLotLineId && l.lotId === scanned.inventoryLotLineId) || |
|
|
|
(scanned?.lotNo && l.lotNo === scanned.lotNo) |
|
|
|
); |
|
|
|
|
|
|
|
if (exactLotMatch && scanned?.lotNo) { |
|
|
|
// Case 1: Normal case - item matches AND lot matches -> proceed |
|
|
|
console.log(`Exact lot match found for ${scanned.lotNo}, submitting QR`); |
|
|
|
handleQrCodeSubmit(scanned.lotNo); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Case 2: Item matches but lot number differs -> open confirmation modal |
|
|
|
const expectedLot = sameItemLotsInExpected[0]; |
|
|
|
if (!expectedLot) { |
|
|
|
console.error("Could not determine expected lot for confirmation"); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
setSelectedLotForQr(expectedLot); |
|
|
|
handleLotMismatch( |
|
|
|
{ |
|
|
|
lotNo: expectedLot.lotNo, |
|
|
|
itemCode: analyzedItemCode || expectedLot.itemCode, |
|
|
|
itemName: analyzedItemName || expectedLot.itemName |
|
|
|
}, |
|
|
|
{ |
|
|
|
lotNo: scanned?.lotNo || '', |
|
|
|
itemCode: analyzedItemCode || expectedLot.itemCode, |
|
|
|
itemName: analyzedItemName || expectedLot.itemName, |
|
|
|
inventoryLotLineId: scanned?.inventoryLotLineId, |
|
|
|
stockInLineId: qrData.stockInLineId |
|
|
|
} |
|
|
|
); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error during analyzeQrCode flow:", error); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
return; |
|
|
|
} |
|
|
|
}, [combinedLotData, handleQrCodeSubmit, handleLotMismatch]); |
|
|
|
// ✅ Update the outside QR scanning effect to use enhanced processing |
|
|
|
useEffect(() => { |
|
|
|
if (!isManualScanning || qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const latestQr = qrValues[qrValues.length - 1]; |
|
|
|
|
|
|
|
if (processedQrCodes.has(latestQr) || lastProcessedQr === latestQr) { |
|
|
|
console.log("QR code already processed, skipping..."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (latestQr && latestQr !== lastProcessedQr) { |
|
|
|
console.log(`🔍 Processing new QR code with enhanced validation: ${latestQr}`); |
|
|
|
setLastProcessedQr(latestQr); |
|
|
|
setProcessedQrCodes(prev => new Set(prev).add(latestQr)); |
|
|
|
|
|
|
|
processOutsideQrCode(latestQr); |
|
|
|
} |
|
|
|
}, [qrValues, isManualScanning, processedQrCodes, lastProcessedQr, isRefreshingData, processOutsideQrCode]); |
|
|
|
// ✅ Only fetch existing data when session is ready, no auto-assignment |
|
|
|
useEffect(() => { |
|
|
|
if (session && currentUserId && !initializationRef.current) { |
|
|
|
console.log("✅ Session loaded, initializing pick order..."); |
|
|
|
initializationRef.current = true; |
|
|
|
|
|
|
|
// ✅ Only fetch existing data, no auto-assignment |
|
|
|
fetchAllCombinedLotData(); |
|
|
|
} |
|
|
|
}, [session, currentUserId, fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
// ✅ Add event listener for manual assignment |
|
|
|
useEffect(() => { |
|
|
|
const handlePickOrderAssigned = () => { |
|
|
|
console.log("🔄 Pick order assigned event received, refreshing data..."); |
|
|
|
fetchAllCombinedLotData(); |
|
|
|
}; |
|
|
|
|
|
|
|
window.addEventListener('pickOrderAssigned', handlePickOrderAssigned); |
|
|
|
|
|
|
|
return () => { |
|
|
|
window.removeEventListener('pickOrderAssigned', handlePickOrderAssigned); |
|
|
|
}; |
|
|
|
}, [fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleManualInputSubmit = useCallback(() => { |
|
|
|
if (qrScanInput.trim() !== '') { |
|
|
|
@@ -612,55 +801,6 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
} |
|
|
|
}, [selectedLotForQr, fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
// ✅ Outside QR scanning - process QR codes from outside the page automatically |
|
|
|
useEffect(() => { |
|
|
|
// ✅ Don't process QR codes when refreshing data or if not manually scanning |
|
|
|
if (!isManualScanning || qrValues.length === 0 || combinedLotData.length === 0 || isRefreshingData) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const latestQr = qrValues[qrValues.length - 1]; |
|
|
|
|
|
|
|
// ✅ Prevent processing the same QR code multiple times |
|
|
|
if (processedQrCodes.has(latestQr) || lastProcessedQr === latestQr) { |
|
|
|
console.log(" QR code already processed, skipping..."); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (latestQr && latestQr !== lastProcessedQr) { |
|
|
|
console.log(` Processing new QR code: ${latestQr}`); |
|
|
|
setLastProcessedQr(latestQr); |
|
|
|
setProcessedQrCodes(prev => new Set(prev).add(latestQr)); |
|
|
|
|
|
|
|
let lotNo = ''; |
|
|
|
try { |
|
|
|
const qrData = JSON.parse(latestQr); |
|
|
|
if (qrData.stockInLineId && qrData.itemId) { |
|
|
|
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; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
lotNo = latestQr.replace(/[{}]/g, ''); |
|
|
|
} |
|
|
|
|
|
|
|
if (lotNo) { |
|
|
|
console.log(`Outside QR scan detected (direct): ${lotNo}`); |
|
|
|
handleQrCodeSubmit(lotNo); |
|
|
|
} |
|
|
|
} |
|
|
|
}, [qrValues, isManualScanning, processedQrCodes, lastProcessedQr, isRefreshingData, handleQrCodeSubmit]); |
|
|
|
|
|
|
|
|
|
|
|
const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => { |
|
|
|
if (value === '' || value === null || value === undefined) { |
|
|
|
@@ -1026,12 +1166,16 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
setIsManualScanning(true); |
|
|
|
setProcessedQrCodes(new Set()); |
|
|
|
setLastProcessedQr(''); |
|
|
|
setQrScanError(false); |
|
|
|
setQrScanSuccess(false); |
|
|
|
startScan(); |
|
|
|
}, [startScan]); |
|
|
|
|
|
|
|
const handleStopScan = useCallback(() => { |
|
|
|
console.log("⏹️ Stopping manual QR scan..."); |
|
|
|
setIsManualScanning(false); |
|
|
|
setQrScanError(false); |
|
|
|
setQrScanSuccess(false); |
|
|
|
stopScan(); |
|
|
|
resetScan(); |
|
|
|
}, [stopScan, resetScan]); |
|
|
|
@@ -1074,6 +1218,9 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Pick Order Code")}:</strong>{fgPickOrders[0].pickOrderCode || '-'} |
|
|
|
</Typography> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Store ID")}:</strong> {fgPickOrders[0].storeId || '-'} |
|
|
|
</Typography> |
|
|
|
<Typography variant="subtitle1"> |
|
|
|
<strong>{t("Ticket No.")}:</strong> {fgPickOrders[0].ticketNo || '-'} |
|
|
|
</Typography> |
|
|
|
@@ -1125,8 +1272,20 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
</Typography> |
|
|
|
</Box> |
|
|
|
)} |
|
|
|
|
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
|
|
|
|
{qrScanError && ( |
|
|
|
<Alert severity="error" sx={{ mb: 2 }}> |
|
|
|
{t("QR code does not match any item in current orders.")} |
|
|
|
</Alert> |
|
|
|
)} |
|
|
|
{qrScanSuccess && ( |
|
|
|
<Alert severity="success" sx={{ mb: 2 }}> |
|
|
|
{t("QR code verified.")} |
|
|
|
</Alert> |
|
|
|
)} |
|
|
|
|
|
|
|
<TableContainer component={Paper}> |
|
|
|
<Table> |
|
|
|
@@ -1134,6 +1293,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
<TableRow> |
|
|
|
<TableCell>{t("Index")}</TableCell> |
|
|
|
<TableCell>{t("Route")}</TableCell> |
|
|
|
<TableCell>{t("Item Code")}</TableCell> |
|
|
|
<TableCell>{t("Item Name")}</TableCell> |
|
|
|
<TableCell>{t("Lot#")}</TableCell> |
|
|
|
{/* <TableCell>{t("Target Date")}</TableCell> */} |
|
|
|
@@ -1178,6 +1338,7 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
{lot.routerRoute || '-'} |
|
|
|
</Typography> |
|
|
|
</TableCell> |
|
|
|
<TableCell>{lot.itemCode}</TableCell> |
|
|
|
<TableCell>{lot.itemName+'('+lot.stockUnit+')'}</TableCell> |
|
|
|
<TableCell> |
|
|
|
<Box> |
|
|
|
@@ -1323,7 +1484,21 @@ const handleSubmitPickQtyWithQty = useCallback(async (lot: any, submitQty: numbe |
|
|
|
combinedLotData={combinedLotData} // ✅ Add this prop |
|
|
|
onQrCodeSubmit={handleQrCodeSubmitFromModal} |
|
|
|
/> |
|
|
|
|
|
|
|
{/* ✅ Lot Confirmation Modal */} |
|
|
|
{lotConfirmationOpen && expectedLotData && scannedLotData && ( |
|
|
|
<LotConfirmationModal |
|
|
|
open={lotConfirmationOpen} |
|
|
|
onClose={() => { |
|
|
|
setLotConfirmationOpen(false); |
|
|
|
setExpectedLotData(null); |
|
|
|
setScannedLotData(null); |
|
|
|
}} |
|
|
|
onConfirm={handleLotConfirmation} |
|
|
|
expectedLot={expectedLotData} |
|
|
|
scannedLot={scannedLotData} |
|
|
|
isLoading={isConfirmingLot} |
|
|
|
/> |
|
|
|
)} |
|
|
|
{/* ✅ Good Pick Execution Form Modal */} |
|
|
|
{pickExecutionFormOpen && selectedLotForExecutionForm && ( |
|
|
|
<GoodPickExecutionForm |
|
|
|
|