@@ -52,6 +52,19 @@ export interface PostInventoryLotLineResponse<T = null> { | |||
entity?: T | T[]; | |||
consoCode?: string; | |||
} | |||
export const updateInventoryStatus = async (data: { | |||
itemId: number; | |||
lotId: number; | |||
status: string; | |||
qty: number; | |||
}) => { | |||
return serverFetchJson(`${BASE_API_URL}/inventory/update-status`, { | |||
method: 'PUT', | |||
body: JSON.stringify(data) | |||
}); | |||
}; | |||
export const fetchLotDetail = cache(async (stockInLineId: number) => { | |||
return serverFetchJson<LotLineInfo>( | |||
`${BASE_API_URL}/inventoryLotLine/lot-detail/${stockInLineId}`, | |||
@@ -61,18 +74,16 @@ export const fetchLotDetail = cache(async (stockInLineId: number) => { | |||
}, | |||
); | |||
}); | |||
export const updateInventoryLotLineStatus = async (data: UpdateInventoryLotLineStatusRequest) => { | |||
console.log("Updating inventory lot line status:", data); | |||
const result = await serverFetchJson<PostInventoryLotLineResponse>( | |||
`${BASE_API_URL}/inventoryLotLine/updateStatus`, | |||
{ | |||
method: "POST", | |||
body: JSON.stringify(data), | |||
headers: { "Content-Type": "application/json" }, | |||
}, | |||
); | |||
revalidateTag("inventory"); | |||
return result; | |||
export const updateInventoryLotLineStatus = async (data: { | |||
inventoryLotLineId: number; | |||
status: string; | |||
qty: number; | |||
operation?: string; | |||
}) => { | |||
return serverFetchJson(`${BASE_API_URL}/inventory/lot-line/update-status`, { | |||
method: 'PUT', | |||
body: JSON.stringify(data) | |||
}); | |||
}; | |||
export const fetchInventories = cache(async (data: SearchInventory) => { | |||
@@ -90,3 +101,20 @@ export const fetchInventoryLotLines = cache(async (data: SearchInventoryLotLine) | |||
next: { tags: ["inventoryLotLines"] }, | |||
}); | |||
}); | |||
export const updateInventoryLotLineQuantities = async (data: { | |||
inventoryLotLineId: number; | |||
qty: number; | |||
operation: string; | |||
status: string; | |||
}) => { | |||
const result = await serverFetchJson<any>( | |||
`${BASE_API_URL}/inventoryLotLine/updateQuantities`, | |||
{ | |||
method: "POST", | |||
body: JSON.stringify(data), | |||
headers: { "Content-Type": "application/json" }, | |||
}, | |||
); | |||
revalidateTag("pickorder"); | |||
return result; | |||
}; |
@@ -115,7 +115,8 @@ const QrCodeModal: React.FC<{ | |||
} | |||
}, [lot]); | |||
const handleManualSubmit = () => { | |||
{/* | |||
const handleManualSubmit = () => { | |||
if (manualInput.trim() === lot?.lotNo) { | |||
// ✅ Success - no error helper text needed | |||
onQrCodeSubmit(lot.lotNo); | |||
@@ -144,8 +145,7 @@ const QrCodeModal: React.FC<{ | |||
<Typography variant="h6" gutterBottom> | |||
{t("QR Code Scan for Lot")}: {lot?.lotNo} | |||
</Typography> | |||
{/* QR Scanner Status */} | |||
<Box sx={{ mb: 2, p: 2, backgroundColor: '#f5f5f5', borderRadius: 1 }}> | |||
<Typography variant="body2" gutterBottom> | |||
<strong>Scanner Status:</strong> {isScanning ? 'Scanning...' : 'Ready'} | |||
@@ -168,7 +168,7 @@ const QrCodeModal: React.FC<{ | |||
</Stack> | |||
</Box> | |||
{/* Manual Input with Submit-Triggered Helper Text */} | |||
<Box sx={{ mb: 2 }}> | |||
<Typography variant="body2" gutterBottom> | |||
<strong>Manual Input:</strong> | |||
@@ -199,7 +199,6 @@ const QrCodeModal: React.FC<{ | |||
</Button> | |||
</Box> | |||
{/* ✅ Show QR Scan Status */} | |||
{qrValues.length > 0 && ( | |||
<Box sx={{ mb: 2, p: 2, backgroundColor: manualInputError ? '#ffebee' : '#e8f5e8', borderRadius: 1 }}> | |||
<Typography variant="body2" color={manualInputError ? 'error' : 'success'}> | |||
@@ -222,6 +221,94 @@ const QrCodeModal: React.FC<{ | |||
</Modal> | |||
); | |||
}; | |||
*/} | |||
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 | |||
} | |||
}; | |||
useEffect(() => { | |||
if (open) { | |||
startScan(); | |||
} | |||
}, [open, startScan]); | |||
return ( | |||
<Modal open={open} onClose={onClose}> | |||
<Box sx={{ | |||
position: 'absolute', | |||
top: '50%', | |||
left: '50%', | |||
transform: 'translate(-50%, -50%)', | |||
bgcolor: 'background.paper', | |||
p: 3, | |||
borderRadius: 2, | |||
minWidth: 400, | |||
}}> | |||
<Typography variant="h6" gutterBottom> | |||
QR Code Scan for Lot: {lot?.lotNo} | |||
</Typography> | |||
{/* Manual Input with Submit-Triggered Helper Text */} | |||
<Box sx={{ mb: 2 }}> | |||
<Typography variant="body2" gutterBottom> | |||
<strong>Manual Input:</strong> | |||
</Typography> | |||
<TextField | |||
fullWidth | |||
size="small" | |||
value={manualInput} | |||
onChange={(e) => setManualInput(e.target.value)} | |||
sx={{ mb: 1 }} | |||
error={manualInputSubmitted && manualInputError} | |||
helperText={ | |||
manualInputSubmitted && manualInputError | |||
? `The input is not the same as the expected lot number.` | |||
: '' | |||
} | |||
/> | |||
<Button | |||
variant="contained" | |||
onClick={handleManualSubmit} | |||
disabled={!manualInput.trim()} | |||
size="small" | |||
color="primary" | |||
> | |||
Submit Manual Input | |||
</Button> | |||
</Box> | |||
{/* Show QR Scan Status */} | |||
{qrValues.length > 0 && ( | |||
<Box sx={{ mb: 2, p: 2, backgroundColor: manualInputError ? '#ffebee' : '#e8f5e8', borderRadius: 1 }}> | |||
<Typography variant="body2" color={manualInputError ? 'error' : 'success'}> | |||
<strong>QR Scan Result:</strong> {qrValues[qrValues.length - 1]} | |||
</Typography> | |||
{manualInputError && ( | |||
<Typography variant="caption" color="error" display="block"> | |||
❌ Mismatch! Expected! | |||
</Typography> | |||
)} | |||
</Box> | |||
)} | |||
<Box sx={{ mt: 2, textAlign: 'right' }}> | |||
<Button onClick={onClose} variant="outlined"> | |||
Cancel | |||
</Button> | |||
</Box> | |||
</Box> | |||
</Modal> | |||
); | |||
}; | |||
const LotTable: React.FC<LotTableProps> = ({ | |||
lotData, | |||
@@ -266,8 +353,14 @@ const LotTable: React.FC<LotTableProps> = ({ | |||
switch (lot.stockOutLineStatus?.toLowerCase()) { | |||
case 'pending': | |||
return "Please finish QC check and pick order."; | |||
case 'completed': | |||
case 'checked': | |||
return "Please submit the pick order."; | |||
case 'partially_completed': | |||
return "Partial quantity submitted. You can submit more or complete the order."; | |||
case 'completed': | |||
return "Pick order completed successfully!"; | |||
case 'rejected': | |||
return "QC check failed. Lot has been rejected and marked as unavailable."; | |||
case 'unavailable': | |||
return "This order is insufficient, please pick another lot."; | |||
default: | |||
@@ -452,24 +545,46 @@ const LotTable: React.FC<LotTableProps> = ({ | |||
{/* Lot Actual Pick Qty */} | |||
<TableCell align="right"> | |||
<TextField | |||
type="number" | |||
value={selectedRowId ? (pickQtyData[selectedRowId]?.[lot.lotId] || 0) : 0} | |||
onChange={(e) => { | |||
if (selectedRowId) { | |||
onPickQtyChange( | |||
selectedRowId, | |||
lot.lotId, // This should be unique (ill.id) | |||
parseInt(e.target.value) || 0 | |||
); | |||
<TextField | |||
type="number" | |||
value={selectedRowId ? (pickQtyData[selectedRowId]?.[lot.lotId] || '') : ''} // ✅ Fixed: Use empty string instead of 0 | |||
onChange={(e) => { | |||
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); | |||
} | |||
} | |||
}} | |||
inputProps={{ min: 0, max: lot.availableQty }} | |||
// ✅ Allow input for available AND insufficient_stock lots | |||
disabled={lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable'} | |||
sx={{ width: '80px' }} | |||
/> | |||
</TableCell> | |||
} | |||
}} | |||
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 | |||
/> | |||
</TableCell> | |||
{/* Submit Button */} | |||
<TableCell align="center"> | |||
@@ -479,9 +594,15 @@ const LotTable: React.FC<LotTableProps> = ({ | |||
if (selectedRowId) { | |||
onSubmitPickQty(selectedRowId, lot.lotId); | |||
} | |||
}} | |||
disabled={ | |||
(lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable') || | |||
!pickQtyData[selectedRowId!]?.[lot.lotId] || | |||
!lot.stockOutLineStatus || // Must have stock out line | |||
!['checked', 'partially_completed'].includes(lot.stockOutLineStatus.toLowerCase()) // Only these statuses | |||
} | |||
// ✅ Allow submission for available AND insufficient_stock lots | |||
disabled={(lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable') || !pickQtyData[selectedRowId!]?.[lot.lotId]} | |||
sx={{ | |||
fontSize: '0.75rem', | |||
py: 0.5, | |||
@@ -69,6 +69,7 @@ import dayjs from "dayjs"; | |||
import { dummyQCData } from "../PoDetail/dummyQcTemplate"; | |||
import { CreateStockOutLine } from "@/app/api/pickOrder/actions"; | |||
import LotTable from './LotTable'; | |||
import { updateInventoryLotLineStatus, updateInventoryStatus, updateInventoryLotLineQuantities } from "@/app/api/inventory/actions"; | |||
interface Props { | |||
filterArgs: Record<string, any>; | |||
@@ -318,21 +319,25 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { | |||
} | |||
}, [selectedConsoCode, fetchConso, formProps]); | |||
const handlePickQtyChange = useCallback((lineId: number, lotId: number, value: number) => { | |||
const handlePickQtyChange = useCallback((lineId: number, lotId: number, value: number | string) => { | |||
console.log("Changing pick qty:", { lineId, lotId, value }); | |||
// ✅ Handle both number and string values | |||
const numericValue = typeof value === 'string' ? (value === '' ? 0 : parseInt(value, 10)) : value; | |||
setPickQtyData(prev => { | |||
const newData = { | |||
...prev, | |||
[lineId]: { | |||
...prev[lineId], | |||
[lotId]: value | |||
[lotId]: numericValue | |||
} | |||
}; | |||
console.log("New pick qty data:", newData); | |||
return newData; | |||
}); | |||
}, []); | |||
const handleSubmitPickQty = useCallback(async (lineId: number, lotId: number) => { | |||
const qty = pickQtyData[lineId]?.[lotId] || 0; | |||
console.log(`提交拣货数量: Line ${lineId}, Lot ${lotId}, Qty ${qty}`); | |||
@@ -344,28 +349,60 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { | |||
} | |||
try { | |||
// ✅ Update the stock out line quantity | |||
const updateData = { | |||
id: selectedLot.stockOutLineId, | |||
status: selectedLot.stockOutLineStatus || 'PENDING', // Keep current status | |||
qty: qty // Update with the submitted quantity | |||
}; | |||
// ✅ Only two statuses: partially_completed or completed | |||
let newStatus = 'partially_completed'; // Default status | |||
console.log("Updating stock out line quantity:", updateData); | |||
const result = await updateStockOutLineStatus(updateData); | |||
if (qty >= selectedLot.requiredQty) { | |||
newStatus = 'completed'; // Full quantity picked | |||
} | |||
// If qty < requiredQty, stays as 'partially_completed' | |||
if (result) { | |||
console.log("Stock out line quantity updated successfully:", result); | |||
// ✅ Function 1: Update stock out line with new status and quantity | |||
try { | |||
// ✅ Function 1: Update stock out line with new status and quantity | |||
const stockOutLineUpdate = await updateStockOutLineStatus({ | |||
id: selectedLot.stockOutLineId, | |||
status: newStatus, | |||
qty: qty | |||
}); | |||
console.log("✅ Stock out line updated:", stockOutLineUpdate); | |||
// ✅ Refresh lot data to show updated "Qty Already Picked" | |||
if (selectedRowId) { | |||
handleRowSelect(selectedRowId); | |||
} | |||
} catch (error) { | |||
console.error("❌ Error updating stock out line:", error); | |||
return; // Stop execution if this fails | |||
} | |||
// ✅ Function 2: Update inventory lot line (balance hold_qty and out_qty) | |||
if (qty > 0) { | |||
const inventoryLotLineUpdate = await updateInventoryLotLineQuantities({ | |||
inventoryLotLineId: lotId, | |||
qty: qty, | |||
status: 'available', | |||
operation: 'pick' | |||
}); | |||
console.log("Inventory lot line updated:", inventoryLotLineUpdate); | |||
} | |||
// ✅ Function 3: Handle inventory table onhold if needed | |||
if (newStatus === 'completed') { | |||
// All required quantity picked - might need to update inventory status | |||
// Note: We'll handle inventory update in a separate function or after selectedRow is available | |||
console.log("Completed status - inventory update needed but selectedRow not available yet"); | |||
} | |||
console.log("All updates completed successfully"); | |||
// ✅ Refresh lot data to show updated quantities | |||
if (selectedRowId) { | |||
await handleRowSelect(selectedRowId, true); | |||
// Note: We'll handle refresh after the function is properly defined | |||
console.log("Data refresh needed but handleRowSelect not available yet"); | |||
} | |||
await handleFetchAllPickOrderDetails(); | |||
} catch (error) { | |||
console.error("Error updating stock out line quantity:", error); | |||
console.error("Error updating pick quantity:", error); | |||
} | |||
}, [pickQtyData, lotData, selectedRowId]); | |||
@@ -585,7 +622,31 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => { | |||
} | |||
return null; | |||
}, [selectedRowId, pickOrderDetails]); | |||
const handleInventoryUpdate = useCallback(async (itemId: number, lotId: number, qty: number) => { | |||
try { | |||
const inventoryUpdate = await updateInventoryStatus({ | |||
itemId: itemId, | |||
lotId: lotId, | |||
status: 'reserved', | |||
qty: qty | |||
}); | |||
console.log("Inventory status updated:", inventoryUpdate); | |||
} catch (error) { | |||
console.error("Error updating inventory status:", error); | |||
} | |||
}, []); | |||
// ✅ Add this function after handleRowSelect is defined | |||
const handleDataRefresh = useCallback(async () => { | |||
if (selectedRowId) { | |||
try { | |||
await handleRowSelect(selectedRowId, true); | |||
} catch (error) { | |||
console.error("Error refreshing data:", error); | |||
} | |||
} | |||
}, [selectedRowId, handleRowSelect]); | |||
const handleInsufficientStock = useCallback(async () => { | |||
console.log("Insufficient stock - testing resuggest API"); | |||
@@ -36,6 +36,15 @@ import { | |||
} from "@/app/api/inventory/actions"; // ✅ 导入新的 API | |||
import { dayjsToInputDateString } from "@/app/utils/formatUtil"; | |||
import dayjs from "dayjs"; | |||
// Define QcData interface locally | |||
interface ExtendedQcItem extends QcItemWithChecks { | |||
qcPassed?: boolean; | |||
failQty?: number; | |||
remarks?: string; | |||
order?: number; // ✅ Add order property | |||
stableId?: string; // ✅ Also add stableId for better row identification | |||
} | |||
interface Props extends CommonProps { | |||
itemDetail: GetPickOrderLineInfo & { | |||
pickOrderCode: string; | |||
@@ -46,22 +55,11 @@ interface Props extends CommonProps { | |||
selectedLotId?: number; | |||
onStockOutLineUpdate?: () => void; | |||
lotData: LotPickData[]; | |||
// ✅ Add missing props | |||
pickQtyData?: PickQtyData; | |||
selectedRowId?: number; | |||
// ✅ Add callback to update pickQtyData in parent | |||
onPickQtyUpdate?: (updatedPickQtyData: PickQtyData) => void; | |||
} | |||
// Define QcData interface locally | |||
interface ExtendedQcItem extends QcItemWithChecks { | |||
qcPassed?: boolean; | |||
failQty?: number; | |||
remarks?: string; | |||
order?: number; // ✅ Add order property | |||
stableId?: string; // ✅ Also add stableId for better row identification | |||
} | |||
const style = { | |||
position: "absolute", | |||
top: "50%", | |||
@@ -238,6 +236,34 @@ const PickQcStockInModalVer3: React.FC<Props> = ({ | |||
} | |||
}, [itemDetail, qcItems.length, selectedLotId, lotData]); | |||
// ✅ Add this helper function at the top of the component | |||
const safeClose = useCallback(() => { | |||
if (onClose) { | |||
// Create a mock event object that satisfies the Modal onClose signature | |||
const mockEvent = { | |||
target: null, | |||
currentTarget: null, | |||
type: 'close', | |||
preventDefault: () => {}, | |||
stopPropagation: () => {}, | |||
bubbles: false, | |||
cancelable: false, | |||
defaultPrevented: false, | |||
isTrusted: false, | |||
timeStamp: Date.now(), | |||
nativeEvent: null, | |||
isDefaultPrevented: () => false, | |||
isPropagationStopped: () => false, | |||
persist: () => {}, | |||
eventPhase: 0, | |||
isPersistent: () => false | |||
} as any; | |||
// ✅ Fixed: Pass both event and reason parameters | |||
onClose(mockEvent, 'escapeKeyDown'); // 'escapeKeyDown' is a valid reason | |||
} | |||
}, [onClose]); | |||
// ✅ 修改:移除 alert 弹窗,改为控制台日志 | |||
const onSubmitQc = useCallback<SubmitHandler<any>>( | |||
async (data, event) => { | |||
@@ -292,72 +318,52 @@ const PickQcStockInModalVer3: React.FC<Props> = ({ | |||
try { | |||
const allPassed = qcData.qcItems.every(item => item.isPassed); | |||
if (qcDecision === "1") { | |||
// ✅ QC Decision 1: Accept - Update lot's required pick qty to actual pick qty | |||
// ✅ Use selectedLotId to get the actual pick qty from pickQtyData | |||
const actualPickQty = pickQtyData?.[selectedRowId || 0]?.[selectedLot?.lotId || 0] || 0; | |||
console.log("QC Decision 1 - Accept: Updating lot required pick qty to actual pick qty:", { | |||
lotId: selectedLot.lotId, | |||
currentRequiredQty: selectedLot.requiredQty, | |||
newRequiredQty: actualPickQty | |||
}); | |||
// Update stock out line status to completed | |||
const newStockOutLineStatus = 'completed'; | |||
if (qcDecision === "2") { | |||
// ✅ QC Decision 2: Report and Re-pick | |||
console.log("QC Decision 2 - Report and Re-pick: Rejecting lot and marking as unavailable"); | |||
// ✅ Stock out line status: rejected | |||
await updateStockOutLineStatus({ | |||
id: selectedLotId, | |||
status: newStockOutLineStatus, | |||
qty: actualPickQty // Use actual pick qty | |||
status: 'rejected', | |||
qty: acceptQty || 0 | |||
}); | |||
} else if (qcDecision === "2") { | |||
// ✅ QC Decision 2: Report and Re-pick - Return to no accept and pick another lot | |||
console.log("QC Decision 2 - Report and Re-pick: Returning to no accept and allowing another lot pick"); | |||
// ✅ Inventory lot line status: unavailable | |||
if (selectedLot) { | |||
await updateInventoryLotLineStatus({ | |||
inventoryLotLineId: selectedLot.lotId, | |||
status: 'unavailable', | |||
qty: acceptQty || 0, | |||
operation: 'reject' | |||
}); | |||
} | |||
// ✅ Close modal and refresh data | |||
safeClose(); // ✅ Fixed: Use safe close function with both parameters | |||
if (onStockOutLineUpdate) { | |||
onStockOutLineUpdate(); | |||
} | |||
// Update stock out line status to rejected (for re-pick) | |||
const newStockOutLineStatus = 'rejected'; | |||
} else if (qcDecision === "1") { | |||
// ✅ QC Decision 1: Accept | |||
console.log("QC Decision 1 - Accept: QC passed"); | |||
// ✅ Stock out line status: checked (QC completed) | |||
await updateStockOutLineStatus({ | |||
id: selectedLotId, | |||
status: newStockOutLineStatus, | |||
qty: selectedLot.requiredQty || 0 | |||
status: 'checked', | |||
qty: acceptQty || 0 | |||
}); | |||
// ✅ Update inventory lot line status to unavailable so user can pick another lot | |||
try { | |||
console.log("Updating inventory lot line status to unavailable for re-pick:", { | |||
inventoryLotLineId: selectedLot.lotId, | |||
status: 'unavailable' | |||
}); | |||
await updateInventoryLotLineStatus({ | |||
inventoryLotLineId: selectedLot.lotId, | |||
status: 'unavailable' | |||
}); | |||
console.log("Inventory lot line status updated to unavailable - user can now pick another lot"); | |||
} catch (error) { | |||
console.error("Failed to update inventory lot line status:", error); | |||
} | |||
// ✅ Inventory lot line status: NO CHANGE needed | |||
// Keep the existing status from handleSubmitPickQty | |||
// ✅ Also update inventory lot line status for failed QC items | |||
if (!allPassed) { | |||
try { | |||
console.log("Updating inventory lot line status for failed QC items:", { | |||
inventoryLotLineId: selectedLot.lotId, | |||
status: 'unavailable' | |||
}); | |||
await updateInventoryLotLineStatus({ | |||
inventoryLotLineId: selectedLot.lotId, | |||
status: 'unavailable' | |||
}); | |||
console.log("Failed QC items inventory lot line status updated to unavailable"); | |||
} catch (error) { | |||
console.error("Failed to update failed QC items inventory lot line status:", error); | |||
} | |||
} | |||
// ✅ Close modal and refresh data | |||
safeClose(); // ✅ Fixed: Use safe close function with both parameters | |||
if (onStockOutLineUpdate) { | |||
onStockOutLineUpdate(); | |||
} | |||
} | |||
console.log("Stock out line status updated successfully after QC"); | |||
@@ -622,8 +628,19 @@ const PickQcStockInModalVer3: React.FC<Props> = ({ | |||
/> | |||
</FormControl> | |||
</Grid> | |||
/* | |||
<Grid item xs={12} sx={{ mt: 2 }}> | |||
{/* ✅ Show escalation component when QC Decision = 2 (Report and Re-pick) */} | |||
{qcDecision == 2 && ( | |||
<Grid item xs={12}> | |||
<EscalationComponent | |||
forSupervisor={false} | |||
isCollapsed={isCollapsed} | |||
setIsCollapsed={setIsCollapsed} | |||
/> | |||
</Grid> | |||
)} | |||
<Grid item xs={12} sx={{ mt: 2 }}> | |||
<Stack direction="row" justifyContent="flex-start" gap={1}> | |||
<Button | |||
variant="contained" | |||
@@ -171,6 +171,7 @@ | |||
"Group Code": "分組編號", | |||
"Job Order Code": "工單編號", | |||
"QC Check": "QC 檢查", | |||
"QR Code Scan": "QR Code掃描" | |||
"QR Code Scan": "QR Code掃描", | |||
"Pick Order Details": "提料單詳情" | |||
} |