| @@ -324,9 +324,11 @@ export interface AllJoborderProductProcessInfoResponse { | |||||
| assignedTo: number; | assignedTo: number; | ||||
| pickOrderId: number; | pickOrderId: number; | ||||
| pickOrderStatus: string; | pickOrderStatus: string; | ||||
| itemCode: string; | |||||
| itemName: string; | itemName: string; | ||||
| requiredQty: number; | requiredQty: number; | ||||
| jobOrderId: number; | jobOrderId: number; | ||||
| uom: string; | |||||
| stockInLineId: number; | stockInLineId: number; | ||||
| jobOrderCode: string; | jobOrderCode: string; | ||||
| productProcessLineCount: number; | productProcessLineCount: number; | ||||
| @@ -908,9 +910,9 @@ export const fetchCompletedJobOrderPickOrdersrecords = cache(async () => { | |||||
| }, | }, | ||||
| ); | ); | ||||
| }); | }); | ||||
| export const fetchJoForPrintQrCode = cache(async () => { | |||||
| export const fetchJoForPrintQrCode = cache(async (date: string) => { | |||||
| return serverFetchJson<JobOrderListForPrintQrCodeResponse[]>( | return serverFetchJson<JobOrderListForPrintQrCodeResponse[]>( | ||||
| `${BASE_API_URL}/jo/joForPrintQrCode`, | |||||
| `${BASE_API_URL}/jo/joForPrintQrCode/${date}`, | |||||
| { | { | ||||
| method: "GET", | method: "GET", | ||||
| next: { tags: ["jo-print-qr-code"] }, | next: { tags: ["jo-print-qr-code"] }, | ||||
| @@ -17,6 +17,10 @@ import { | |||||
| Paper, | Paper, | ||||
| IconButton, | IconButton, | ||||
| Tooltip, | Tooltip, | ||||
| FormControl, | |||||
| InputLabel, | |||||
| Select, | |||||
| MenuItem, | |||||
| } from "@mui/material"; | } from "@mui/material"; | ||||
| import QrCodeIcon from '@mui/icons-material/QrCode'; | import QrCodeIcon from '@mui/icons-material/QrCode'; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| @@ -50,11 +54,28 @@ const FinishedQcJobOrderList: React.FC<FinishedQcJobOrderListProps> = ({ | |||||
| const [page, setPage] = useState(0); | const [page, setPage] = useState(0); | ||||
| const [isPrinting, setIsPrinting] = useState(false); | const [isPrinting, setIsPrinting] = useState(false); | ||||
| const [printingId, setPrintingId] = useState<number | null>(null); | const [printingId, setPrintingId] = useState<number | null>(null); | ||||
| const [selectedDate, setSelectedDate] = useState<string>("today"); | |||||
| const getDateLabel = (offset: number) => { | |||||
| return dayjs().subtract(offset, 'day').format('YYYY-MM-DD'); | |||||
| }; | |||||
| // 根据选择的日期获取实际日期字符串 | |||||
| const getDateParam = (dateOption: string): string => { | |||||
| if (dateOption === "today") { | |||||
| return dayjs().format('YYYY-MM-DD'); | |||||
| } else if (dateOption === "yesterday") { | |||||
| return dayjs().subtract(1, 'day').format('YYYY-MM-DD'); | |||||
| } else if (dateOption === "dayBeforeYesterday") { | |||||
| return dayjs().subtract(2, 'day').format('YYYY-MM-DD'); | |||||
| } | |||||
| return dayjs().format('YYYY-MM-DD'); | |||||
| }; | |||||
| const fetchJobOrders = useCallback(async () => { | const fetchJobOrders = useCallback(async () => { | ||||
| setLoading(true); | setLoading(true); | ||||
| try { | try { | ||||
| const data = await fetchJoForPrintQrCode(); | |||||
| const dateParam = getDateParam(selectedDate); | |||||
| const data = await fetchJoForPrintQrCode(dateParam); | |||||
| setJobOrders(data || []); | setJobOrders(data || []); | ||||
| setPage(0); | setPage(0); | ||||
| } catch (e) { | } catch (e) { | ||||
| @@ -63,7 +84,9 @@ const FinishedQcJobOrderList: React.FC<FinishedQcJobOrderListProps> = ({ | |||||
| } finally { | } finally { | ||||
| setLoading(false); | setLoading(false); | ||||
| } | } | ||||
| }, []); | |||||
| }, [selectedDate]); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| fetchJobOrders(); | fetchJobOrders(); | ||||
| @@ -114,6 +137,34 @@ const FinishedQcJobOrderList: React.FC<FinishedQcJobOrderListProps> = ({ | |||||
| return ( | return ( | ||||
| <Box> | <Box> | ||||
| {/* Date Selector */} | |||||
| <Stack direction="row" spacing={2} sx={{ mb: 2, alignItems: 'flex-start' }}> | |||||
| <Box sx={{ maxWidth: 300 }}> | |||||
| <FormControl fullWidth size="small"> | |||||
| <InputLabel id="date-select-label">{t("Select Date")}</InputLabel> | |||||
| <Select | |||||
| labelId="date-select-label" | |||||
| id="date-select" | |||||
| value={selectedDate} | |||||
| // label={t("Select Date")} | |||||
| onChange={(e) => { | |||||
| setSelectedDate(e.target.value); | |||||
| }} | |||||
| > | |||||
| <MenuItem value="today"> | |||||
| {t("Today")} ({getDateLabel(0)}) | |||||
| </MenuItem> | |||||
| <MenuItem value="yesterday"> | |||||
| {t("Yesterday")} ({getDateLabel(1)}) | |||||
| </MenuItem> | |||||
| <MenuItem value="dayBeforeYesterday"> | |||||
| {t("Day Before Yesterday")} ({getDateLabel(2)}) | |||||
| </MenuItem> | |||||
| </Select> | |||||
| </FormControl> | |||||
| </Box> | |||||
| </Stack> | |||||
| {loading ? ( | {loading ? ( | ||||
| <Box sx={{ display: "flex", justifyContent: "center", p: 3 }}> | <Box sx={{ display: "flex", justifyContent: "center", p: 3 }}> | ||||
| <CircularProgress /> | <CircularProgress /> | ||||
| @@ -56,7 +56,7 @@ const ProductionProcessDetail: React.FC<ProductProcessDetailProps> = ({ | |||||
| onBack, | onBack, | ||||
| fromJosave, | fromJosave, | ||||
| }) => { | }) => { | ||||
| const { t } = useTranslation(); | |||||
| const { t } = useTranslation("common"); | |||||
| const { data: session } = useSession() as { data: SessionWithTokens | null }; | const { data: session } = useSession() as { data: SessionWithTokens | null }; | ||||
| const currentUserId = session?.id ? parseInt(session.id) : undefined; | const currentUserId = session?.id ? parseInt(session.id) : undefined; | ||||
| const { values: qrValues, startScan, stopScan, resetScan } = useQrCodeScannerContext(); | const { values: qrValues, startScan, stopScan, resetScan } = useQrCodeScannerContext(); | ||||
| @@ -334,16 +334,6 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| const effectiveEquipmentCode = | const effectiveEquipmentCode = | ||||
| scannedEquipmentCode ?? null; | scannedEquipmentCode ?? null; | ||||
| if (!effectiveEquipmentCode) { | |||||
| console.error("No equipment code available"); | |||||
| alert(t("Please scan equipment code or equipment detail ID")); | |||||
| setIsAutoSubmitting(false); | |||||
| if (autoSubmitTimerRef.current) { | |||||
| clearTimeout(autoSubmitTimerRef.current); | |||||
| autoSubmitTimerRef.current = null; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| console.log("Submitting scan data with equipmentCode:", { | console.log("Submitting scan data with equipmentCode:", { | ||||
| productProcessLineId: lineId, | productProcessLineId: lineId, | ||||
| @@ -353,7 +343,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| const response = await newUpdateProductProcessLineQrscan({ | const response = await newUpdateProductProcessLineQrscan({ | ||||
| productProcessLineId: lineId, | productProcessLineId: lineId, | ||||
| equipmentCode: effectiveEquipmentCode, | |||||
| equipmentCode: effectiveEquipmentCode ?? "", | |||||
| staffNo: scannedStaffNo, | staffNo: scannedStaffNo, | ||||
| }); | }); | ||||
| @@ -423,6 +413,8 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| setProcessedQrCodes(new Set()); | setProcessedQrCodes(new Set()); | ||||
| setScannedOperatorId(null); | setScannedOperatorId(null); | ||||
| setScannedEquipmentId(null); | setScannedEquipmentId(null); | ||||
| setScannedStaffNo(null); // ✅ Add this | |||||
| setScannedEquipmentCode(null); | |||||
| setIsAutoSubmitting(false); // 添加:重置自动提交状态 | setIsAutoSubmitting(false); // 添加:重置自动提交状态 | ||||
| setLineDetailForScan(null); | setLineDetailForScan(null); | ||||
| // 获取 line detail 以获取 bomProcessEquipmentId | // 获取 line detail 以获取 bomProcessEquipmentId | ||||
| @@ -446,7 +438,9 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| } | } | ||||
| setIsManualScanning(false); | setIsManualScanning(false); | ||||
| setIsAutoSubmitting(false); // 添加:重置自动提交状态 | |||||
| setIsAutoSubmitting(false); | |||||
| setScannedStaffNo(null); // ✅ Add this | |||||
| setScannedEquipmentCode(null); | |||||
| stopScan(); | stopScan(); | ||||
| resetScan(); | resetScan(); | ||||
| }, [stopScan, resetScan]); | }, [stopScan, resetScan]); | ||||
| @@ -461,7 +455,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| } | } | ||||
| }; | }; | ||||
| // 提交扫描结果并验证 | // 提交扫描结果并验证 | ||||
| /* | |||||
| useEffect(() => { | useEffect(() => { | ||||
| console.log("Auto-submit check:", { | console.log("Auto-submit check:", { | ||||
| scanningLineId, | scanningLineId, | ||||
| @@ -501,6 +495,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| // 只在组件卸载时清除 | // 只在组件卸载时清除 | ||||
| }; | }; | ||||
| }, [scanningLineId, scannedStaffNo, scannedEquipmentCode, isAutoSubmitting, isManualScanning, submitScanAndStart]); | }, [scanningLineId, scannedStaffNo, scannedEquipmentCode, isAutoSubmitting, isManualScanning, submitScanAndStart]); | ||||
| */ | |||||
| useEffect(() => { | useEffect(() => { | ||||
| return () => { | return () => { | ||||
| if (autoSubmitTimerRef.current) { | if (autoSubmitTimerRef.current) { | ||||
| @@ -518,6 +513,9 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| setScannedEquipmentId(null); | setScannedEquipmentId(null); | ||||
| setProcessedQrCodes(new Set()); | setProcessedQrCodes(new Set()); | ||||
| setScannedStaffNo(null); | |||||
| setScannedEquipmentCode(null); | |||||
| setProcessedQrCodes(new Set()); | |||||
| // 清除之前的定时器 | // 清除之前的定时器 | ||||
| if (autoSubmitTimerRef.current) { | if (autoSubmitTimerRef.current) { | ||||
| clearTimeout(autoSubmitTimerRef.current); | clearTimeout(autoSubmitTimerRef.current); | ||||
| @@ -783,7 +781,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| {/* ✅ Show both options */} | {/* ✅ Show both options */} | ||||
| {scannedEquipmentCode | {scannedEquipmentCode | ||||
| ? `${t("Equipment Code")}: ${scannedEquipmentCode}` | ? `${t("Equipment Code")}: ${scannedEquipmentCode}` | ||||
| : t("Please scan equipment code or equipment detail id") | |||||
| : t("Please scan equipment code") | |||||
| } | } | ||||
| </Typography> | </Typography> | ||||
| </Box> | </Box> | ||||
| @@ -809,7 +807,7 @@ const processQrCode = useCallback((qrValue: string, lineId: number) => { | |||||
| <Button | <Button | ||||
| variant="contained" | variant="contained" | ||||
| onClick={() => scanningLineId && handleSubmitScanAndStart(scanningLineId)} | onClick={() => scanningLineId && handleSubmitScanAndStart(scanningLineId)} | ||||
| disabled={!scannedStaffNo || (!scannedEquipmentCode)} | |||||
| disabled={!scannedStaffNo } | |||||
| > | > | ||||
| {t("Submit & Start")} | {t("Submit & Start")} | ||||
| </Button> | </Button> | ||||
| @@ -316,7 +316,7 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||||
| headerAlign: "left", | headerAlign: "left", | ||||
| type: "number", | type: "number", | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return <Typography sx={{ fontSize: "18px" }}>{params.value}</Typography>; | |||||
| return <Typography sx={{ fontWeight: 500 }}>{params.value}</Typography>; | |||||
| }, | }, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -326,16 +326,28 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||||
| align: "left", | align: "left", | ||||
| headerAlign: "left", | headerAlign: "left", | ||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return <Typography sx={{ fontSize: "18px" }}>{params.value || ""}</Typography>; | |||||
| return( | |||||
| <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}> | |||||
| <Typography sx={{ fontWeight: 500 }}> </Typography> | |||||
| <Typography sx={{ fontWeight: 500 }}>{params.value || ""}</Typography> | |||||
| <Typography sx={{ fontWeight: 500 }}> </Typography> | |||||
| </Box> | |||||
| ) | |||||
| }, | }, | ||||
| }, | }, | ||||
| ]; | ]; | ||||
| const productionProcessesLineRemarkTableRows = | const productionProcessesLineRemarkTableRows = | ||||
| processData?.productProcessLines?.map((line: any) => ({ | processData?.productProcessLines?.map((line: any) => ({ | ||||
| id: line.seqNo, | id: line.seqNo, | ||||
| seqNo: line.seqNo, | seqNo: line.seqNo, | ||||
| description: line.description ?? "", | description: line.description ?? "", | ||||
| })) ?? []; | })) ?? []; | ||||
| @@ -487,21 +499,37 @@ const handleRelease = useCallback(async ( jobOrderId: number) => { | |||||
| /> | /> | ||||
| </Box> | </Box> | ||||
| ); | ); | ||||
| const ProductionProcessesLineRemarkTableContent = () => ( | |||||
| <Box sx={{ mt: 2 }}> | |||||
| <ProcessSummaryHeader processData={processData} /> | |||||
| <StyledDataGrid | |||||
| sx={{ | |||||
| "--DataGrid-overlayHeight": "100px", | |||||
| }} | |||||
| disableColumnMenu | |||||
| rows={productionProcessesLineRemarkTableRows ?? []} | |||||
| columns={productionProcessesLineRemarkTableColumns} | |||||
| getRowHeight={() => 'auto'} | |||||
| /> | |||||
| </Box> | |||||
| ); | |||||
| const ProductionProcessesLineRemarkTableContent = () => ( | |||||
| <Box sx={{ mt: 2 }}> | |||||
| <ProcessSummaryHeader processData={processData} /> | |||||
| <StyledDataGrid | |||||
| sx={{ | |||||
| "--DataGrid-overlayHeight": "100px", | |||||
| // ✅ Match ProductionProcessDetail font size (default body2 = 0.875rem) | |||||
| "& .MuiDataGrid-cell": { | |||||
| fontSize: "0.875rem", // ✅ Match default body2 size | |||||
| fontWeight: 500, | |||||
| }, | |||||
| "& .MuiDataGrid-columnHeader": { | |||||
| fontSize: "0.875rem", // ✅ Match header size | |||||
| fontWeight: 600, | |||||
| }, | |||||
| // ✅ Ensure empty columns are visible | |||||
| "& .MuiDataGrid-columnHeaders": { | |||||
| display: "flex", | |||||
| }, | |||||
| "& .MuiDataGrid-row": { | |||||
| display: "flex", | |||||
| }, | |||||
| }} | |||||
| disableColumnMenu | |||||
| rows={productionProcessesLineRemarkTableRows ?? []} | |||||
| columns={productionProcessesLineRemarkTableColumns} | |||||
| getRowHeight={() => 'auto'} | |||||
| hideFooter={false} // ✅ Ensure footer is visible | |||||
| /> | |||||
| </Box> | |||||
| ); | |||||
| return ( | return ( | ||||
| @@ -235,10 +235,10 @@ const ProductProcessList: React.FC<ProductProcessListProps> = ({ onSelectProcess | |||||
| </Stack> | </Stack> | ||||
| <Typography variant="body2" color="text.secondary"> | <Typography variant="body2" color="text.secondary"> | ||||
| {t("Item Name")}: {process.itemName} | |||||
| {t("Item Name")}: {process.itemCode} {process.itemName} | |||||
| </Typography> | </Typography> | ||||
| <Typography variant="body2" color="text.secondary"> | <Typography variant="body2" color="text.secondary"> | ||||
| {t("Required Qty")}: {process.requiredQty} | |||||
| {t("Required Qty")}: {process.requiredQty} {process.uom} | |||||
| </Typography> | </Typography> | ||||
| <Typography variant="body2" color="text.secondary"> | <Typography variant="body2" color="text.secondary"> | ||||
| {t("Production date")}: {process.date ? dayjs(process.date as any).format(OUTPUT_DATE_FORMAT) : "-"} | {t("Production date")}: {process.date ? dayjs(process.date as any).format(OUTPUT_DATE_FORMAT) : "-"} | ||||
| @@ -410,7 +410,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| <Card sx={{ bgcolor: 'success.50', border: '2px solid', borderColor: 'success.main', mb: 3 }}> | <Card sx={{ bgcolor: 'success.50', border: '2px solid', borderColor: 'success.main', mb: 3 }}> | ||||
| <CardContent> | <CardContent> | ||||
| <Typography variant="h5" color="success.main" gutterBottom fontWeight="bold"> | <Typography variant="h5" color="success.main" gutterBottom fontWeight="bold"> | ||||
| {t("Completed Step")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo}) | |||||
| {t("Completed Step")}: {lineDetail?.name} ({t("Seq")}: {lineDetail?.seqNo}) | |||||
| </Typography> | </Typography> | ||||
| {/*<Divider sx={{ my: 2 }} />*/} | {/*<Divider sx={{ my: 2 }} />*/} | ||||
| @@ -420,27 +420,27 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| {t("Step Information")} | {t("Step Information")} | ||||
| </Typography> | </Typography> | ||||
| <Grid container spacing={2} sx={{ mb: 3 }}> | <Grid container spacing={2} sx={{ mb: 3 }}> | ||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary"> | |||||
| <strong>{t("Description")}:</strong> {lineDetail?.description || "-"} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary"> | |||||
| <strong>{t("Operator")}:</strong> {lineDetail?.operatorName || "-"} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary"> | |||||
| <strong>{t("Equipment")}:</strong> {equipmentName} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary"> | |||||
| <strong>{t("Status")}:</strong> {lineDetail?.status || "-"} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary" sx={{ fontSize: '1.25rem' }}> | |||||
| <strong>{t("Description")}:</strong> {lineDetail?.description || "-"} | |||||
| </Typography> | |||||
| </Grid> | </Grid> | ||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary" sx={{ fontSize: '1.25rem' }}> | |||||
| <strong>{t("Operator")}:</strong> {lineDetail?.operatorName || "-"} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary" sx={{ fontSize: '1.25rem' }}> | |||||
| <strong>{t("Equipment")}:</strong> {equipmentName} | |||||
| </Typography> | |||||
| </Grid> | |||||
| <Grid item xs={12} md={6}> | |||||
| <Typography variant="body2" color="text.secondary" sx={{ fontSize: '1.25rem' }}> | |||||
| <strong>{t("Status")}:</strong> {t(lineDetail?.status || "-")} | |||||
| </Typography> | |||||
| </Grid> | |||||
| </Grid> | |||||
| {/*<Divider sx={{ my: 2 }} />*/} | {/*<Divider sx={{ my: 2 }} />*/} | ||||
| @@ -563,7 +563,7 @@ const ProductionProcessStepExecution: React.FC<ProductionProcessStepExecutionPro | |||||
| <Card sx={{ bgcolor: 'primary.50', border: '2px solid', borderColor: 'primary.main', height: '100%' }}> | <Card sx={{ bgcolor: 'primary.50', border: '2px solid', borderColor: 'primary.main', height: '100%' }}> | ||||
| <CardContent> | <CardContent> | ||||
| <Typography variant="h6" color="primary.main" gutterBottom> | <Typography variant="h6" color="primary.main" gutterBottom> | ||||
| {t("Executing")}: {lineDetail?.name} (Seq: {lineDetail?.seqNo}) | |||||
| {t("Executing")}: {lineDetail?.name} ({t("Seq")}:{lineDetail?.seqNo}) | |||||
| </Typography> | </Typography> | ||||
| <Typography variant="body2" color="text.secondary"> | <Typography variant="body2" color="text.secondary"> | ||||
| {lineDetail?.description} | {lineDetail?.description} | ||||
| @@ -397,7 +397,7 @@ const QcStockInModal: React.FC<Props> = ({ | |||||
| // confirmButtonText: t("confirm putaway"), html: ""}); | // confirmButtonText: t("confirm putaway"), html: ""}); | ||||
| // onOpenPutaway(); | // onOpenPutaway(); | ||||
| const isJobOrderBom = (stockInLineInfo?.jobOrderId != null || printSource === "productionProcess") | const isJobOrderBom = (stockInLineInfo?.jobOrderId != null || printSource === "productionProcess") | ||||
| && stockInLineInfo?.bomDescription === "半成品"; | |||||
| && stockInLineInfo?.bomDescription === "WIP"; | |||||
| if (isJobOrderBom) { | if (isJobOrderBom) { | ||||
| // Auto putaway to default warehouse | // Auto putaway to default warehouse | ||||
| const defaultWarehouseId = stockInLineInfo?.defaultWarehouseId ?? 1; | const defaultWarehouseId = stockInLineInfo?.defaultWarehouseId ?? 1; | ||||
| @@ -417,7 +417,7 @@ const QcStockInModal: React.FC<Props> = ({ | |||||
| itemId: stockInLineInfo?.itemId, // Include Item ID | itemId: stockInLineInfo?.itemId, // Include Item ID | ||||
| purchaseOrderId: stockInLineInfo?.purchaseOrderId, // Include PO ID if exists | purchaseOrderId: stockInLineInfo?.purchaseOrderId, // Include PO ID if exists | ||||
| purchaseOrderLineId: stockInLineInfo?.purchaseOrderLineId, // Include POL ID if exists | purchaseOrderLineId: stockInLineInfo?.purchaseOrderLineId, // Include POL ID if exists | ||||
| acceptedQty: stockInLineInfo?.acceptedQty, // Include acceptedQty | |||||
| acceptedQty:acceptQty, // Include acceptedQty | |||||
| acceptQty: stockInLineInfo?.acceptedQty, // Putaway quantity | acceptQty: stockInLineInfo?.acceptedQty, // Putaway quantity | ||||
| warehouseId: defaultWarehouseId, | warehouseId: defaultWarehouseId, | ||||
| status: "received", // Use string like PutAwayModal | status: "received", // Use string like PutAwayModal | ||||
| @@ -84,7 +84,14 @@ | |||||
| "Detail Scheduling": "詳細排程", | "Detail Scheduling": "詳細排程", | ||||
| "Customer": "客戶", | "Customer": "客戶", | ||||
| "qcItem": "品檢項目", | "qcItem": "品檢項目", | ||||
| "Item": "物料", | |||||
| "Item": "成品/半成品", | |||||
| "Today": "今天", | |||||
| "Yesterday": "昨天", | |||||
| "Input Equipment is not match with process": "輸入的設備與流程不匹配", | |||||
| "Staff No is required": "員工編號必填", | |||||
| "Day Before Yesterday": "前天", | |||||
| "Select Date": "選擇日期", | |||||
| "Production Date": "生產日期", | "Production Date": "生產日期", | ||||
| "QC Check Item": "QC品檢項目", | "QC Check Item": "QC品檢項目", | ||||
| "QC Category": "QC品檢模板", | "QC Category": "QC品檢模板", | ||||
| @@ -179,7 +186,6 @@ | |||||
| "Production Process Information": "生產流程信息", | "Production Process Information": "生產流程信息", | ||||
| "Production Process Steps": "生產流程步驟", | "Production Process Steps": "生產流程步驟", | ||||
| "Scan Operator & Equipment": "掃描操作員和設備", | "Scan Operator & Equipment": "掃描操作員和設備", | ||||
| "Seq": "序號", | |||||
| "Setup Time (mins)": "生產前預備時間(分鐘)", | "Setup Time (mins)": "生產前預備時間(分鐘)", | ||||
| "Start": "開始", | "Start": "開始", | ||||
| "Start QR Scan": "開始掃碼", | "Start QR Scan": "開始掃碼", | ||||
| @@ -195,10 +201,13 @@ | |||||
| "Validation failed. Please check operator and equipment.": "驗證失敗. 請檢查操作員和設備.", | "Validation failed. Please check operator and equipment.": "驗證失敗. 請檢查操作員和設備.", | ||||
| "View": "查看", | "View": "查看", | ||||
| "Back": "返回", | "Back": "返回", | ||||
| "BoM Material": "物料清單", | |||||
| "BoM Material": "成品/半成品清單", | |||||
| "N/A": "不適用", | "N/A": "不適用", | ||||
| "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度", | "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間次序 | 複雜度", | ||||
| "Item Code": "物料編號", | |||||
| "Item Code": "成品/半成品名稱", | |||||
| "Please scan equipment code": "請掃描設備編號", | |||||
| "Equipment Code": "設備編號", | |||||
| "Seq": "步驟", | |||||
| "Item Name": "物料名稱", | "Item Name": "物料名稱", | ||||
| "Job Order Info": "工單信息", | "Job Order Info": "工單信息", | ||||
| "Matching Stock": "工單對料", | "Matching Stock": "工單對料", | ||||
| @@ -8,7 +8,7 @@ | |||||
| "Code": "工單編號", | "Code": "工單編號", | ||||
| "Name": "成品/半成品名稱", | "Name": "成品/半成品名稱", | ||||
| "Picked Qty": "已提料數量", | "Picked Qty": "已提料數量", | ||||
| "Confirm All": "確認所有", | |||||
| "Confirm All": "確認所有提料", | |||||
| "UoM": "銷售單位", | "UoM": "銷售單位", | ||||
| "No": "沒有", | "No": "沒有", | ||||
| "User not found with staffNo:": "用戶不存在", | "User not found with staffNo:": "用戶不存在", | ||||
| @@ -156,7 +156,9 @@ | |||||
| "Reject": "拒絕", | "Reject": "拒絕", | ||||
| "Stock Unit": "庫存單位", | "Stock Unit": "庫存單位", | ||||
| "Group": "組", | "Group": "組", | ||||
| "Item": "物料", | |||||
| "Input Equipment is not match with process": "輸入的設備與流程不匹配", | |||||
| "Item": "成品/半成品", | |||||
| "Select Date": "選擇日期", | |||||
| "No Group": "沒有組", | "No Group": "沒有組", | ||||
| "No created items": "沒有創建物料", | "No created items": "沒有創建物料", | ||||
| "Order Quantity": "需求數量", | "Order Quantity": "需求數量", | ||||
| @@ -284,7 +286,6 @@ | |||||
| "acceptQty must not greater than": "接受數量不能大於", | "acceptQty must not greater than": "接受數量不能大於", | ||||
| "escalation": "升級", | "escalation": "升級", | ||||
| "failedQty": "失敗數量", | "failedQty": "失敗數量", | ||||
| "qcItem": "QC物料", | |||||
| "qcResult": "QC結果", | "qcResult": "QC結果", | ||||
| "remarks": "備註", | "remarks": "備註", | ||||
| "supervisor": "主管", | "supervisor": "主管", | ||||
| @@ -334,13 +335,15 @@ | |||||
| "pending": "待處理", | "pending": "待處理", | ||||
| "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)", | "Please scan equipment code (optional if not required)": "請掃描設備編號(可選)", | ||||
| "Please scan equipment code": "請掃描設備編號", | |||||
| "Equipment Code": "設備編號", | |||||
| "Please scan operator code": "請掃描操作員編號", | "Please scan operator code": "請掃描操作員編號", | ||||
| "Please scan operator code first": "請先掃描操作員編號", | "Please scan operator code first": "請先掃描操作員編號", | ||||
| "Processing Time (mins)": "步驟時間(分鐘)", | "Processing Time (mins)": "步驟時間(分鐘)", | ||||
| "Production Process Information": "生產流程信息", | "Production Process Information": "生產流程信息", | ||||
| "Production Process Steps": "生產流程步驟", | "Production Process Steps": "生產流程步驟", | ||||
| "Scan Operator & Equipment": "掃描操作員和設備", | "Scan Operator & Equipment": "掃描操作員和設備", | ||||
| "Seq": "序號", | |||||
| "Seq:": "步驟", | |||||
| "Setup Time (mins)": "生產前預備時間(分鐘)", | "Setup Time (mins)": "生產前預備時間(分鐘)", | ||||
| "Start": "開始", | "Start": "開始", | ||||
| "Start QR Scan": "開始掃碼", | "Start QR Scan": "開始掃碼", | ||||
| @@ -366,18 +369,13 @@ | |||||
| "View": "查看", | "View": "查看", | ||||
| "Back": "返回", | "Back": "返回", | ||||
| "N/A": "不適用", | "N/A": "不適用", | ||||
| "BoM Material": "物料清單", | |||||
| "BoM Material": "成品/半成品清單", | |||||
| "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間順序 | 複雜度", | "Is Dark | Dense | Float| Scrap Rate| Allergic Substance | Time Sequence | Complexity": "顔色深淺度 | 濃淡 | 浮沉 | 損耗率 | 過敏原 | 時間順序 | 複雜度", | ||||
| "Item Code": "物料編號", | |||||
| "Item Name": "物料名稱", | |||||
| "Enter the number of cartons: ": "請輸入箱數:", | "Enter the number of cartons: ": "請輸入箱數:", | ||||
| "Number of cartons": "箱數", | "Number of cartons": "箱數", | ||||
| "You need to enter a number": "您需要輸入一個數字", | "You need to enter a number": "您需要輸入一個數字", | ||||
| "Number must be at least 1": "數字必須至少為1", | "Number must be at least 1": "數字必須至少為1", | ||||
| "Cancel": "取消", | |||||
| "Print Pick Record": "打印板頭紙", | |||||
| "Printed Successfully.": "成功列印", | |||||
| "Job Order Info": "工單信息", | "Job Order Info": "工單信息", | ||||
| "Matching Stock": "工單對料", | "Matching Stock": "工單對料", | ||||
| "No data found": "沒有找到資料", | "No data found": "沒有找到資料", | ||||