| @@ -1,4 +1,4 @@ | |||
| import React, { useState } from "react"; | |||
| import React, { createContext, useContext, useState, useCallback, Dispatch, SetStateAction } from "react"; | |||
| import { | |||
| Card, | |||
| CardHeader, | |||
| @@ -7,6 +7,7 @@ import { | |||
| Collapse, | |||
| Checkbox, | |||
| Box, | |||
| FormControlLabel, | |||
| } from "@mui/material"; | |||
| import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; | |||
| import ExpandLessIcon from "@mui/icons-material/ExpandLess"; | |||
| @@ -18,6 +19,19 @@ interface CollapsibleCardProps { | |||
| showFilter?: boolean; | |||
| filterText?: string; | |||
| } | |||
| interface CardFilterContextType { | |||
| filter: boolean; | |||
| onFilterChange: (checked: boolean) => void; | |||
| filterText: string; | |||
| setOnFilterChange: (override: () => void) => void; | |||
| } | |||
| export const CardFilterContext = createContext<CardFilterContextType>({ | |||
| filter: false, | |||
| onFilterChange: (checked: boolean) => {}, | |||
| filterText: "FilterText", | |||
| setOnFilterChange: () => {}, //Not working yet | |||
| }); | |||
| const CollapsibleCard: React.FC<CollapsibleCardProps> = ({ | |||
| title, | |||
| @@ -28,38 +42,51 @@ const CollapsibleCard: React.FC<CollapsibleCardProps> = ({ | |||
| }) => { | |||
| const [filter, setFilter] = useState(false); | |||
| const [open, setOpen] = useState(defaultOpen); | |||
| const [onFilterChange, setOnFilterChange] = useState<() => void>(); | |||
| const onFilterChange = (bool : boolean) => { | |||
| setFilter(bool); | |||
| const handleFilterChange = useCallback((checked : boolean) => { | |||
| if (onFilterChange) { | |||
| onFilterChange(); | |||
| } | |||
| setFilter(checked); | |||
| setOpen(true); | |||
| } | |||
| const [open, setOpen] = useState(defaultOpen); | |||
| }, [onFilterChange]); | |||
| return ( | |||
| <Card> | |||
| <CardHeader | |||
| title={title} | |||
| action={ | |||
| <Box display="flex" justifyContent="flex-end" alignItems="center" gap={1}> | |||
| {showFilter && ( | |||
| <> | |||
| <Checkbox | |||
| sx={{textAlign: "left"}} | |||
| checked={filter} | |||
| onChange={(e) => {onFilterChange(e.target.checked);}} | |||
| // disabled={!isEmpty(pickOrder.consoCode)} | |||
| /> <span style={{paddingRight: 20}}>{filterText}</span> | |||
| </>)} | |||
| <IconButton onClick={() => setOpen((v) => !v)}> | |||
| {open ? <ExpandLessIcon /> : <ExpandMoreIcon />} | |||
| </IconButton> | |||
| </Box> | |||
| } | |||
| /> | |||
| <Collapse in={open}> | |||
| <CardContent>{children}</CardContent> | |||
| </Collapse> | |||
| </Card> | |||
| <CardFilterContext.Provider value={{ | |||
| filter, onFilterChange: handleFilterChange, filterText, setOnFilterChange | |||
| }}> | |||
| <Card> | |||
| <CardHeader | |||
| title={title} | |||
| action={ | |||
| <Box display="flex" justifyContent="flex-end" alignItems="center" gap={1}> | |||
| {showFilter && ( | |||
| <> | |||
| <FormControlLabel | |||
| control={ | |||
| <Checkbox | |||
| checked={filter} | |||
| onChange={(e) => handleFilterChange(e.target.checked)} | |||
| /> | |||
| } | |||
| label={filterText} // Use filterText as the label | |||
| sx={{ marginRight: 2 }} // Optional: Adjust spacing | |||
| /> | |||
| </>)} | |||
| <IconButton onClick={() => setOpen((v) => !v)}> | |||
| {open ? <ExpandLessIcon /> : <ExpandMoreIcon />} | |||
| </IconButton> | |||
| </Box> | |||
| } | |||
| /> | |||
| <Collapse in={open}> | |||
| <CardContent>{children}</CardContent> | |||
| </Collapse> | |||
| </Card> | |||
| </CardFilterContext.Provider> | |||
| ); | |||
| }; | |||
| @@ -46,6 +46,8 @@ const DashboardPage: React.FC<Props> = ({ | |||
| <CollapsibleCard | |||
| title={`${t("Responsible Escalation List")} (${t("pending")} : ${ | |||
| getPendingLog().length > 0 ? getPendingLog().length : t("No")})`} | |||
| showFilter={true} | |||
| filterText={t("show completed logs")} | |||
| // defaultOpen={getPendingLog().length > 0} // TODO Fix default not opening | |||
| > | |||
| <CardContent> | |||
| @@ -2,13 +2,14 @@ | |||
| import { Box, Card, CardActionArea, CardContent, CardHeader, Grid, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material"; | |||
| import { useRouter } from "next/navigation"; | |||
| import { useCallback, useMemo, useState } from "react"; | |||
| import { useCallback, useContext, useEffect, useMemo, useState } from "react"; | |||
| import { usePathname } from "next/navigation"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { EscalationResult } from "@/app/api/escalation"; | |||
| import { Column } from "@/components/SearchResults"; | |||
| import SearchResults from "@/components/SearchResults/SearchResults"; | |||
| import { arrayToDateString, arrayToDateTimeString } from "@/app/utils/formatUtil"; | |||
| import { CardFilterContext } from "@/components/CollapsibleCard/CollapsibleCard"; | |||
| export type IQCItems = { | |||
| id: number; | |||
| @@ -36,6 +37,20 @@ const EscalationLogTable: React.FC<Props> = ({ | |||
| const router = useRouter(); | |||
| const [selectedId, setSelectedId] = useState<number | null>(null); | |||
| const [escalationLogs, setEscalationLogs] = useState<EscalationResult[]>([]); | |||
| const useCardFilter = useContext(CardFilterContext); | |||
| const showCompleted = useCardFilter.filter; | |||
| useEffect(() => { | |||
| if (showCompleted) { | |||
| setEscalationLogs(items); | |||
| } else { | |||
| const filteredEscLog = items.filter(log => log.status == "pending"); | |||
| setEscalationLogs(filteredEscLog); | |||
| } | |||
| }, [showCompleted, items]) | |||
| const navigateTo = useCallback( | |||
| (item: EscalationResult) => { | |||
| setSelectedId(item.id); | |||
| @@ -237,7 +252,7 @@ const EscalationLogTable: React.FC<Props> = ({ | |||
| return ( | |||
| <SearchResults | |||
| onRowClick={onRowClick} | |||
| items={items} | |||
| items={escalationLogs} | |||
| columns={getColumnByType(type)} | |||
| isAutoPaging={false} | |||
| /> | |||
| @@ -443,7 +443,7 @@ const closeNewModal = useCallback(() => { | |||
| const status = sil?.status?.toLowerCase(); | |||
| let btnSx = {label:"", color:""}; | |||
| switch (status) { | |||
| case "received": btnSx = {label: t("putaway processing"), color:"secondary.main"}; break; | |||
| case "received": btnSx = {label: t("view putaway"), color:"secondary.main"}; break; | |||
| case "escalated": if (sessionToken?.id == sil?.handlerId) { | |||
| btnSx = {label: t("escalation processing"), color:"warning.main"}; | |||
| break;} | |||
| @@ -198,56 +198,6 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| [], | |||
| ); | |||
| const onOpenScanner = useCallback(() => { | |||
| setOpenScanner(true); | |||
| }, []); | |||
| const onCloseScanner = useCallback(() => { | |||
| setOpenScanner(false); | |||
| }, []); | |||
| const scannerConfig = useMemo<ScannerConfig>( | |||
| () => ({ | |||
| onUpdate: (err, result) => { | |||
| console.log(result); | |||
| console.log(Boolean(result)); | |||
| if (result) { | |||
| const data: QrCodeInfo = JSON.parse(result.getText()); | |||
| console.log(data); | |||
| if (data.warehouseId) { | |||
| console.log(data.warehouseId); | |||
| setWarehouseId(data.warehouseId); | |||
| onCloseScanner(); | |||
| } | |||
| } else return; | |||
| }, | |||
| }), | |||
| [onCloseScanner], | |||
| ); | |||
| // QR Code Scanner | |||
| const scanner = useQrCodeScannerContext(); | |||
| useEffect(() => { | |||
| if (isOpenScanner) { | |||
| scanner.startScan(); | |||
| } else if (!isOpenScanner) { | |||
| scanner.stopScan(); | |||
| } | |||
| }, [isOpenScanner]); | |||
| useEffect(() => { | |||
| if (scanner.values.length > 0) { | |||
| console.log(scanner.values[0]); | |||
| const data: QrCodeInfo = JSON.parse(scanner.values[0]); | |||
| console.log(data); | |||
| if (data.warehouseId) { | |||
| console.log(data.warehouseId); | |||
| setWarehouseId(data.warehouseId); | |||
| onCloseScanner(); | |||
| } | |||
| scanner.resetScan(); | |||
| } | |||
| }, [scanner.values]); | |||
| useEffect(() => { | |||
| setValue("status", "received"); | |||
| // setValue("status", "completed"); | |||
| @@ -536,7 +486,7 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||
| {/* <QrCode content={qrContent} sx={{ width: 200, height: 200 }} /> */} | |||
| <InputDataGrid<PutAwayInput, PutAwayLine, EntryError> | |||
| apiRef={apiRef} | |||
| checkboxSelection={true} | |||
| checkboxSelection={false} | |||
| _formKey={"putAwayLines"} | |||
| columns={columns} | |||
| validateRow={validation} | |||
| @@ -239,13 +239,19 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| { | |||
| field: "code", | |||
| headerName: t("qcItem"), | |||
| wrapText: true, | |||
| flex: 2, | |||
| renderCell: (params) => { | |||
| const index = params.api.getRowIndexRelativeToVisibleRows(params.id) + 1; | |||
| return ( | |||
| <Box> | |||
| <Box | |||
| sx={{ | |||
| lineHeight: 1.5, | |||
| padding: "4px", | |||
| }} | |||
| > | |||
| <b>{`${index}. ${params.value}`}</b><br/> | |||
| {params.row.name}<br/> | |||
| {params.row.name} | |||
| </Box> | |||
| )}, | |||
| }, | |||
| @@ -433,7 +439,7 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| const setDefaultQcDecision = (status : string | undefined) => { | |||
| const param = status?.toLowerCase(); | |||
| if (param !== undefined && param !== null) { | |||
| if (param == "completed" || param == "partially_completed") { | |||
| if (param == "received" || param == "completed" || param == "partially_completed") { | |||
| return 1; | |||
| } else if (param == "rejected") { | |||
| return 2; | |||
| @@ -456,6 +462,13 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| // return row.id || `${row.name}-${Math.random().toString(36).substr(2, 9)}`; | |||
| }; | |||
| const getRowHeight = (row :any) => { // Not used? | |||
| console.log("row", row); | |||
| if (!row.model.name) { | |||
| return (row.model.name.length ?? 10) * 1.2 + 30; | |||
| } else { return 60} | |||
| }; | |||
| return ( | |||
| <> | |||
| <Grid container justifyContent="flex-start" alignItems="flex-start"> | |||
| @@ -504,8 +517,10 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| rows={qcResult} | |||
| // rows={qcResult && qcResult.length > 0 ? qcResult : qcItems} | |||
| // rows={disabled? qcResult:qcItems} | |||
| autoHeight | |||
| // autoHeight | |||
| sortModel={[]} | |||
| // getRowHeight={getRowHeight} | |||
| getRowHeight={() => 'auto'} | |||
| getRowId={getRowId} | |||
| /> | |||
| </Grid> | |||
| @@ -548,17 +563,13 @@ const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||
| sortModel={[]} | |||
| /> | |||
| </CollapsibleCard> | |||
| {/* <StyledDataGrid | |||
| rows={escalationHistory} | |||
| columns={columns} | |||
| onRowSelectionModelChange={(newRowSelectionModel) => { | |||
| setRowSelectionModel(newRowSelectionModel); | |||
| }} | |||
| /> */} | |||
| </Grid> | |||
| </> | |||
| )} | |||
| <Grid item xs={12}> | |||
| <Typography variant="h6" display="block" marginBlockEnd={1}> | |||
| {t("Qc Decision")} | |||
| </Typography> | |||
| <FormControl> | |||
| <Controller | |||
| name="qcDecision" | |||
| @@ -6,10 +6,14 @@ import { | |||
| Autocomplete, | |||
| Box, | |||
| Button, | |||
| Divider, | |||
| Grid, | |||
| Modal, | |||
| ModalProps, | |||
| Stack, | |||
| Tab, | |||
| Tabs, | |||
| TabsProps, | |||
| TextField, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| @@ -34,6 +38,7 @@ import { GridRowModesModel } from "@mui/x-data-grid"; | |||
| import { isEmpty } from "lodash"; | |||
| import { EscalationCombo } from "@/app/api/user"; | |||
| import { truncateSync } from "fs"; | |||
| import PutAwayGrid from "./PutAwayGrid"; | |||
| const style = { | |||
| @@ -47,7 +52,7 @@ const style = { | |||
| pb: 10, | |||
| display: "block", | |||
| width: { xs: "90%", sm: "90%", md: "90%" }, | |||
| // height: { xs: "60%", sm: "60%", md: "60%" }, | |||
| height: { xs: "90%", sm: "90%", md: "90%" }, | |||
| }; | |||
| interface CommonProps extends Omit<ModalProps, "children"> { | |||
| // setRows: Dispatch<SetStateAction<PurchaseOrderLine[]>>; | |||
| @@ -95,6 +100,14 @@ const PoQcStockInModalVer2: React.FC<Props> = ({ | |||
| // Select Printer | |||
| const [selectedPrinter, setSelectedPrinter] = useState(printerCombo[0]); | |||
| const [tabIndex, setTabIndex] = useState(0); | |||
| const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||
| (_e, newValue) => { | |||
| setTabIndex(newValue); | |||
| }, | |||
| [], | |||
| ); | |||
| const defaultNewValue = useMemo(() => { | |||
| return ( | |||
| @@ -150,6 +163,8 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| setViewOnly(isViewOnly) | |||
| } | |||
| console.log("Modal ItemDetail updated:", itemDetail); | |||
| console.log("%c SHOW PUTAWAY? ", "color:lime", showPutaway); | |||
| if (showPutaway) { setTabIndex(1); } else { setTabIndex(0); } | |||
| }, [itemDetail]); | |||
| useEffect(() => { | |||
| @@ -158,8 +173,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| }) | |||
| setQcItems(dummyQCData); | |||
| setOpenPutaway(isPutaway); | |||
| // setOpenPutaway(isPutaway); | |||
| }, [open]) | |||
| const [openPutaway, setOpenPutaway] = useState(false); | |||
| @@ -322,7 +336,9 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| if (qcData.qcAccept) { | |||
| // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", | |||
| // confirmButtonText: t("confirm putaway"), html: ""}); | |||
| onOpenPutaway(); | |||
| // onOpenPutaway(); | |||
| closeHandler({}, "backdropClick"); | |||
| // setTabIndex(1); // Need to go Putaway tab? | |||
| } else { | |||
| closeHandler({}, "backdropClick"); | |||
| } | |||
| @@ -463,6 +479,11 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| const acceptQty = formProps.watch("acceptedQty") | |||
| const showPutaway = useMemo(() => { | |||
| const status = itemDetail.status; | |||
| return status !== "pending" && status !== "escalated" && status !== "rejected"; | |||
| }, [itemDetail]); | |||
| const checkQcIsPassed = useCallback((qcItems: PurchaseQcResult[]) => { | |||
| const isPassed = qcItems.every((qc) => qc.qcPassed); | |||
| console.log(isPassed) | |||
| @@ -492,88 +513,36 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| overflowY: "auto", | |||
| marginLeft: 3, | |||
| marginRight: 3, | |||
| // overflow: "hidden", | |||
| }} | |||
| > | |||
| {openPutaway ? ( | |||
| <Box | |||
| component="form" | |||
| onSubmit={formProps.handleSubmit(onSubmitPutaway)} | |||
| <Box sx={{ position: 'sticky', top: 0, bgcolor: 'background.paper', | |||
| zIndex: 5, borderBottom: 2, borderColor: 'divider', width: "100%" }}> | |||
| <Tabs | |||
| value={tabIndex} | |||
| onChange={handleTabChange} | |||
| variant="scrollable" | |||
| > | |||
| <PutAwayForm | |||
| itemDetail={itemDetail} | |||
| warehouse={warehouse!} | |||
| disabled={viewOnly} | |||
| setRowModesModel={setPafRowModesModel} | |||
| setRowSelectionModel={setPafRowSelectionModel} | |||
| /> | |||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| <Autocomplete | |||
| disableClearable | |||
| options={printerCombo} | |||
| defaultValue={selectedPrinter} | |||
| onChange={(event, value) => { | |||
| setSelectedPrinter(value) | |||
| }} | |||
| renderInput={(params) => ( | |||
| <TextField | |||
| {...params} | |||
| variant="outlined" | |||
| label={t("Printer")} | |||
| sx={{ width: 300}} | |||
| /> | |||
| )} | |||
| /> | |||
| <Button | |||
| id="printButton" | |||
| type="button" | |||
| variant="contained" | |||
| color="primary" | |||
| sx={{ mt: 1 }} | |||
| onClick={handlePrint} | |||
| disabled={isPrinting || printerCombo.length <= 0 || pafSubmitDisable} | |||
| > | |||
| {isPrinting ? t("Printing") : t("print")} | |||
| </Button> | |||
| <Button | |||
| id="putawaySubmit" | |||
| type="submit" | |||
| variant="contained" | |||
| color="primary" | |||
| sx={{ mt: 1 }} | |||
| onClick={formProps.handleSubmit(onSubmitPutaway)} | |||
| disabled={pafSubmitDisable} | |||
| > | |||
| {t("confirm putaway")} | |||
| </Button> | |||
| </Stack> | |||
| </Box> | |||
| ) : ( | |||
| <> | |||
| <Grid | |||
| container | |||
| justifyContent="flex-start" | |||
| alignItems="flex-start" | |||
| > | |||
| <Grid item xs={12}> | |||
| <Typography variant="h6" display="block" marginBlockEnd={1}> | |||
| {t("qc processing")} | |||
| </Typography> | |||
| </Grid> | |||
| <Grid item xs={12}> | |||
| <StockInForm itemDetail={itemDetail} disabled={viewOnly} /> | |||
| </Grid> | |||
| <Tab label={ | |||
| showPutaway ? t("dn and qc info") : t("qc processing") | |||
| } iconPosition="end" /> | |||
| {showPutaway && <Tab label={t("putaway processing")} iconPosition="end" />} | |||
| </Tabs> | |||
| </Box> | |||
| <Grid | |||
| container | |||
| justifyContent="flex-start" | |||
| alignItems="flex-start" | |||
| > | |||
| <Grid item xs={12}> | |||
| {tabIndex === 0 && <> | |||
| <Grid item xs={12}> | |||
| <Typography variant="h6" display="block" marginBlockEnd={1}> | |||
| {t("Delivery Detail")} | |||
| </Typography> | |||
| </Grid> | |||
| {/* <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| <Button | |||
| id="stockInSubmit" | |||
| type="button" | |||
| variant="contained" | |||
| color="primary" | |||
| onClick={formProps.handleSubmit(onSubmitStockIn)} | |||
| > | |||
| {t("submitStockIn")} | |||
| </Button> | |||
| </Stack> */} | |||
| <StockInForm itemDetail={itemDetail} disabled={viewOnly || showPutaway} /> | |||
| <Grid | |||
| container | |||
| justifyContent="flex-start" | |||
| @@ -582,13 +551,13 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| <QcComponent | |||
| // qc={qc!} | |||
| itemDetail={itemDetail} | |||
| disabled={viewOnly} | |||
| disabled={viewOnly || showPutaway} | |||
| // qcItems={qcItems} | |||
| // setQcItems={setQcItems} | |||
| /> | |||
| </Grid> | |||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| {!viewOnly && (<Button | |||
| {(!viewOnly && !showPutaway) && (<Button | |||
| id="qcSubmit" | |||
| type="button" | |||
| variant="contained" | |||
| @@ -599,8 +568,75 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
| {t("confirm qc result")} | |||
| </Button>)} | |||
| </Stack> | |||
| </> | |||
| )} | |||
| </>} | |||
| {tabIndex === 1 && | |||
| <Box | |||
| // component="form" | |||
| // onSubmit={formProps.handleSubmit(onSubmitPutaway)} | |||
| > | |||
| <Grid | |||
| container | |||
| justifyContent="flex-start" | |||
| alignItems="flex-start" | |||
| > | |||
| <PutAwayForm | |||
| itemDetail={itemDetail} | |||
| warehouse={warehouse!} | |||
| disabled={viewOnly} | |||
| setRowModesModel={setPafRowModesModel} | |||
| setRowSelectionModel={setPafRowSelectionModel} | |||
| /> | |||
| {/* <PutAwayGrid | |||
| itemDetail={itemDetail} | |||
| warehouse={warehouse!} | |||
| disabled={viewOnly} | |||
| /> */} | |||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| <Autocomplete | |||
| disableClearable | |||
| options={printerCombo} | |||
| defaultValue={selectedPrinter} | |||
| onChange={(event, value) => { | |||
| setSelectedPrinter(value) | |||
| }} | |||
| renderInput={(params) => ( | |||
| <TextField | |||
| {...params} | |||
| variant="outlined" | |||
| label={t("Printer")} | |||
| sx={{ width: 300}} | |||
| /> | |||
| )} | |||
| /> | |||
| <Button | |||
| id="printButton" | |||
| type="button" | |||
| variant="contained" | |||
| color="primary" | |||
| sx={{ mt: 1 }} | |||
| onClick={handlePrint} | |||
| disabled={isPrinting || printerCombo.length <= 0 || pafSubmitDisable} | |||
| > | |||
| {isPrinting ? t("Printing") : t("print")} | |||
| </Button> | |||
| {/* <Button | |||
| id="putawaySubmit" | |||
| type="submit" | |||
| variant="contained" | |||
| color="primary" | |||
| sx={{ mt: 1 }} | |||
| onClick={formProps.handleSubmit(onSubmitPutaway)} | |||
| disabled={pafSubmitDisable} | |||
| > | |||
| {t("confirm putaway")} | |||
| </Button> */} | |||
| </Stack> | |||
| </Grid> | |||
| </Box> | |||
| } | |||
| </Grid> | |||
| </Grid> | |||
| </Box> | |||
| </Modal> | |||
| </FormProvider> | |||
| @@ -54,5 +54,6 @@ | |||
| "escalated datetime": "上報時間", | |||
| "escalateFrom": "上報同事", | |||
| "No": "無", | |||
| "Responsible Escalation List": "負責的上報列表" | |||
| "Responsible Escalation List": "負責的上報列表", | |||
| "show completed logs": "顯示已完成上報" | |||
| } | |||
| @@ -100,6 +100,7 @@ | |||
| "Default Warehouse": "預設倉庫", | |||
| "Select warehouse": "選擇倉庫", | |||
| "Putaway Detail": "上架詳情", | |||
| "Delivery Detail": "來貨詳情", | |||
| "LotNo": "批號", | |||
| "Po Code": "採購訂單編號", | |||
| "No Warehouse": "沒有倉庫", | |||
| @@ -109,7 +110,8 @@ | |||
| "Accept submit": "接受來貨", | |||
| "qc processing": "處理來貨及品檢", | |||
| "putaway processing": "處理來貨及上架", | |||
| "view stockin": "查看收貨及品檢", | |||
| "view stockin": "查看收貨詳情", | |||
| "view putaway": "查看上架詳情", | |||
| "putawayBtn": "上架", | |||
| "dnNo": "送貨單編號", | |||
| "dnDate": "送貨單日期", | |||
| @@ -144,5 +146,7 @@ | |||
| "No Option": "沒有選項", | |||
| "receivedTotal": "已來貨總數", | |||
| "QC Record": "品檢記錄", | |||
| "value must be integer": "請輸入整數" | |||
| "value must be integer": "請輸入整數", | |||
| "dn and qc info": "來貨及品檢詳情", | |||
| "Qc Decision": "品檢詳情" | |||
| } | |||