From 00233d5353ebf6dee51f12b2e29c9b1480c6bf4b Mon Sep 17 00:00:00 2001 From: "CANCERYS\\kw093" Date: Sat, 4 Apr 2026 23:19:01 +0800 Subject: [PATCH] update --- .../GoodPickExecutiondetail.tsx | 53 ++++- .../LotConfirmationModal.tsx | 8 + .../Jodetail/LotConfirmationModal.tsx | 8 + .../Jodetail/newJobPickExecution.tsx | 182 +++++++++--------- src/i18n/zh/pickOrder.json | 8 +- 5 files changed, 164 insertions(+), 95 deletions(-) diff --git a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx index 264e956..ca44093 100644 --- a/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx +++ b/src/components/FinishedGoodSearch/GoodPickExecutiondetail.tsx @@ -522,6 +522,13 @@ function isLotAvailabilityExpired(lot: any): boolean { return String(lot?.lotAvailability || "").toLowerCase() === "expired"; } +/** inventory_lot_line.status = unavailable(API 可能用 lotAvailability 或 lotStatus) */ +function isInventoryLotLineUnavailable(lot: any): boolean { + if (!lot) return false; + if (lot.lotAvailability === "status_unavailable") return true; + return String(lot.lotStatus || "").toLowerCase() === "unavailable"; +} + /** Issue「改數」未寫入 SOL,刷新/換頁後需靠 session 還原,否則 Qty will submit 會回到 req */ const FG_ISSUE_PICKED_KEY = (doPickOrderId: number) => `fpsms-fg-issuePickedQty:${doPickOrderId}`; @@ -611,6 +618,7 @@ const [pickOrderSwitching, setPickOrderSwitching] = useState(false); // QR scanner states (always-on, no modal) const [selectedLotForQr, setSelectedLotForQr] = useState(null); const [lotConfirmationOpen, setLotConfirmationOpen] = useState(false); + const [lotConfirmationError, setLotConfirmationError] = useState(null); const [expectedLotData, setExpectedLotData] = useState(null); const [scannedLotData, setScannedLotData] = useState(null); const [isConfirmingLot, setIsConfirmingLot] = useState(false); @@ -1250,6 +1258,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO const clearLotConfirmationState = useCallback((clearProcessedRefs: boolean = false) => { setLotConfirmationOpen(false); + setLotConfirmationError(null); setExpectedLotData(null); setScannedLotData(null); setSelectedLotForQr(null); @@ -1299,18 +1308,34 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO const handleLotConfirmation = useCallback(async () => { if (!expectedLotData || !scannedLotData || !selectedLotForQr) return; setIsConfirmingLot(true); + setLotConfirmationError(null); try { const newLotNo = scannedLotData?.lotNo; const newStockInLineId = scannedLotData?.stockInLineId; - await confirmLotSubstitution({ + const substitutionResult = await confirmLotSubstitution({ pickOrderLineId: selectedLotForQr.pickOrderLineId, stockOutLineId: selectedLotForQr.stockOutLineId, originalSuggestedPickLotId: selectedLotForQr.suggestedPickLotId, newInventoryLotNo: "", newStockInLineId: newStockInLineId }); + + if (!substitutionResult || substitutionResult.code !== "SUCCESS") { + const errMsg = + substitutionResult?.code === "LOT_UNAVAILABLE" + ? t( + "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated." + ) + : substitutionResult?.message || + t("Lot switch failed; pick line was not marked as checked."); + setLotConfirmationError(errMsg); + setQrScanError(true); + setQrScanSuccess(false); + setQrScanErrorMsg(errMsg); + return; + } setQrScanError(false); setQrScanSuccess(false); @@ -1342,10 +1367,14 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO setIsRefreshingData(false); } catch (error) { console.error("Error confirming lot substitution:", error); + const errMsg = t("Lot confirmation failed. Please try again."); + setLotConfirmationError(errMsg); + setQrScanError(true); + setQrScanErrorMsg(errMsg); } finally { setIsConfirmingLot(false); } - }, [expectedLotData, scannedLotData, selectedLotForQr, fetchAllCombinedLotData, resetScan, clearLotConfirmationState]); + }, [expectedLotData, scannedLotData, selectedLotForQr, fetchAllCombinedLotData, resetScan, clearLotConfirmationState, t]); const handleLotConfirmationByRescan = useCallback(async (rawQr: string): Promise => { if (!lotConfirmationOpen || !selectedLotForQr || !expectedLotData || !scannedLotData) { @@ -1785,7 +1814,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO const isRejected = scannedLot.stockOutLineStatus?.toLowerCase() === 'rejected' || scannedLot.lotAvailability === 'rejected' || - scannedLot.lotAvailability === 'status_unavailable'; + isInventoryLotLineUnavailable(scannedLot); if (isRejected) { console.warn(`⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is rejected or unavailable`); @@ -1849,7 +1878,7 @@ const fetchAllCombinedLotData = useCallback(async (userId?: number, pickOrderIdO const rejectedLot = allLotsForItem.find((lot: any) => lot.stockOutLineStatus?.toLowerCase() === 'rejected' || lot.lotAvailability === 'rejected' || - lot.lotAvailability === 'status_unavailable' + isInventoryLotLineUnavailable(lot) ); const expectedLot = rejectedLot || @@ -3700,10 +3729,13 @@ paginatedData.map((lot, index) => { variant="outlined" size="small" onClick={() => handlelotnull(lot)} + /* disabled={ status === 'completed' || (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) } + */ + disabled={true} sx={{ fontSize: '0.7rem', py: 0.5, @@ -3729,14 +3761,18 @@ paginatedData.map((lot, index) => { handlePickQtyChange(lotKey, submitQty); handleSubmitPickQtyWithQty(lot, submitQty, 'singleSubmit'); }} + /* disabled={ lot.lotAvailability === 'expired' || - lot.lotAvailability === 'status_unavailable' || + isInventoryLotLineUnavailable(lot) || lot.lotAvailability === 'rejected' || lot.stockOutLineStatus === 'completed' || lot.stockOutLineStatus === 'pending' || (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) } +*/ + disabled={true} + sx={{ fontSize: '0.75rem', py: 0.5, minHeight: '28px', minWidth: '70px' }} > {t("Submit")} @@ -3746,11 +3782,14 @@ paginatedData.map((lot, index) => { variant="outlined" size="small" onClick={() => handlePickExecutionForm(lot)} + /* disabled={ lot.lotAvailability === 'expired' || lot.stockOutLineStatus === 'completed' || (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) } + */ + disabled={true} sx={{ fontSize: '0.7rem', py: 0.5, @@ -3767,6 +3806,7 @@ paginatedData.map((lot, index) => { variant="outlined" size="small" onClick={() => handleSkip(lot)} + disabled={ lot.stockOutLineStatus === 'completed' || lot.stockOutLineStatus === 'checked' || @@ -3777,6 +3817,8 @@ paginatedData.map((lot, index) => { (Number(lot.stockOutLineId) > 0 && issuePickedQtyBySolId[Number(lot.stockOutLineId)] !== undefined) || (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) } + + sx={{ fontSize: '0.7rem', py: 0.5, minHeight: '28px', minWidth: '60px' }} > {t("Just Completed")} @@ -3833,6 +3875,7 @@ paginatedData.map((lot, index) => { expectedLot={expectedLotData} scannedLot={scannedLotData} isLoading={isConfirmingLot} + errorMessage={lotConfirmationError} /> )} diff --git a/src/components/FinishedGoodSearch/LotConfirmationModal.tsx b/src/components/FinishedGoodSearch/LotConfirmationModal.tsx index 8f18c79..fee9bc3 100644 --- a/src/components/FinishedGoodSearch/LotConfirmationModal.tsx +++ b/src/components/FinishedGoodSearch/LotConfirmationModal.tsx @@ -29,6 +29,8 @@ interface LotConfirmationModalProps { itemName: string; }; isLoading?: boolean; + /** Shown inside the dialog when confirm/switch API fails (e.g. LOT_UNAVAILABLE). */ + errorMessage?: string | null; } const LotConfirmationModal: React.FC = ({ @@ -38,6 +40,7 @@ const LotConfirmationModal: React.FC = ({ expectedLot, scannedLot, isLoading = false, + errorMessage = null, }) => { const { t } = useTranslation("pickOrder"); @@ -60,6 +63,11 @@ const LotConfirmationModal: React.FC = ({ + {errorMessage ? ( + + {t(errorMessage)} + + ) : null} {t("The scanned item matches the expected item, but the lot number is different. Scan again to confirm: scan the expected lot QR to keep the suggested lot, or scan the other lot QR again to switch.")} diff --git a/src/components/Jodetail/LotConfirmationModal.tsx b/src/components/Jodetail/LotConfirmationModal.tsx index 7fd61a1..887e963 100644 --- a/src/components/Jodetail/LotConfirmationModal.tsx +++ b/src/components/Jodetail/LotConfirmationModal.tsx @@ -29,6 +29,8 @@ interface LotConfirmationModalProps { itemName: string; }; isLoading?: boolean; + /** Shown inside the dialog when confirm/switch API fails (e.g. LOT_UNAVAILABLE). */ + errorMessage?: string | null; } const LotConfirmationModal: React.FC = ({ @@ -38,6 +40,7 @@ const LotConfirmationModal: React.FC = ({ expectedLot, scannedLot, isLoading = false, + errorMessage = null, }) => { const { t } = useTranslation("pickOrder"); @@ -60,6 +63,11 @@ const LotConfirmationModal: React.FC = ({ + {errorMessage ? ( + + {t(errorMessage)} + + ) : null} {t("The scanned item matches the expected item, but the lot number is different. Do you want to proceed with this different lot?")} diff --git a/src/components/Jodetail/newJobPickExecution.tsx b/src/components/Jodetail/newJobPickExecution.tsx index 470ddbe..354dfd0 100644 --- a/src/components/Jodetail/newJobPickExecution.tsx +++ b/src/components/Jodetail/newJobPickExecution.tsx @@ -76,6 +76,13 @@ function isLotAvailabilityExpired(lot: any): boolean { return String(lot?.lotAvailability || "").toLowerCase() === "expired"; } +/** inventory_lot_line.status = unavailable(API 可能用 lotAvailability 或 lotStatus) */ +function isInventoryLotLineUnavailable(lot: any): boolean { + if (!lot) return false; + if (lot.lotAvailability === "status_unavailable") return true; + return String(lot.lotStatus || "").toLowerCase() === "unavailable"; +} + const JO_ISSUE_PICKED_KEY = (pickOrderId: number) => `fpsms-jo-issuePickedQty:${pickOrderId}`; @@ -471,6 +478,7 @@ const QrCodeModal: React.FC<{ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { const { t } = useTranslation("jo"); + const { t: tPick } = useTranslation("pickOrder"); const router = useRouter(); const { data: session } = useSession() as { data: SessionWithTokens | null }; @@ -486,6 +494,7 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { const { values: qrValues, isScanning, startScan, stopScan, resetScan } = useQrCodeScannerContext(); const [lotConfirmationOpen, setLotConfirmationOpen] = useState(false); + const [lotConfirmationError, setLotConfirmationError] = useState(null); const [expectedLotData, setExpectedLotData] = useState(null); const [scannedLotData, setScannedLotData] = useState(null); const [isConfirmingLot, setIsConfirmingLot] = useState(false); @@ -1114,6 +1123,7 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { console.log("✅ [LOT CONFIRM] Selected lot for QR:", selectedLotForQr); setIsConfirmingLot(true); + setLotConfirmationError(null); try { let newLotLineId = scannedLotData?.inventoryLotLineId; if (!newLotLineId && scannedLotData?.stockInLineId) { @@ -1171,9 +1181,16 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { console.log("✅ [LOT CONFIRM] updateStockOutLineStatusByQRCodeAndLotNo result:", res); const ok = res?.code === "checked" || res?.code === "SUCCESS"; if (!ok) { + const errMsg = + res?.code === "LOT_UNAVAILABLE" + ? tPick( + "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated." + ) + : res?.message || tPick("Lot switch failed; pick line was not marked as checked."); + setLotConfirmationError(errMsg); setQrScanError(true); setQrScanSuccess(false); - setQrScanErrorMsg(res?.message || "换批失败:无法更新 stock out line"); + setQrScanErrorMsg(errMsg); return; } } else { @@ -1194,12 +1211,17 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { // Keep modal open so user can cancel/rescan. if (!substitutionResult || substitutionResult.code !== "SUCCESS") { console.error("❌ [LOT CONFIRM] Lot substitution failed. Will NOT update stockOutLine status."); + const errMsg = + substitutionResult?.code === "LOT_UNAVAILABLE" + ? tPick( + "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated." + ) + : substitutionResult?.message || + `换批失败:stockInLineId ${scannedLotData?.stockInLineId ?? ""} 不存在或无法匹配`; + setLotConfirmationError(errMsg); setQrScanError(true); setQrScanSuccess(false); - setQrScanErrorMsg( - substitutionResult?.message || - `换批失败:stockInLineId ${scannedLotData?.stockInLineId ?? ""} 不存在或无法匹配` - ); + setQrScanErrorMsg(errMsg); return; } } @@ -1262,15 +1284,17 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { } catch (error) { console.error("Error confirming lot substitution:", error); + const errMsg = tPick("Lot confirmation failed. Please try again."); + setLotConfirmationError(errMsg); setQrScanError(true); setQrScanSuccess(false); - setQrScanErrorMsg('换批发生异常,请重试或联系管理员'); + setQrScanErrorMsg(errMsg); // Clear refresh flag on error setIsRefreshingData(false); } finally { setIsConfirmingLot(false); } - }, [expectedLotData, scannedLotData, selectedLotForQr, fetchJobOrderData,currentUserId, updateHandledBy ]); + }, [expectedLotData, scannedLotData, selectedLotForQr, fetchJobOrderData, currentUserId, updateHandledBy, tPick]); const processOutsideQrCode = useCallback(async (latestQr: string) => { // ✅ Only JSON QR supported for outside scanner (avoid false positive with lotNo) @@ -1315,7 +1339,7 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { const isRejected = scannedLot.stockOutLineStatus?.toLowerCase() === 'rejected' || scannedLot.lotAvailability === 'rejected' || - scannedLot.lotAvailability === 'status_unavailable'; + isInventoryLotLineUnavailable(scannedLot); if (isRejected) { console.warn(`⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is rejected or unavailable`); @@ -1335,6 +1359,28 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { }); return; } + + const isExpired = + String(scannedLot.lotAvailability || "").toLowerCase() === "expired"; + if (isExpired) { + console.warn( + `⚠️ [QR PROCESS] Scanned lot (stockInLineId: ${scannedStockInLineId}, lotNo: ${scannedLot.lotNo}) is expired` + ); + startTransition(() => { + setQrScanError(true); + setQrScanSuccess(false); + setQrScanErrorMsg( + `此批次(${scannedLot.lotNo || scannedStockInLineId})已过期,无法使用。请扫描其他批次。` + ); + }); + setProcessedQrCombinations((prev) => { + const newMap = new Map(prev); + if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set()); + newMap.get(scannedItemId)!.add(scannedStockInLineId); + return newMap; + }); + return; + } } // ✅ If no active suggested lots, but scanned lot is not rejected, allow lot switching @@ -1489,10 +1535,16 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { return; } - // ✅ mismatch: validate scanned stockInLineId exists before opening confirmation modal - console.log(`⚠️ [QR PROCESS] No exact match found. Validating scanned stockInLineId ${scannedStockInLineId} for itemId ${scannedItemId}`); - console.log(`⚠️ [QR PROCESS] Active suggested lots for itemId ${scannedItemId}:`, activeSuggestedLots.map(l => ({ lotNo: l.lotNo, stockInLineId: l.stockInLineId }))); - + // ✅ mismatch: align with GoodPickExecutiondetail — open LotConfirmationModal first; + // handleLotMismatch loads scanned lotNo via fetchStockInLineInfoCached in the background when lotNo is null. + console.log( + `⚠️ [QR PROCESS] No exact match found (itemId ${scannedItemId}, scanned stockInLineId ${scannedStockInLineId})` + ); + console.log( + `⚠️ [QR PROCESS] Active suggested lots for itemId ${scannedItemId}:`, + activeSuggestedLots.map((l) => ({ lotNo: l.lotNo, stockInLineId: l.stockInLineId })) + ); + if (activeSuggestedLots.length === 0) { console.error(`❌ [QR PROCESS] No active suggested lots found for itemId ${scannedItemId}`); startTransition(() => { @@ -1504,82 +1556,28 @@ const JobPickExecution: React.FC = ({ filterArgs, onBackToList }) => { } const expectedLot = activeSuggestedLots[0]; - console.log(`⚠️ [QR PROCESS] Expected lot: ${expectedLot.lotNo} (stockInLineId: ${expectedLot.stockInLineId}), Scanned stockInLineId: ${scannedStockInLineId}`); - - // ✅ Validate scanned stockInLineId exists before opening modal - // This ensures the backend can find the lot when user confirms - try { - console.log(`🔍 [QR PROCESS] Validating scanned stockInLineId ${scannedStockInLineId} exists...`); - const stockInLineInfo = await fetchStockInLineInfoCached(scannedStockInLineId); - console.log(`✅ [QR PROCESS] Scanned stockInLineId ${scannedStockInLineId} exists, lotNo: ${stockInLineInfo.lotNo}`); - - // ✅ 检查扫描的批次是否已被拒绝 - const scannedLot = combinedLotData.find( - (lot: any) => lot.stockInLineId === scannedStockInLineId && lot.itemId === scannedItemId - ); - - if (scannedLot) { - const isRejected = - scannedLot.stockOutLineStatus?.toLowerCase() === 'rejected' || - scannedLot.lotAvailability === 'rejected' || - scannedLot.lotAvailability === 'status_unavailable'; - - if (isRejected) { - console.warn(`⚠️ [QR PROCESS] Scanned lot ${stockInLineInfo.lotNo} (stockInLineId: ${scannedStockInLineId}) is rejected or unavailable`); - startTransition(() => { - setQrScanError(true); - setQrScanSuccess(false); - setQrScanErrorMsg( - `此批次(${stockInLineInfo.lotNo || scannedStockInLineId})已被拒绝,无法使用。请扫描其他批次。` - ); - }); - // Mark as processed to prevent re-processing - setProcessedQrCombinations(prev => { - const newMap = new Map(prev); - if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set()); - newMap.get(scannedItemId)!.add(scannedStockInLineId); - return newMap; - }); - return; - } + console.log( + `⚠️ [QR PROCESS] Expected lot: ${expectedLot.lotNo} (stockInLineId: ${expectedLot.stockInLineId}), Scanned stockInLineId: ${scannedStockInLineId}` + ); + console.log( + `⚠️ [QR PROCESS] Opening confirmation modal - user must confirm before any lot is marked as scanned` + ); + setSelectedLotForQr(expectedLot); + handleLotMismatch( + { + lotNo: expectedLot.lotNo, + itemCode: expectedLot.itemCode, + itemName: expectedLot.itemName, + }, + { + lotNo: null, + itemCode: expectedLot.itemCode, + itemName: expectedLot.itemName, + inventoryLotLineId: null, + stockInLineId: scannedStockInLineId, } - - // ✅ stockInLineId exists and is not rejected, open confirmation modal - console.log(`⚠️ [QR PROCESS] Opening confirmation modal - user must confirm before any lot is marked as scanned`); - setSelectedLotForQr(expectedLot); - handleLotMismatch( - { - lotNo: expectedLot.lotNo, - itemCode: expectedLot.itemCode, - itemName: expectedLot.itemName - }, - { - lotNo: stockInLineInfo.lotNo || null, // Use fetched lotNo for display - itemCode: expectedLot.itemCode, - itemName: expectedLot.itemName, - inventoryLotLineId: null, - stockInLineId: scannedStockInLineId - } - ); - } catch (error) { - // ✅ stockInLineId does NOT exist, show error immediately (don't open modal) - console.error(`❌ [QR PROCESS] Scanned stockInLineId ${scannedStockInLineId} does NOT exist:`, error); - startTransition(() => { - setQrScanError(true); - setQrScanSuccess(false); - setQrScanErrorMsg( - `扫描的 stockInLineId ${scannedStockInLineId} 不存在。请检查 QR 码是否正确,或联系管理员。` - ); - }); - // Mark as processed to prevent re-processing - setProcessedQrCombinations(prev => { - const newMap = new Map(prev); - if (!newMap.has(scannedItemId)) newMap.set(scannedItemId, new Set()); - newMap.get(scannedItemId)!.add(scannedStockInLineId); - return newMap; - }); - } - }, [filterArgs?.pickOrderId, fetchJobOrderData, handleLotMismatch, lotDataIndexes, processedQrCombinations, combinedLotData, fetchStockInLineInfoCached,currentUserId, updateHandledBy ]); + ); + }, [filterArgs?.pickOrderId, fetchJobOrderData, handleLotMismatch, lotDataIndexes, processedQrCombinations, combinedLotData, currentUserId, updateHandledBy]); // Store in refs for immediate access in qrValues effect processOutsideQrCodeRef.current = processOutsideQrCode; @@ -2823,14 +2821,17 @@ const sortedData = [...sourceData].sort((a, b) => { } } }} + /* disabled={ (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) || (lot.lotAvailability === 'expired' || - lot.lotAvailability === 'status_unavailable' || + isInventoryLotLineUnavailable(lot) || lot.lotAvailability === 'rejected') || lot.stockOutLineStatus === 'completed' || lot.stockOutLineStatus === 'pending' } + */ + disabled={true} sx={{ fontSize: '0.75rem', py: 0.5, @@ -2845,6 +2846,7 @@ const sortedData = [...sourceData].sort((a, b) => { variant="outlined" size="small" onClick={() => handlePickExecutionForm(lot)} + /* disabled={ lot.lotAvailability === "expired" || lot.stockOutLineStatus === "completed" || @@ -2853,6 +2855,8 @@ const sortedData = [...sourceData].sort((a, b) => { (Number(lot.stockOutLineId) > 0 && actionBusyBySolId[Number(lot.stockOutLineId)] === true) } + */ + disabled={true} sx={{ fontSize: '0.7rem', py: 0.5, @@ -2954,6 +2958,7 @@ const sortedData = [...sourceData].sort((a, b) => { onClose={() => { console.log(`⏱️ [LOT CONFIRM MODAL] Closing modal, clearing state`); setLotConfirmationOpen(false); + setLotConfirmationError(null); setExpectedLotData(null); setScannedLotData(null); setSelectedLotForQr(null); @@ -2986,6 +2991,7 @@ const sortedData = [...sourceData].sort((a, b) => { expectedLot={expectedLotData} scannedLot={scannedLotData} isLoading={isConfirmingLot} + errorMessage={lotConfirmationError} /> )} diff --git a/src/i18n/zh/pickOrder.json b/src/i18n/zh/pickOrder.json index 1bd58f1..e55fc9d 100644 --- a/src/i18n/zh/pickOrder.json +++ b/src/i18n/zh/pickOrder.json @@ -459,5 +459,9 @@ "Ticket Release Table": "查看提貨情況", "Please take one pick order before printing the draft.": "請先從「撳單/提料單詳情」頁面下方選取提料單,再列印草稿。", "No released pick order records found.": "目前沒有可用的提料單。", - "EDT - Lane Code (Unassigned/Total)": "預計出發時間 - 貨車班次(未撳數/總單數)" - } \ No newline at end of file + "EDT - Lane Code (Unassigned/Total)": "預計出發時間 - 貨車班次(未撳數/總單數)", + "The scanned lot inventory line is unavailable. Cannot switch or bind; pick line was not updated.": "掃描的庫存批行為「不可用」,無法換批或綁定;揀貨行未更新。", + "Lot switch failed; pick line was not marked as checked.": "換批失敗;揀貨行未標為已核對。", + "Lot confirmation failed. Please try again.": "確認批號失敗,請重試。", + "Lot status is unavailable. Cannot switch or bind; pick line was not updated.": "批號狀態為「不可用」,無法換批或綁定;揀貨行未更新。" + } \ No newline at end of file