|
|
|
@@ -59,7 +59,8 @@ const QrCodeModal: React.FC<{ |
|
|
|
onClose: () => void; |
|
|
|
lot: any | null; |
|
|
|
onQrCodeSubmit: (lotNo: string) => void; |
|
|
|
}> = ({ open, onClose, lot, onQrCodeSubmit }) => { |
|
|
|
combinedLotData: any[]; // ✅ Add this prop |
|
|
|
}> = ({ open, onClose, lot, onQrCodeSubmit, combinedLotData }) => { |
|
|
|
const { t } = useTranslation("pickOrder"); |
|
|
|
const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext(); |
|
|
|
const [manualInput, setManualInput] = useState<string>(''); |
|
|
|
@@ -398,11 +399,15 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
// const handleAutoAssignAndRelease = useCallback(async () => { ... }); // 删除这个函数 |
|
|
|
|
|
|
|
// ✅ Handle QR code submission for matched lot (external scanning) |
|
|
|
const handleQrCodeSubmit = useCallback(async (lotNo: string) => { |
|
|
|
// ✅ Handle QR code submission for matched lot (external scanning) |
|
|
|
const handleQrCodeSubmit = useCallback(async (lotNo: string) => { |
|
|
|
console.log(`✅ Processing QR Code for lot: ${lotNo}`); |
|
|
|
console.log(`🔍 Available lots:`, combinedLotData.map(lot => lot.lotNo)); |
|
|
|
|
|
|
|
const matchingLots = combinedLotData.filter(lot => |
|
|
|
// ✅ Use current data without refreshing to avoid infinite loop |
|
|
|
const currentLotData = combinedLotData; |
|
|
|
console.log(`🔍 Available lots:`, currentLotData.map(lot => lot.lotNo)); |
|
|
|
|
|
|
|
const matchingLots = currentLotData.filter(lot => |
|
|
|
lot.lotNo === lotNo || |
|
|
|
lot.lotNo?.toLowerCase() === lotNo.toLowerCase() |
|
|
|
); |
|
|
|
@@ -430,7 +435,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
existsCount++; |
|
|
|
} else { |
|
|
|
const stockOutLineData: CreateStockOutLine = { |
|
|
|
consoCode: matchingLot.pickOrderConsoCode, // ✅ Use pickOrderConsoCode instead of pickOrderCode |
|
|
|
consoCode: matchingLot.pickOrderConsoCode, |
|
|
|
pickOrderLineId: matchingLot.pickOrderLineId, |
|
|
|
inventoryLotLineId: matchingLot.lotId, |
|
|
|
qty: 0.0 |
|
|
|
@@ -447,40 +452,56 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
console.log(`✅ Stock out line created successfully for line ${matchingLot.pickOrderLineId}`); |
|
|
|
successCount++; |
|
|
|
} else { |
|
|
|
console.error(`❌ Unexpected response for line ${matchingLot.pickOrderLineId}:`, result); |
|
|
|
console.error(`❌ Failed to create stock out line for line ${matchingLot.pickOrderLineId}:`, result); |
|
|
|
errorCount++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const lotKey = `${matchingLot.pickOrderLineId}-${matchingLot.lotId}`; |
|
|
|
setPickQtyData(prev => ({ |
|
|
|
...prev, |
|
|
|
[lotKey]: matchingLot.requiredQty |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
// ✅ Always refresh data after processing (success or failure) |
|
|
|
console.log("🔄 Refreshing data after QR code processing..."); |
|
|
|
await fetchAllCombinedLotData(); |
|
|
|
|
|
|
|
if (successCount > 0 || existsCount > 0) { |
|
|
|
console.log(`✅ QR Code processing completed: ${successCount} created, ${existsCount} already existed`); |
|
|
|
setQrScanSuccess(true); |
|
|
|
setQrScanError(false); |
|
|
|
console.log(`✅ QR Code processing completed: ${successCount} created, ${existsCount} already existed, ${errorCount} errors`); |
|
|
|
setQrScanInput(''); // Clear input after successful processing |
|
|
|
|
|
|
|
// ✅ Clear success state after a delay |
|
|
|
setTimeout(() => { |
|
|
|
setQrScanSuccess(false); |
|
|
|
}, 2000); |
|
|
|
} else { |
|
|
|
console.error(`❌ QR Code processing failed: ${errorCount} errors`); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
console.error(`❌ All operations failed for lot ${lotNo}`); |
|
|
|
return; |
|
|
|
|
|
|
|
// ✅ Clear error state after a delay |
|
|
|
setTimeout(() => { |
|
|
|
setQrScanError(false); |
|
|
|
}, 3000); |
|
|
|
} |
|
|
|
|
|
|
|
await fetchAllCombinedLotData(); |
|
|
|
setQrScanInput(''); |
|
|
|
|
|
|
|
console.log("Stock out line process completed successfully!"); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error creating stock out line:", error); |
|
|
|
console.error("❌ Error processing QR code:", error); |
|
|
|
setQrScanError(true); |
|
|
|
setQrScanSuccess(false); |
|
|
|
|
|
|
|
// ✅ Still refresh data even on error |
|
|
|
await fetchAllCombinedLotData(); |
|
|
|
|
|
|
|
// ✅ Clear error state after a delay |
|
|
|
setTimeout(() => { |
|
|
|
setQrScanError(false); |
|
|
|
}, 3000); |
|
|
|
} |
|
|
|
}, [combinedLotData, fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
const handleManualInputSubmit = useCallback(() => { |
|
|
|
if (qrScanInput.trim() !== '') { |
|
|
|
handleQrCodeSubmit(qrScanInput.trim()); |
|
|
|
} |
|
|
|
}, [qrScanInput, handleQrCodeSubmit]); |
|
|
|
|
|
|
|
// ✅ Handle QR code submission from modal (internal scanning) |
|
|
|
const handleQrCodeSubmitFromModal = useCallback(async (lotNo: string) => { |
|
|
|
if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) { |
|
|
|
@@ -523,22 +544,44 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
} |
|
|
|
}, [selectedLotForQr, fetchAllCombinedLotData]); |
|
|
|
|
|
|
|
// ✅ External QR scanning - process QR codes from outside the page |
|
|
|
// ✅ 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]; |
|
|
|
const qrContent = latestQr.replace(/[{}]/g, ''); |
|
|
|
setQrScanInput(qrContent); |
|
|
|
|
|
|
|
handleQrCodeSubmit(qrContent); |
|
|
|
// 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 handleManualInputSubmit = useCallback(() => { |
|
|
|
if (qrScanInput.trim() !== '') { |
|
|
|
handleQrCodeSubmit(qrScanInput.trim()); |
|
|
|
} |
|
|
|
}, [qrScanInput, handleQrCodeSubmit]); |
|
|
|
|
|
|
|
const handlePickQtyChange = useCallback((lotKey: string, value: number | string) => { |
|
|
|
if (value === '' || value === null || value === undefined) { |
|
|
|
@@ -836,41 +879,8 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
<Typography variant="h6" gutterBottom sx={{ mb: 0 }}> |
|
|
|
{t("All Pick Order Lots")} |
|
|
|
</Typography> |
|
|
|
{/* ✅ External QR scan input - for scanning from outside the page */} |
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> |
|
|
|
<TextField |
|
|
|
size="small" |
|
|
|
value={qrScanInput} |
|
|
|
onChange={(e) => setQrScanInput(e.target.value)} |
|
|
|
onKeyPress={(e) => { |
|
|
|
if (e.key === 'Enter') { |
|
|
|
handleManualInputSubmit(); |
|
|
|
} |
|
|
|
}} |
|
|
|
error={qrScanError} |
|
|
|
color={qrScanSuccess ? 'success' : undefined} |
|
|
|
helperText={ |
|
|
|
qrScanError |
|
|
|
? t("Lot number not found") |
|
|
|
: qrScanSuccess |
|
|
|
? t("Lot processed successfully") |
|
|
|
: t("Enter lot number or scan QR code") |
|
|
|
} |
|
|
|
placeholder={t("Enter lot number...")} |
|
|
|
sx={{ minWidth: '250px' }} |
|
|
|
InputProps={{ |
|
|
|
startAdornment: <QrCodeIcon sx={{ mr: 1, color: isScanning ? 'primary.main' : 'text.secondary' }} />, |
|
|
|
}} |
|
|
|
/> |
|
|
|
<Button |
|
|
|
variant="outlined" |
|
|
|
onClick={handleManualInputSubmit} |
|
|
|
disabled={!qrScanInput.trim()} |
|
|
|
size="small" |
|
|
|
> |
|
|
|
{t("Submit")} |
|
|
|
</Button> |
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
<TableContainer component={Paper}> |
|
|
|
@@ -923,7 +933,9 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
}} |
|
|
|
> |
|
|
|
{lot.lotNo} |
|
|
|
|
|
|
|
</Typography> |
|
|
|
{/* |
|
|
|
{lot.lotAvailability !== 'available' && ( |
|
|
|
<Typography variant="caption" color="error" display="block"> |
|
|
|
({lot.lotAvailability === 'expired' ? 'Expired' : |
|
|
|
@@ -931,7 +943,8 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
lot.lotAvailability === 'rejected' ? 'Rejected' : |
|
|
|
'Unavailable'}) |
|
|
|
</Typography> |
|
|
|
)} |
|
|
|
|
|
|
|
)*/} |
|
|
|
</Box> |
|
|
|
</TableCell> |
|
|
|
<TableCell>{lot.pickOrderTargetDate}</TableCell> |
|
|
|
@@ -1091,6 +1104,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { |
|
|
|
resetScan(); |
|
|
|
}} |
|
|
|
lot={selectedLotForQr} |
|
|
|
combinedLotData={combinedLotData} // ✅ Add this prop |
|
|
|
onQrCodeSubmit={handleQrCodeSubmitFromModal} |
|
|
|
/> |
|
|
|
|
|
|
|
|