|
|
|
@@ -429,7 +429,21 @@ const LotTable: React.FC<LotTableProps> = ({ |
|
|
|
return t("Please finish QR code scan and pick order."); |
|
|
|
} |
|
|
|
}, [t]); |
|
|
|
|
|
|
|
const handleOpenQrModal = useCallback((lot: LotPickData) => { |
|
|
|
setSelectedLotForQr(lot); |
|
|
|
setManualQrInput(lot.lotNo ?? ""); |
|
|
|
setValidationErrors({}); |
|
|
|
setQrModalOpen(true); |
|
|
|
resetScan(); |
|
|
|
startScan(); |
|
|
|
}, [startScan, resetScan]); |
|
|
|
|
|
|
|
const handleCloseQrModal = useCallback(() => { |
|
|
|
setQrModalOpen(false); |
|
|
|
setSelectedLotForQr(null); |
|
|
|
stopScan(); |
|
|
|
resetScan(); |
|
|
|
}, [stopScan, resetScan]); |
|
|
|
const prepareLotTableData = useMemo(() => { |
|
|
|
return lotData.map((lot) => ({ |
|
|
|
...lot, |
|
|
|
@@ -477,9 +491,55 @@ const LotTable: React.FC<LotTableProps> = ({ |
|
|
|
}, [calculateRemainingAvailableQty, calculateRemainingRequiredQty, t]); |
|
|
|
|
|
|
|
const handleQrCodeSubmit = useCallback(async (lotNo: string) => { |
|
|
|
// ... 保持你原本的 QR 提交邏輯 ... |
|
|
|
}, [selectedLotForQr, selectedRowId, onPickQtyChange, onLotDataRefresh]); |
|
|
|
|
|
|
|
if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) { |
|
|
|
console.log(` QR Code verified for lot: ${lotNo}`); |
|
|
|
if (!selectedLotForQr.stockOutLineId) { |
|
|
|
console.error("No stock out line ID found for this lot"); |
|
|
|
alert("No stock out line found for this lot. Please contact administrator."); |
|
|
|
return; |
|
|
|
} |
|
|
|
// Store the required quantity before creating stock out line |
|
|
|
const requiredQty = selectedLotForQr.requiredQty; |
|
|
|
const lotId = selectedLotForQr.lotId; |
|
|
|
|
|
|
|
try { |
|
|
|
// Update stock out line status to 'checked' (QR scan completed) |
|
|
|
const stockOutLineUpdate = await updateStockOutLineStatus({ |
|
|
|
id: selectedLotForQr.stockOutLineId, |
|
|
|
status: 'checked', |
|
|
|
qty: selectedLotForQr.stockOutLineQty || 0 |
|
|
|
}); |
|
|
|
|
|
|
|
console.log(" Stock out line updated to 'checked':", stockOutLineUpdate); |
|
|
|
|
|
|
|
// Close modal |
|
|
|
setQrModalOpen(false); |
|
|
|
setSelectedLotForQr(null); |
|
|
|
if (onLotDataRefresh) { |
|
|
|
await onLotDataRefresh(); |
|
|
|
} |
|
|
|
// Set pick quantity AFTER stock out line update is complete |
|
|
|
if (selectedRowId) { |
|
|
|
// Add a small delay to ensure the data refresh is complete |
|
|
|
setTimeout(() => { |
|
|
|
onPickQtyChange(selectedRowId, lotId ?? 0, requiredQty); |
|
|
|
console.log(` Auto-set pick quantity to ${requiredQty} for lot ${lotNo}`); |
|
|
|
}, 500); // 500ms delay to ensure refresh is complete |
|
|
|
} |
|
|
|
|
|
|
|
// Show success message |
|
|
|
console.log("Stock out line updated successfully!"); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error("❌ Error updating stock out line status:", error); |
|
|
|
alert("Failed to update lot status. Please try again."); |
|
|
|
} |
|
|
|
} else { |
|
|
|
// Handle case where lot numbers don't match |
|
|
|
console.error("QR scan mismatch:", { scanned: lotNo, expected: selectedLotForQr?.lotNo }); |
|
|
|
alert(`QR scan mismatch! Expected: ${selectedLotForQr?.lotNo}, Scanned: ${lotNo}`); |
|
|
|
} |
|
|
|
}, [selectedLotForQr, selectedRowId, onPickQtyChange]); |
|
|
|
// PickExecutionForm 狀態與提交(保持原本邏輯) |
|
|
|
const [pickExecutionFormOpen, setPickExecutionFormOpen] = useState(false); |
|
|
|
const [selectedLotForExecutionForm, setSelectedLotForExecutionForm] = useState<LotPickData | null>(null); |
|
|
|
@@ -606,9 +666,73 @@ const LotTable: React.FC<LotTableProps> = ({ |
|
|
|
})()} |
|
|
|
</TableCell> |
|
|
|
<TableCell align="center"> |
|
|
|
{/* 已掃碼後的實際數量 + Issue 按鈕(保持原有邏輯,略) */} |
|
|
|
{/* 對 noLot 行而言這裡通常保持為 0/禁用 */} |
|
|
|
</TableCell> |
|
|
|
{lot.stockOutLineStatus?.toLowerCase() === 'pending' ? ( |
|
|
|
<Button |
|
|
|
variant="outlined" |
|
|
|
size="small" |
|
|
|
startIcon={<QrCodeIcon />} |
|
|
|
onClick={() => handleOpenQrModal(lot)} |
|
|
|
disabled={ |
|
|
|
lot.lotAvailability === 'expired' || |
|
|
|
lot.lotAvailability === 'status_unavailable' || |
|
|
|
lot.lotAvailability === 'rejected' || |
|
|
|
selectedLotRowId !== `row_${index}` |
|
|
|
} |
|
|
|
sx={{ fontSize: '0.7rem', minHeight: 40, minWidth: 100 }} |
|
|
|
title={ |
|
|
|
selectedLotRowId !== `row_${index}` |
|
|
|
? t("Please select this lot first to enable QR scanning") |
|
|
|
: t("Click to scan QR code") |
|
|
|
} |
|
|
|
> |
|
|
|
{t("Scan")} |
|
|
|
</Button> |
|
|
|
) : ( |
|
|
|
<Stack direction="row" spacing={1} alignItems="center" justifyContent="center"> |
|
|
|
<TextField |
|
|
|
type="number" |
|
|
|
size="small" |
|
|
|
value={ |
|
|
|
selectedRowId && lot.lotId != null |
|
|
|
? pickQtyData[selectedRowId]?.[lot.lotId] ?? '' |
|
|
|
: '' |
|
|
|
} |
|
|
|
onChange={(e) => { |
|
|
|
if (selectedRowId && lot.lotId != null) { |
|
|
|
onPickQtyChange(selectedRowId, lot.lotId, Number(e.target.value) || 0); |
|
|
|
} |
|
|
|
}} |
|
|
|
disabled={ |
|
|
|
lot.lotAvailability === 'expired' || |
|
|
|
lot.lotAvailability === 'status_unavailable' || |
|
|
|
lot.lotAvailability === 'rejected' || |
|
|
|
selectedLotRowId !== `row_${index}` || |
|
|
|
lot.stockOutLineStatus === 'completed' |
|
|
|
} |
|
|
|
error={!!validationErrors[`lot_${lot.lotId}`]} |
|
|
|
helperText={validationErrors[`lot_${lot.lotId}`]} |
|
|
|
inputProps={{ min: 0, max: calculateRemainingRequiredQty(lot) }} |
|
|
|
sx={{ width: 70 }} |
|
|
|
placeholder="0" |
|
|
|
/> |
|
|
|
<Button |
|
|
|
variant="outlined" |
|
|
|
size="small" |
|
|
|
onClick={() => handlePickExecutionForm(lot)} |
|
|
|
disabled={ |
|
|
|
lot.lotAvailability === 'expired' || |
|
|
|
lot.lotAvailability === 'status_unavailable' || |
|
|
|
lot.lotAvailability === 'rejected' || |
|
|
|
selectedLotRowId !== `row_${index}` |
|
|
|
} |
|
|
|
sx={{ fontSize: '0.7rem', minWidth: 70, borderColor: 'warning.main', color: 'warning.main' }} |
|
|
|
title={t("Report missing or bad items")} |
|
|
|
> |
|
|
|
{t("Issue")} |
|
|
|
</Button> |
|
|
|
</Stack> |
|
|
|
)} |
|
|
|
</TableCell> |
|
|
|
<TableCell align="right"> |
|
|
|
{calculateRemainingAvailableQty(lot).toLocaleString()} |
|
|
|
</TableCell> |
|
|
|
@@ -680,7 +804,12 @@ const LotTable: React.FC<LotTableProps> = ({ |
|
|
|
</TableContainer> |
|
|
|
|
|
|
|
{/* Status message & pagination & modals 保持原有程式不變(略) */} |
|
|
|
|
|
|
|
<QrCodeModal |
|
|
|
open={qrModalOpen} |
|
|
|
onClose={handleCloseQrModal} |
|
|
|
lot={selectedLotForQr} |
|
|
|
onQrCodeSubmit={handleQrCodeSubmit} |
|
|
|
/> |
|
|
|
{pickExecutionFormOpen && selectedLotForExecutionForm && selectedRow && ( |
|
|
|
<PickExecutionForm |
|
|
|
open={pickExecutionFormOpen} |
|
|
|
|