浏览代码

update

master
CANCERYS\kw093 3 天前
父节点
当前提交
a4ea73e17b
共有 5 个文件被更改,包括 353 次插入125 次删除
  1. +40
    -12
      src/app/api/inventory/actions.ts
  2. +145
    -24
      src/components/PickOrderSearch/LotTable.tsx
  3. +81
    -20
      src/components/PickOrderSearch/PickExecution.tsx
  4. +85
    -68
      src/components/PickOrderSearch/PickQcStockInModalVer3.tsx
  5. +2
    -1
      src/i18n/zh/pickOrder.json

+ 40
- 12
src/app/api/inventory/actions.ts 查看文件

@@ -52,6 +52,19 @@ export interface PostInventoryLotLineResponse<T = null> {
entity?: T | T[]; entity?: T | T[];
consoCode?: string; 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) => { export const fetchLotDetail = cache(async (stockInLineId: number) => {
return serverFetchJson<LotLineInfo>( return serverFetchJson<LotLineInfo>(
`${BASE_API_URL}/inventoryLotLine/lot-detail/${stockInLineId}`, `${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) => { export const fetchInventories = cache(async (data: SearchInventory) => {
@@ -90,3 +101,20 @@ export const fetchInventoryLotLines = cache(async (data: SearchInventoryLotLine)
next: { tags: ["inventoryLotLines"] }, 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;
};

+ 145
- 24
src/components/PickOrderSearch/LotTable.tsx 查看文件

@@ -115,7 +115,8 @@ const QrCodeModal: React.FC<{
} }
}, [lot]); }, [lot]);


const handleManualSubmit = () => {
{/*
const handleManualSubmit = () => {
if (manualInput.trim() === lot?.lotNo) { if (manualInput.trim() === lot?.lotNo) {
// ✅ Success - no error helper text needed // ✅ Success - no error helper text needed
onQrCodeSubmit(lot.lotNo); onQrCodeSubmit(lot.lotNo);
@@ -144,8 +145,7 @@ const QrCodeModal: React.FC<{
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
{t("QR Code Scan for Lot")}: {lot?.lotNo} {t("QR Code Scan for Lot")}: {lot?.lotNo}
</Typography> </Typography>
{/* QR Scanner Status */}
<Box sx={{ mb: 2, p: 2, backgroundColor: '#f5f5f5', borderRadius: 1 }}> <Box sx={{ mb: 2, p: 2, backgroundColor: '#f5f5f5', borderRadius: 1 }}>
<Typography variant="body2" gutterBottom> <Typography variant="body2" gutterBottom>
<strong>Scanner Status:</strong> {isScanning ? 'Scanning...' : 'Ready'} <strong>Scanner Status:</strong> {isScanning ? 'Scanning...' : 'Ready'}
@@ -168,7 +168,7 @@ const QrCodeModal: React.FC<{
</Stack> </Stack>
</Box> </Box>


{/* Manual Input with Submit-Triggered Helper Text */}
<Box sx={{ mb: 2 }}> <Box sx={{ mb: 2 }}>
<Typography variant="body2" gutterBottom> <Typography variant="body2" gutterBottom>
<strong>Manual Input:</strong> <strong>Manual Input:</strong>
@@ -199,7 +199,6 @@ const QrCodeModal: React.FC<{
</Button> </Button>
</Box> </Box>


{/* ✅ Show QR Scan Status */}
{qrValues.length > 0 && ( {qrValues.length > 0 && (
<Box sx={{ mb: 2, p: 2, backgroundColor: manualInputError ? '#ffebee' : '#e8f5e8', borderRadius: 1 }}> <Box sx={{ mb: 2, p: 2, backgroundColor: manualInputError ? '#ffebee' : '#e8f5e8', borderRadius: 1 }}>
<Typography variant="body2" color={manualInputError ? 'error' : 'success'}> <Typography variant="body2" color={manualInputError ? 'error' : 'success'}>
@@ -222,6 +221,94 @@ const QrCodeModal: React.FC<{
</Modal> </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> = ({ const LotTable: React.FC<LotTableProps> = ({
lotData, lotData,
@@ -266,8 +353,14 @@ const LotTable: React.FC<LotTableProps> = ({
switch (lot.stockOutLineStatus?.toLowerCase()) { switch (lot.stockOutLineStatus?.toLowerCase()) {
case 'pending': case 'pending':
return "Please finish QC check and pick order."; return "Please finish QC check and pick order.";
case 'completed':
case 'checked':
return "Please submit the pick order."; 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': case 'unavailable':
return "This order is insufficient, please pick another lot."; return "This order is insufficient, please pick another lot.";
default: default:
@@ -452,24 +545,46 @@ const LotTable: React.FC<LotTableProps> = ({
{/* Lot Actual Pick Qty */} {/* Lot Actual Pick Qty */}
<TableCell align="right"> <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 */} {/* Submit Button */}
<TableCell align="center"> <TableCell align="center">
@@ -479,9 +594,15 @@ const LotTable: React.FC<LotTableProps> = ({
if (selectedRowId) { if (selectedRowId) {
onSubmitPickQty(selectedRowId, lot.lotId); 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 // ✅ Allow submission for available AND insufficient_stock lots
disabled={(lot.lotAvailability === 'expired' || lot.lotAvailability === 'status_unavailable') || !pickQtyData[selectedRowId!]?.[lot.lotId]}
sx={{ sx={{
fontSize: '0.75rem', fontSize: '0.75rem',
py: 0.5, py: 0.5,


+ 81
- 20
src/components/PickOrderSearch/PickExecution.tsx 查看文件

@@ -69,6 +69,7 @@ import dayjs from "dayjs";
import { dummyQCData } from "../PoDetail/dummyQcTemplate"; import { dummyQCData } from "../PoDetail/dummyQcTemplate";
import { CreateStockOutLine } from "@/app/api/pickOrder/actions"; import { CreateStockOutLine } from "@/app/api/pickOrder/actions";
import LotTable from './LotTable'; import LotTable from './LotTable';
import { updateInventoryLotLineStatus, updateInventoryStatus, updateInventoryLotLineQuantities } from "@/app/api/inventory/actions";


interface Props { interface Props {
filterArgs: Record<string, any>; filterArgs: Record<string, any>;
@@ -318,21 +319,25 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
} }
}, [selectedConsoCode, fetchConso, formProps]); }, [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 }); 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 => { setPickQtyData(prev => {
const newData = { const newData = {
...prev, ...prev,
[lineId]: { [lineId]: {
...prev[lineId], ...prev[lineId],
[lotId]: value
[lotId]: numericValue
} }
}; };
console.log("New pick qty data:", newData); console.log("New pick qty data:", newData);
return newData; return newData;
}); });
}, []); }, []);
const handleSubmitPickQty = useCallback(async (lineId: number, lotId: number) => { const handleSubmitPickQty = useCallback(async (lineId: number, lotId: number) => {
const qty = pickQtyData[lineId]?.[lotId] || 0; const qty = pickQtyData[lineId]?.[lotId] || 0;
console.log(`提交拣货数量: Line ${lineId}, Lot ${lotId}, Qty ${qty}`); console.log(`提交拣货数量: Line ${lineId}, Lot ${lotId}, Qty ${qty}`);
@@ -344,28 +349,60 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
} }
try { 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) { } catch (error) {
console.error("Error updating stock out line quantity:", error);
console.error("Error updating pick quantity:", error);
} }
}, [pickQtyData, lotData, selectedRowId]); }, [pickQtyData, lotData, selectedRowId]);


@@ -585,7 +622,31 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
} }
return null; return null;
}, [selectedRowId, pickOrderDetails]); }, [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 () => { const handleInsufficientStock = useCallback(async () => {
console.log("Insufficient stock - testing resuggest API"); console.log("Insufficient stock - testing resuggest API");


+ 85
- 68
src/components/PickOrderSearch/PickQcStockInModalVer3.tsx 查看文件

@@ -36,6 +36,15 @@ import {
} from "@/app/api/inventory/actions"; // ✅ 导入新的 API } from "@/app/api/inventory/actions"; // ✅ 导入新的 API
import { dayjsToInputDateString } from "@/app/utils/formatUtil"; import { dayjsToInputDateString } from "@/app/utils/formatUtil";
import dayjs from "dayjs"; 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 { interface Props extends CommonProps {
itemDetail: GetPickOrderLineInfo & { itemDetail: GetPickOrderLineInfo & {
pickOrderCode: string; pickOrderCode: string;
@@ -46,22 +55,11 @@ interface Props extends CommonProps {
selectedLotId?: number; selectedLotId?: number;
onStockOutLineUpdate?: () => void; onStockOutLineUpdate?: () => void;
lotData: LotPickData[]; lotData: LotPickData[];
// ✅ Add missing props
pickQtyData?: PickQtyData; pickQtyData?: PickQtyData;
selectedRowId?: number; 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 = { const style = {
position: "absolute", position: "absolute",
top: "50%", top: "50%",
@@ -238,6 +236,34 @@ const PickQcStockInModalVer3: React.FC<Props> = ({
} }
}, [itemDetail, qcItems.length, selectedLotId, lotData]); }, [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 弹窗,改为控制台日志 // ✅ 修改:移除 alert 弹窗,改为控制台日志
const onSubmitQc = useCallback<SubmitHandler<any>>( const onSubmitQc = useCallback<SubmitHandler<any>>(
async (data, event) => { async (data, event) => {
@@ -292,72 +318,52 @@ const PickQcStockInModalVer3: React.FC<Props> = ({
try { try {
const allPassed = qcData.qcItems.every(item => item.isPassed); 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({ await updateStockOutLineStatus({
id: selectedLotId, 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({ await updateStockOutLineStatus({
id: selectedLotId, 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"); console.log("Stock out line status updated successfully after QC");
@@ -622,8 +628,19 @@ const PickQcStockInModalVer3: React.FC<Props> = ({
/> />
</FormControl> </FormControl>
</Grid> </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}> <Stack direction="row" justifyContent="flex-start" gap={1}>
<Button <Button
variant="contained" variant="contained"


+ 2
- 1
src/i18n/zh/pickOrder.json 查看文件

@@ -171,6 +171,7 @@
"Group Code": "分組編號", "Group Code": "分組編號",
"Job Order Code": "工單編號", "Job Order Code": "工單編號",
"QC Check": "QC 檢查", "QC Check": "QC 檢查",
"QR Code Scan": "QR Code掃描"
"QR Code Scan": "QR Code掃描",
"Pick Order Details": "提料單詳情"


} }

正在加载...
取消
保存