diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index bc11775..9552aa5 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -280,6 +280,7 @@ export interface PickOrderLotDetailResponse { expiryDate: string; location: string; stockUnit: string; + inQty: number; availableQty: number; requiredQty: number; actualPickQty: number; diff --git a/src/components/FinishedGoodSearch/AssignAndRelease.tsx b/src/components/FinishedGoodSearch/AssignAndRelease.tsx index 8c84893..5c9582d 100644 --- a/src/components/FinishedGoodSearch/AssignAndRelease.tsx +++ b/src/components/FinishedGoodSearch/AssignAndRelease.tsx @@ -24,6 +24,7 @@ import { useTranslation } from "react-i18next"; import { newassignPickOrder, AssignPickOrderInputs, + releaseAssignedPickOrders, // Add this import } from "@/app/api/pickOrder/actions"; import { fetchNameList, NameList ,fetchNewNameList, NewNameList} from "@/app/api/user/actions"; import { FormProvider, useForm } from "react-hook-form"; @@ -323,7 +324,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { setPagingController(newPagingController); }, []); - const handleAssignAndRelease = useCallback(async (data: AssignPickOrderInputs) => { + const handleAssignOnly = useCallback(async (data: AssignPickOrderInputs) => { if (selectedPickOrderIds.length === 0) return; setIsUploading(true); @@ -349,6 +350,44 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { } }, [selectedPickOrderIds, setIsUploading, fetchNewPageItems, pagingController, filterArgs]); + const handleAssignAndReleaseCombined = useCallback(async (data: AssignPickOrderInputs) => { + if (selectedPickOrderIds.length === 0) return; + + setIsUploading(true); + try { + // Step 1: Assign the pick orders + const assignRes = await newassignPickOrder({ + pickOrderIds: selectedPickOrderIds, + assignTo: data.assignTo, + }); + + if (assignRes && assignRes.code === "SUCCESS") { + console.log("Assign successful:", assignRes); + + // Step 2: Release the assigned pick orders + const releaseRes = await releaseAssignedPickOrders({ + pickOrderIds: selectedPickOrderIds, + assignTo: data.assignTo, + }); + + if (releaseRes && releaseRes.code === "SUCCESS") { + console.log("Assign and Release successful:", releaseRes); + setModalOpen(false); + setSelectedPickOrderIds([]); // 清空选择 + fetchNewPageItems(pagingController, filterArgs); + } else { + console.error("Release failed:", releaseRes); + } + } else { + console.error("Assign failed:", assignRes); + } + } catch (error) { + console.error("Error in assign and release:", error); + } finally { + setIsUploading(false); + } + }, [selectedPickOrderIds, setIsUploading, fetchNewPageItems, pagingController, filterArgs]); + const openAssignModal = useCallback(() => { setModalOpen(true); formProps.reset(); @@ -464,8 +503,6 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { ) : null} - - {/* Pick Order Status - 只在第一个项目显示 */} {index === 0 ? upperFirst(item.status) : null} @@ -541,7 +578,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { -
+ @@ -579,7 +616,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { - {t("This action will assign the selected pick orders to picker.")} + {t("Select an action for the assigned pick orders.")} @@ -587,9 +624,20 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { - + diff --git a/src/components/FinishedGoodSearch/LotTable.tsx b/src/components/FinishedGoodSearch/LotTable.tsx index 7f4beda..8ae15df 100644 --- a/src/components/FinishedGoodSearch/LotTable.tsx +++ b/src/components/FinishedGoodSearch/LotTable.tsx @@ -372,7 +372,7 @@ const LotTable: React.FC = ({ switch (lot.stockOutLineStatus?.toLowerCase()) { case 'pending': - return t("Please finish QC check and pick order."); + return t("Please submit pick order."); case 'checked': return t("Please submit the pick order."); case 'partially_completed': diff --git a/src/components/PickOrderSearch/AssignAndRelease.tsx b/src/components/PickOrderSearch/AssignAndRelease.tsx index 8c84893..c11d48a 100644 --- a/src/components/PickOrderSearch/AssignAndRelease.tsx +++ b/src/components/PickOrderSearch/AssignAndRelease.tsx @@ -24,6 +24,7 @@ import { useTranslation } from "react-i18next"; import { newassignPickOrder, AssignPickOrderInputs, + releaseAssignedPickOrders, } from "@/app/api/pickOrder/actions"; import { fetchNameList, NameList ,fetchNewNameList, NewNameList} from "@/app/api/user/actions"; import { FormProvider, useForm } from "react-hook-form"; @@ -323,7 +324,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { setPagingController(newPagingController); }, []); - const handleAssignAndRelease = useCallback(async (data: AssignPickOrderInputs) => { + const handleAssignOnly = useCallback(async (data: AssignPickOrderInputs) => { if (selectedPickOrderIds.length === 0) return; setIsUploading(true); @@ -349,6 +350,44 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { } }, [selectedPickOrderIds, setIsUploading, fetchNewPageItems, pagingController, filterArgs]); + const handleAssignAndReleaseCombined = useCallback(async (data: AssignPickOrderInputs) => { + if (selectedPickOrderIds.length === 0) return; + + setIsUploading(true); + try { + // Step 1: Assign the pick orders + const assignRes = await newassignPickOrder({ + pickOrderIds: selectedPickOrderIds, + assignTo: data.assignTo, + }); + + if (assignRes && assignRes.code === "SUCCESS") { + console.log("Assign successful:", assignRes); + + // Step 2: Release the assigned pick orders + const releaseRes = await releaseAssignedPickOrders({ + pickOrderIds: selectedPickOrderIds, + assignTo: data.assignTo, + }); + + if (releaseRes && releaseRes.code === "SUCCESS") { + console.log("Assign and Release successful:", releaseRes); + setModalOpen(false); + setSelectedPickOrderIds([]); // 清空选择 + fetchNewPageItems(pagingController, filterArgs); + } else { + console.error("Release failed:", releaseRes); + } + } else { + console.error("Assign failed:", assignRes); + } + } catch (error) { + console.error("Error in assign and release:", error); + } finally { + setIsUploading(false); + } + }, [selectedPickOrderIds, setIsUploading, fetchNewPageItems, pagingController, filterArgs]); + const openAssignModal = useCallback(() => { setModalOpen(true); formProps.reset(); @@ -464,8 +503,6 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { ) : null} - - {/* Pick Order Status - 只在第一个项目显示 */} {index === 0 ? upperFirst(item.status) : null} @@ -541,7 +578,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { - + @@ -579,7 +616,7 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { - {t("This action will assign the selected pick orders to picker.")} + {t("Select an action for the assigned pick orders.")} @@ -587,9 +624,20 @@ const AssignAndRelease: React.FC = ({ filterArgs }) => { - + diff --git a/src/components/PickOrderSearch/LotTable.tsx b/src/components/PickOrderSearch/LotTable.tsx index 0fe63ee..0e0165a 100644 --- a/src/components/PickOrderSearch/LotTable.tsx +++ b/src/components/PickOrderSearch/LotTable.tsx @@ -24,6 +24,7 @@ import { GetPickOrderLineInfo } from "@/app/api/pickOrder/actions"; import { useQrCodeScannerContext } from '../QrCodeScannerProvider/QrCodeScannerProvider'; import { updateInventoryLotLineStatus } from "@/app/api/inventory/actions"; import { updateStockOutLineStatus } from "@/app/api/pickOrder/actions"; +import { fetchStockInLineInfo } from "@/app/api/po/actions"; // ✅ Add this import interface LotPickData { id: number; lotId: number; @@ -31,6 +32,7 @@ interface LotPickData { expiryDate: string; location: string; stockUnit: string; + inQty: number; availableQty: number; requiredQty: number; actualPickQty: number; @@ -65,6 +67,7 @@ interface LotTableProps { selectedLotForInput: LotPickData | null; generateInputBody: () => any; onDataRefresh: () => Promise; + onLotDataRefresh: () => Promise; } // ✅ QR Code Modal Component @@ -81,24 +84,114 @@ const QrCodeModal: React.FC<{ // ✅ Add state to track manual input submission const [manualInputSubmitted, setManualInputSubmitted] = useState(false); const [manualInputError, setManualInputError] = useState(false); + const [isProcessingQr, setIsProcessingQr] = useState(false); + const [qrScanFailed, setQrScanFailed] = useState(false); + const [qrScanSuccess, setQrScanSuccess] = useState(false); + + // ✅ Add state to track processed QR codes to prevent re-processing + const [processedQrCodes, setProcessedQrCodes] = useState>(new Set()); + + // ✅ Add state to store the scanned QR result + const [scannedQrResult, setScannedQrResult] = useState(''); - // ✅ Process scanned QR codes + // ✅ Process scanned QR codes with new format useEffect(() => { - if (qrValues.length > 0 && lot) { + if (qrValues.length > 0 && lot && !isProcessingQr && !qrScanSuccess) { const latestQr = qrValues[qrValues.length - 1]; - const qrContent = latestQr.replace(/[{}]/g, ''); - if (qrContent === lot.lotNo) { - onQrCodeSubmit(lot.lotNo); - onClose(); - resetScan(); - } else { - // ✅ Set error state for helper text - setManualInputError(true); - setManualInputSubmitted(true); + // ✅ Check if this QR code has already been processed + if (processedQrCodes.has(latestQr)) { + console.log("QR code already processed, skipping..."); + return; + } + + // ✅ Add to processed set immediately to prevent re-processing + setProcessedQrCodes(prev => new Set(prev).add(latestQr)); + + try { + // ✅ Parse QR code as JSON + const qrData = JSON.parse(latestQr); + + // ✅ Check if it has the expected structure + if (qrData.stockInLineId && qrData.itemId) { + setIsProcessingQr(true); + setQrScanFailed(false); + + // ✅ Fetch stock in line info to get lotNo + fetchStockInLineInfo(qrData.stockInLineId) + .then((stockInLineInfo) => { + console.log("Stock in line info:", stockInLineInfo); + + // ✅ Store the scanned result for display + setScannedQrResult(stockInLineInfo.lotNo || 'Unknown lot number'); + + // ✅ Compare lotNo from API with expected lotNo + if (stockInLineInfo.lotNo === lot.lotNo) { + console.log(`✅ QR Code verified for lot: ${lot.lotNo}`); + setQrScanSuccess(true); + onQrCodeSubmit(lot.lotNo); + onClose(); + resetScan(); + } else { + console.log(`❌ QR Code mismatch. Expected: ${lot.lotNo}, Got: ${stockInLineInfo.lotNo}`); + setQrScanFailed(true); + setManualInputError(true); + setManualInputSubmitted(true); + // ✅ DON'T stop scanning - allow new QR codes to be processed + } + }) + .catch((error) => { + console.error("Error fetching stock in line info:", error); + setScannedQrResult('Error fetching data'); + setQrScanFailed(true); + setManualInputError(true); + setManualInputSubmitted(true); + // ✅ DON'T stop scanning - allow new QR codes to be processed + }) + .finally(() => { + setIsProcessingQr(false); + }); + } else { + // ✅ Fallback to old format (direct lotNo comparison) + const qrContent = latestQr.replace(/[{}]/g, ''); + + // ✅ Store the scanned result for display + setScannedQrResult(qrContent); + + if (qrContent === lot.lotNo) { + setQrScanSuccess(true); + onQrCodeSubmit(lot.lotNo); + onClose(); + resetScan(); + } else { + setQrScanFailed(true); + setManualInputError(true); + setManualInputSubmitted(true); + // ✅ DON'T stop scanning - allow new QR codes to be processed + } + } + } catch (error) { + // ✅ If JSON parsing fails, fallback to old format + console.log("QR code is not JSON format, trying direct comparison"); + const qrContent = latestQr.replace(/[{}]/g, ''); + + // ✅ Store the scanned result for display + setScannedQrResult(qrContent); + + if (qrContent === lot.lotNo) { + setQrScanSuccess(true); + onQrCodeSubmit(lot.lotNo); + onClose(); + resetScan(); + } else { + setQrScanFailed(true); + setManualInputError(true); + setManualInputSubmitted(true); + // ✅ DON'T stop scanning - allow new QR codes to be processed + } } } - }, [qrValues, lot, onQrCodeSubmit, onClose, resetScan]); + }, [qrValues, lot, onQrCodeSubmit, onClose, resetScan, isProcessingQr, qrScanSuccess, processedQrCodes, stopScan]); // ✅ Clear states when modal opens or lot changes useEffect(() => { @@ -106,6 +199,12 @@ const QrCodeModal: React.FC<{ setManualInput(''); setManualInputSubmitted(false); setManualInputError(false); + setIsProcessingQr(false); + setQrScanFailed(false); + setQrScanSuccess(false); + setScannedQrResult(''); // ✅ Clear scanned result + // ✅ Clear processed QR codes when modal opens + setProcessedQrCodes(new Set()); } }, [open]); @@ -114,151 +213,62 @@ const QrCodeModal: React.FC<{ setManualInput(''); setManualInputSubmitted(false); setManualInputError(false); + setIsProcessingQr(false); + setQrScanFailed(false); + setQrScanSuccess(false); + setScannedQrResult(''); // ✅ Clear scanned result + // ✅ Clear processed QR codes when lot changes + setProcessedQrCodes(new Set()); } }, [lot]); -{/* -const handleManualSubmit = () => { - if (manualInput.trim() === lot?.lotNo) { - // ✅ Success - no error helper text needed - onQrCodeSubmit(lot.lotNo); - onClose(); - setManualInput(''); - } else { - // ✅ Show error helper text after submit - setManualInputError(true); - setManualInputSubmitted(true); - // Don't clear input - let user see what they typed + // ✅ Auto-submit manual input when it matches (but only if QR scan hasn't failed) + useEffect(() => { + if (manualInput.trim() === lot?.lotNo && manualInput.trim() !== '' && !qrScanFailed && !qrScanSuccess) { + console.log('🔄 Auto-submitting manual input:', manualInput.trim()); + + const timer = setTimeout(() => { + setQrScanSuccess(true); + onQrCodeSubmit(lot.lotNo); + onClose(); + setManualInput(''); + setManualInputError(false); + setManualInputSubmitted(false); + }, 200); + + return () => clearTimeout(timer); } - }; + }, [manualInput, lot, onQrCodeSubmit, onClose, qrScanFailed, qrScanSuccess]); - return ( - - - - {t("QR Code Scan for Lot")}: {lot?.lotNo} - - - - - Scanner Status: {isScanning ? 'Scanning...' : 'Ready'} - - - - - - - - - - - Manual Input: - - setManualInput(e.target.value)} - sx={{ mb: 1 }} - // ✅ Only show error after submit button is clicked - error={manualInputSubmitted && manualInputError} - helperText={ - // ✅ Show helper text only after submit with error - manualInputSubmitted && manualInputError - ? `The input is not the same as the expected lot number. Expected: ${lot?.lotNo}` - : '' - } - /> - - - - {qrValues.length > 0 && ( - - - QR Scan Result: {qrValues[qrValues.length - 1]} - - {manualInputError && ( - - ❌ Mismatch! Expected: {lot?.lotNo} - - )} - - )} - - - - - - - ); -}; -*/} -useEffect(() => { - if (manualInput.trim() === lot?.lotNo && manualInput.trim() !== '') { - // Auto-submit when manual input matches the expected lot number - console.log('🔄 Auto-submitting manual input:', manualInput.trim()); - - // Add a small delay to ensure proper execution order - const timer = setTimeout(() => { - onQrCodeSubmit(lot.lotNo); - onClose(); - setManualInput(''); - setManualInputError(false); - setManualInputSubmitted(false); - }, 200); // 200ms delay - - return () => clearTimeout(timer); - } -}, [manualInput, lot, onQrCodeSubmit, onClose]); + // ✅ Add the missing handleManualSubmit function const handleManualSubmit = () => { if (manualInput.trim() === lot?.lotNo) { - // ✅ Success - no error helper text needed + setQrScanSuccess(true); onQrCodeSubmit(lot.lotNo); onClose(); setManualInput(''); } else { - // ✅ Show error helper text after submit + setQrScanFailed(true); setManualInputError(true); setManualInputSubmitted(true); - // Don't clear input - let user see what they typed } }; -useEffect(() => { + + // ✅ Add function to restart scanning after manual input error + const handleRestartScan = () => { + setQrScanFailed(false); + setManualInputError(false); + setManualInputSubmitted(false); + setProcessedQrCodes(new Set()); // Clear processed QR codes + startScan(); // Restart scanning + }; + + useEffect(() => { if (open) { startScan(); } }, [open, startScan]); + return ( { minWidth: 400, }}> - QR Code Scan for Lot: {lot?.lotNo} + {t("QR Code Scan for Lot")}: {lot?.lotNo} + {/* ✅ Show processing status */} + {isProcessingQr && ( + + + {t("Processing QR code...")} + + + )} + {/* Manual Input with Submit-Triggered Helper Text */} - Manual Input: + {t("Manual Input")}: setManualInput(e.target.value)} + onChange={(e) => { + setManualInput(e.target.value); + // ✅ Reset error states when user starts typing + if (qrScanFailed || manualInputError) { + setQrScanFailed(false); + setManualInputError(false); + setManualInputSubmitted(false); + } + }} sx={{ mb: 1 }} error={manualInputSubmitted && manualInputError} helperText={ manualInputSubmitted && manualInputError - ? `The input is not the same as the expected lot number.` + ? `${t("The input is not the same as the expected lot number.")}` : '' } /> @@ -300,19 +327,25 @@ useEffect(() => { size="small" color="primary" > - Submit Manual Input + {t("Submit")} {/* Show QR Scan Status */} {qrValues.length > 0 && ( - - - QR Scan Result: {qrValues[qrValues.length - 1]} + + + {t("QR Scan Result:")} {scannedQrResult} - {manualInputError && ( - - ❌ Mismatch! Expected! + + {qrScanSuccess && ( + + ✅ {t("Verified successfully!")} )} @@ -320,7 +353,7 @@ useEffect(() => { @@ -347,6 +380,7 @@ const LotTable: React.FC = ({ selectedLotForInput, generateInputBody, onDataRefresh, + onLotDataRefresh, }) => { const { t } = useTranslation("pickOrder"); @@ -367,12 +401,12 @@ const LotTable: React.FC = ({ // ✅ 添加状态消息生成函数 const getStatusMessage = useCallback((lot: LotPickData) => { if (!lot.stockOutLineId) { - return t("Please finish QR code scan, QC check and pick order."); + return t("Please finish QR code scanand pick order."); } switch (lot.stockOutLineStatus?.toLowerCase()) { case 'pending': - return t("Please finish QC check and pick order."); + return t("Please finish pick order."); case 'checked': return t("Please submit the pick order."); case 'partially_completed': @@ -384,7 +418,7 @@ const LotTable: React.FC = ({ case 'unavailable': return t("This order is insufficient, please pick another lot."); default: - return t("Please finish QR code scan, QC check and pick order."); + return t("Please finish QR code scan and pick order."); } }, []); @@ -417,7 +451,15 @@ const LotTable: React.FC = ({ pageSize: newPageSize, }); }, []); - + const calculateRemainingAvailableQty = useCallback((lot: LotPickData) => { + if (!selectedRowId) return lot.availableQty; + const lactualPickQty = lot.actualPickQty || 0; + const actualPickQty = pickQtyData[selectedRowId]?.[lot.lotId] || 0; + const remainingQty = lot.inQty - actualPickQty - lactualPickQty; + + // Ensure it doesn't go below 0 + return Math.max(0, remainingQty); + }, [selectedRowId, pickQtyData]); // ✅ Handle QR code submission const handleQrCodeSubmit = useCallback(async (lotNo: string) => { if (selectedLotForQr && selectedLotForQr.lotNo === lotNo) { @@ -458,13 +500,19 @@ const LotTable: React.FC = ({ {t("Lot#")} {t("Lot Expiry Date")} {t("Lot Location")} - {t("Available Lot")} - {t("Lot Required Pick Qty")} {t("Stock Unit")} - {t("QR Code Scan")} + {t("Lot Required Pick Qty")} + {t("Original Available Qty")} {t("Lot Actual Pick Qty")} - {t("Reject")} - {t("Submit")} + {/*{t("Available Lot")}*/} + {t("Remaining Available Qty")} + + {/*{t("QR Code Scan")}*/} + {/*} + {t("Reject")} + */} + + {t("Action")} @@ -503,11 +551,102 @@ const LotTable: React.FC = ({ {lot.expiryDate} {lot.location} - {lot.availableQty.toLocaleString()} - {lot.requiredQty.toLocaleString()} {lot.stockUnit} + {lot.requiredQty.toLocaleString()} + {lot.inQty.toLocaleString()??'0'} + + {/* Show QR Scan Button if not scanned, otherwise show TextField */} + {!lot.stockOutLineId ? ( + + ) : ( + { + if (selectedRowId) { + const inputValue = e.target.value; + // ✅ Fixed: Handle empty string and prevent leading zeros + if (inputValue === '') { + // Allow empty input (user can backspace to clear) + onPickQtyChange(selectedRowId, lot.lotId, 0); + } else { + // Parse the number and prevent leading zeros + const numValue = parseInt(inputValue, 10); + if (!isNaN(numValue)) { + onPickQtyChange(selectedRowId, lot.lotId, numValue); + } + } + } + }} + onBlur={(e) => { + // ✅ Fixed: When input loses focus, ensure we have a valid number + if (selectedRowId) { + const currentValue = pickQtyData[selectedRowId]?.[lot.lotId]; + if (currentValue === undefined || currentValue === null) { + // Set to 0 if no value + onPickQtyChange(selectedRowId, lot.lotId, 0); + } + } + }} + inputProps={{ + min: 0, + max: lot.availableQty, + step: 1 // Allow only whole numbers + }} + // ✅ Allow input for available AND insufficient_stock lots + disabled={lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable'} + sx={{ + width: '80px', + '& .MuiInputBase-root': { + height: '40px', // ✅ Match table cell height + }, + '& .MuiInputBase-input': { + height: '40px', + padding: '8px 12px', // ✅ Adjust padding to center text vertically + } + }} + placeholder="0" // Show placeholder instead of default value + /> + )} + + {/*{lot.availableQty.toLocaleString()}*/} + {calculateRemainingAvailableQty(lot).toLocaleString()} + {/* {lot.stockUnit} */} {/* QR Code Scan Button */} + {/* - + - + */} {/* QC Check Button */} {/* @@ -579,48 +718,9 @@ const LotTable: React.FC = ({ {/* Lot Actual Pick Qty */} - - { - if (selectedRowId) { - const inputValue = e.target.value; - // ✅ Fixed: Handle empty string and prevent leading zeros - if (inputValue === '') { - // Allow empty input (user can backspace to clear) - onPickQtyChange(selectedRowId, lot.lotId, 0); - } else { - // Parse the number and prevent leading zeros - const numValue = parseInt(inputValue, 10); - if (!isNaN(numValue)) { - onPickQtyChange(selectedRowId, lot.lotId, numValue); - } - } - } - }} - onBlur={(e) => { - // ✅ Fixed: When input loses focus, ensure we have a valid number - if (selectedRowId) { - const currentValue = pickQtyData[selectedRowId]?.[lot.lotId]; - if (currentValue === undefined || currentValue === null) { - // Set to 0 if no value - onPickQtyChange(selectedRowId, lot.lotId, 0); - } - } - }} - inputProps={{ - min: 0, - max: lot.availableQty, - step: 1 // Allow only whole numbers - }} - // ✅ Allow input for available AND insufficient_stock lots - disabled={lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable'} - sx={{ width: '80px' }} - placeholder="0" // Show placeholder instead of default value - /> - + + + + {/*} - {/* Submit Button */} + + */} + + )) @@ -695,7 +803,7 @@ const LotTable: React.FC = ({ {paginatedLotTableData.map((lot, index) => ( - Lot {lot.lotNo}: {getStatusMessage(lot)} + {t("Lot")} {lot.lotNo}: {getStatusMessage(lot)} ))} diff --git a/src/components/PickOrderSearch/PickExecution.tsx b/src/components/PickOrderSearch/PickExecution.tsx index 0e15fb5..41503da 100644 --- a/src/components/PickOrderSearch/PickExecution.tsx +++ b/src/components/PickOrderSearch/PickExecution.tsx @@ -84,6 +84,7 @@ interface LotPickData { expiryDate: string; location: string; stockUnit: string; + inQty: number; availableQty: number; requiredQty: number; actualPickQty: number; @@ -562,6 +563,7 @@ const PickExecution: React.FC = ({ filterArgs }) => { expiryDate: lot.expiryDate ? new Date(lot.expiryDate).toLocaleDateString() : 'N/A', location: lot.location, stockUnit: lot.stockUnit, + inQty: lot.inQty, availableQty: lot.availableQty, requiredQty: lot.requiredQty, actualPickQty: lot.actualPickQty || 0, @@ -651,7 +653,15 @@ const PickExecution: React.FC = ({ filterArgs }) => { console.error("Error updating inventory status:", error); } }, []); - + const handleLotDataRefresh = useCallback(async () => { + if (selectedRowId) { + try { + await handleRowSelect(selectedRowId, true); // Preserve lot selection + } catch (error) { + console.error("Error refreshing lot data:", error); + } + } + }, [selectedRowId, handleRowSelect]); // ✅ Add this function after handleRowSelect is defined const handleDataRefresh = useCallback(async () => { if (selectedRowId) { @@ -1027,7 +1037,7 @@ const PickExecution: React.FC = ({ filterArgs }) => { ) : ( - 正在載入數據... + {t("Loading data...")} )} @@ -1051,10 +1061,12 @@ const PickExecution: React.FC = ({ filterArgs }) => { selectedLotId={selectedLotId} onLotSelection={handleLotSelection} onPickQtyChange={handlePickQtyChange} + onSubmitPickQty={handleSubmitPickQty} onCreateStockOutLine={handleCreateStockOutLine} onQcCheck={handleQcCheck} onDataRefresh={handleFetchAllPickOrderDetails} + onLotDataRefresh={handleLotDataRefresh} onLotSelectForInput={handleLotSelectForInput} showInputBody={showInputBody} setShowInputBody={setShowInputBody} diff --git a/src/components/PickOrderSearch/newcreatitem.tsx b/src/components/PickOrderSearch/newcreatitem.tsx index 4e6b58c..682bb90 100644 --- a/src/components/PickOrderSearch/newcreatitem.tsx +++ b/src/components/PickOrderSearch/newcreatitem.tsx @@ -1916,7 +1916,7 @@ const CustomSearchResultsTable = () => { textField: { size: "small", label: t("Target Date"), - sx: { width: 180 } + sx: { width: 200 } }, }} /> diff --git a/src/i18n/zh/pickOrder.json b/src/i18n/zh/pickOrder.json index 9e9c70e..93be626 100644 --- a/src/i18n/zh/pickOrder.json +++ b/src/i18n/zh/pickOrder.json @@ -148,11 +148,11 @@ "Material": "食材", "Job Order": "工單", "End Product": "成品", - "Lot Expiry Date": "批號到期日", - "Lot Location": "批號位置", - "Available Lot": "批號可用提料數", - "Lot Required Pick Qty": "批號所需提料數", - "Lot Actual Pick Qty": "批號實際提料數", + "Lot Expiry Date": "到期日", + "Lot Location": "位置", + "Available Lot": "可用提料數", + "Lot Required Pick Qty": "所需數", + "Lot Actual Pick Qty": "此單將提數", "Lot#": "批號", "Submit": "提交", "Created Items": "已建立貨品", @@ -183,11 +183,37 @@ "Item lot to be Pick:": "批次貨品提料:", "Report and Pick another lot": "上報並需重新選擇批號", "Accept Stock Out": "接受出庫", - "Pick Another Lot": "重新選擇批號", + "Pick Another Lot": "欠數,並重新選擇批號", "Lot No": "批號", "Expiry Date": "到期日", "Location": "位置", "All Pick Order Lots": "所有提料單批次", "Completed": "已完成", - "Finished Good Order": "成品訂單" + "Finished Good Order": "成品訂單", + "Assign and Release": "分派並放單", + "Original Available Qty": "原可用數", + "Remaining Available Qty": "剩餘", + "Please submit pick order.": "請提交提料單。", + "Please finish QR code scan and pick order.": "請完成 QR 碼掃描和提料。", + "Please finish QR code scanand pick order.": "請完成 QR 碼掃描和提料。", + "First created group": "首次建立分組", + "Latest created group": "最新建立分組", + "Manual Input": "手動輸入", + "QR Code Scan for Lot": " QR 碼掃描批次", + "Processing QR code...": "處理 QR 碼...", + "The input is not the same as the expected lot number.": "輸入的批次號碼與預期的不符。", + "Verified successfully!": "驗證成功!", + "Cancel": "取消", + "Scan": "掃描", + "Scanned": "已掃描", + "Loading data...": "正在載入數據...", + "No available stock for this item": "沒有可用庫存", + "No lot details available for this item": "沒有批次詳情", + "Current stock is insufficient or unavailable": "現時可用庫存不足或不可用", + "Please check inventory status": "請檢查庫存狀態", + "Rows per page": "每頁行數", + "QR Scan Result:": "QR 掃描結果:", + "Action": "操作", + "Please finish pick order.": "請完成提料。", + "Lot": "批號" } \ No newline at end of file