| @@ -49,7 +49,10 @@ export const arrayToDayjs = (arr: ConfigType | (number | undefined)[], showTime: | |||||
| tempArr = `${arr[0]?.toString().padStart(4, "0")}-${arr[1]?.toString().padStart(2, "0")}-${arr[2]?.toString().padStart(2, "0")}`; | tempArr = `${arr[0]?.toString().padStart(4, "0")}-${arr[1]?.toString().padStart(2, "0")}-${arr[2]?.toString().padStart(2, "0")}`; | ||||
| if (showTime) { | if (showTime) { | ||||
| // [year, month, day, hour, minute, second] | // [year, month, day, hour, minute, second] | ||||
| tempArr += ` ${arr[3]?.toString().padStart(2, "0")}:${arr[4]?.toString().padStart(2, "0")}:${arr[5]?.toString().padStart(2, "0")}`; | |||||
| tempArr += ` ${ | |||||
| arr[3]?.toString().padStart(2, "0")}:${ | |||||
| arr[4]?.toString().padStart(2, "0")}:${ | |||||
| (arr[5] ?? 0)?.toString().padStart(2, "0")}`; | |||||
| } | } | ||||
| } | } | ||||
| @@ -39,6 +39,7 @@ import { GridEditInputCell } from "@mui/x-data-grid"; | |||||
| import { StockInLine } from "@/app/api/po"; | import { StockInLine } from "@/app/api/po"; | ||||
| import { WarehouseResult } from "@/app/api/warehouse"; | import { WarehouseResult } from "@/app/api/warehouse"; | ||||
| import { | import { | ||||
| arrayToDateTimeString, | |||||
| OUTPUT_DATE_FORMAT, | OUTPUT_DATE_FORMAT, | ||||
| stockInLineStatusMap, | stockInLineStatusMap, | ||||
| } from "@/app/utils/formatUtil"; | } from "@/app/utils/formatUtil"; | ||||
| @@ -231,19 +232,33 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||||
| return `${params.api.getRowIndexRelativeToVisibleRows(params.id) + 1}.` | return `${params.api.getRowIndexRelativeToVisibleRows(params.id) + 1}.` | ||||
| }, | }, | ||||
| }, | }, | ||||
| { | |||||
| field: "putawayDate", | |||||
| headerName: t("putawayDatetime"), | |||||
| flex: 1, | |||||
| editable: false, | |||||
| renderCell(params) { | |||||
| return `${(arrayToDateTimeString(params.value))}`; | |||||
| }, | |||||
| }, | |||||
| { | |||||
| field: "putawayUser", | |||||
| headerName: t("putawayUser"), | |||||
| flex: 1, | |||||
| editable: false, | |||||
| }, | |||||
| { | { | ||||
| field: "qty", | field: "qty", | ||||
| headerName: t("qty"), | |||||
| headerName: t("putawayQty"), | |||||
| flex: 0.5, | flex: 0.5, | ||||
| editable: false, | editable: false, | ||||
| // renderCell(params) { | |||||
| // return <>100</> | |||||
| // }, | |||||
| headerAlign: "right", | |||||
| align: "right", | |||||
| }, | }, | ||||
| { | { | ||||
| field: "warehouse", | field: "warehouse", | ||||
| headerName: t("warehouse"), | headerName: t("warehouse"), | ||||
| flex: 1, | |||||
| flex: 2, | |||||
| editable: false, | editable: false, | ||||
| renderEditCell: (params) => { | renderEditCell: (params) => { | ||||
| const index = params.api.getRowIndexRelativeToVisibleRows(params.row.id) | const index = params.api.getRowIndexRelativeToVisibleRows(params.row.id) | ||||
| @@ -275,6 +290,7 @@ const PutAwayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled, setRowM | |||||
| // return <>{filteredWarehouse[0].name}</> | // return <>{filteredWarehouse[0].name}</> | ||||
| // }, | // }, | ||||
| }, | }, | ||||
| // { | // { | ||||
| // field: "printQty", | // field: "printQty", | ||||
| // headerName: t("printQty"), | // headerName: t("printQty"), | ||||
| @@ -163,7 +163,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
| setViewOnly(isViewOnly) | setViewOnly(isViewOnly) | ||||
| } | } | ||||
| console.log("Modal ItemDetail updated:", itemDetail); | console.log("Modal ItemDetail updated:", itemDetail); | ||||
| console.log("%c SHOW PUTAWAY? ", "color:lime", showPutaway); | |||||
| if (showPutaway) { setTabIndex(1); } else { setTabIndex(0); } | if (showPutaway) { setTabIndex(1); } else { setTabIndex(0); } | ||||
| }, [itemDetail]); | }, [itemDetail]); | ||||
| @@ -48,7 +48,7 @@ const PoSearch: React.FC<Props> = ({ | |||||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { | const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { | ||||
| const searchCriteria: Criterion<SearchParamNames>[] = [ | const searchCriteria: Criterion<SearchParamNames>[] = [ | ||||
| { label: t("Supplier"), paramName: "supplier", type: "text" }, | { label: t("Supplier"), paramName: "supplier", type: "text" }, | ||||
| { label: t("Po No."), paramName: "code", type: "text" }, | |||||
| { label: t("PO No."), paramName: "code", type: "text" }, | |||||
| { | { | ||||
| label: t("Escalated"), | label: t("Escalated"), | ||||
| paramName: "escalated", | paramName: "escalated", | ||||
| @@ -141,7 +141,7 @@ const PoSearch: React.FC<Props> = ({ | |||||
| }, | }, | ||||
| { | { | ||||
| name: "code", | name: "code", | ||||
| label: `${t("Po No.")} &\n${t("Supplier")}`, | |||||
| label: `${t("PO No.")} &\n${t("Supplier")}`, | |||||
| renderCell: (params) => { | renderCell: (params) => { | ||||
| return <>{params.code}<br/>{params.supplier}</> | return <>{params.code}<br/>{params.supplier}</> | ||||
| }, | }, | ||||
| @@ -35,6 +35,7 @@ import StockInForm from "../PoDetail/StockInForm"; | |||||
| import { arrayToDateString, INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | import { arrayToDateString, INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | ||||
| import { QrCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | import { QrCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | ||||
| import { msg } from "../Swal/CustomAlerts"; | import { msg } from "../Swal/CustomAlerts"; | ||||
| import { PutAwayRecord } from "."; | |||||
| interface Props extends Omit<ModalProps, "children"> { | interface Props extends Omit<ModalProps, "children"> { | ||||
| @@ -42,6 +43,7 @@ interface Props extends Omit<ModalProps, "children"> { | |||||
| stockInLineId: number; | stockInLineId: number; | ||||
| warehouseId: number; | warehouseId: number; | ||||
| scanner: QrCodeScanner; | scanner: QrCodeScanner; | ||||
| addPutAwayHistory: (putAwayData: PutAwayRecord) => void; | |||||
| } | } | ||||
| const style = { | const style = { | ||||
| position: "absolute", | position: "absolute", | ||||
| @@ -69,7 +71,7 @@ const scannerStyle = { | |||||
| width: { xs: "60%", sm: "60%", md: "60%" }, | width: { xs: "60%", sm: "60%", md: "60%" }, | ||||
| }; | }; | ||||
| const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId, warehouseId, scanner }) => { | |||||
| const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId, warehouseId, scanner, addPutAwayHistory }) => { | |||||
| const { t } = useTranslation("putAway"); | const { t } = useTranslation("putAway"); | ||||
| const [serverError, setServerError] = useState(""); | const [serverError, setServerError] = useState(""); | ||||
| const params = useSearchParams(); | const params = useSearchParams(); | ||||
| @@ -77,7 +79,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| const [isOpenScanner, setIsOpenScanner] = useState<boolean>(false); | const [isOpenScanner, setIsOpenScanner] = useState<boolean>(false); | ||||
| const [itemDetail, setItemDetail] = useState<StockInLine>(); | const [itemDetail, setItemDetail] = useState<StockInLine>(); | ||||
| const [putAwayQty, setPutAwayQty] = useState<number>(0); | |||||
| const [totalPutAwayQty, setTotalPutAwayQty] = useState<number>(0); | |||||
| const [unavailableText, setUnavailableText] = useState<string | undefined>( | const [unavailableText, setUnavailableText] = useState<string | undefined>( | ||||
| undefined, | undefined, | ||||
| ); | ); | ||||
| @@ -124,7 +126,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| (...args) => { | (...args) => { | ||||
| setVerified(false); | setVerified(false); | ||||
| setItemDetail(undefined); | setItemDetail(undefined); | ||||
| setPutAwayQty(0); | |||||
| setTotalPutAwayQty(0); | |||||
| onClose?.(...args); | onClose?.(...args); | ||||
| // reset(); | // reset(); | ||||
| }, | }, | ||||
| @@ -177,7 +179,8 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| formProps.reset({ | formProps.reset({ | ||||
| ...defaultNewValue | ...defaultNewValue | ||||
| }) | }) | ||||
| setPutQty(itemDetail?.demandQty); | |||||
| const total = itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0; | |||||
| setPutQty(itemDetail?.demandQty - total); | |||||
| console.log("%c Loaded data:", "color:lime", defaultNewValue); | console.log("%c Loaded data:", "color:lime", defaultNewValue); | ||||
| } else { | } else { | ||||
| switch (itemDetail.status) { | switch (itemDetail.status) { | ||||
| @@ -201,8 +204,8 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| const res = await fetchStockInLineInfo(stockInLineId); | const res = await fetchStockInLineInfo(stockInLineId); | ||||
| console.log("%c Fetched Stock In Line Info:", "color:gold", res); | console.log("%c Fetched Stock In Line Info:", "color:gold", res); | ||||
| const totalPutAwayQty = res.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0; | |||||
| setPutAwayQty(totalPutAwayQty); | |||||
| const total = res.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0; | |||||
| setTotalPutAwayQty(total); | |||||
| setItemDetail(res); | setItemDetail(res); | ||||
| } catch (e) { | } catch (e) { | ||||
| console.log("%c Error when fetching Stock In Line: ", "color:red", e); | console.log("%c Error when fetching Stock In Line: ", "color:red", e); | ||||
| @@ -224,9 +227,9 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| if (!Number.isInteger(qty)) { | if (!Number.isInteger(qty)) { | ||||
| setQtyError(t("value must be integer")); | setQtyError(t("value must be integer")); | ||||
| } | } | ||||
| if (qty > itemDetail?.acceptedQty!! - putAwayQty) { | |||||
| if (qty > itemDetail?.demandQty!! - totalPutAwayQty) { | |||||
| setQtyError(`${t("putQty must not greater than")} ${ | setQtyError(`${t("putQty must not greater than")} ${ | ||||
| itemDetail?.acceptedQty!! - putAwayQty}` ); | |||||
| itemDetail?.demandQty!! - totalPutAwayQty}` ); | |||||
| } else | } else | ||||
| // if (qty > itemDetail?.acceptedQty!!) { | // if (qty > itemDetail?.acceptedQty!!) { | ||||
| // setQtyError(`${t("putQty must not greater than")} ${ | // setQtyError(`${t("putQty must not greater than")} ${ | ||||
| @@ -290,11 +293,24 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| // update entries | // update entries | ||||
| console.log("%c Update Success:", "color:green", res); | console.log("%c Update Success:", "color:green", res); | ||||
| // add loading | // add loading | ||||
| const putAwayData = { | |||||
| itemName: itemDetail?.itemName, | |||||
| itemCode: itemDetail?.itemNo, | |||||
| poCode: itemDetail?.poCode, | |||||
| lotNo: itemDetail?.lotNo, | |||||
| warehouse: warehouse.find((w) => w.id == warehouseId)?.name, | |||||
| putQty: putQty, | |||||
| uom: itemDetail?.uom?.udfudesc, | |||||
| } as PutAwayRecord; | |||||
| addPutAwayHistory(putAwayData); | |||||
| msg("貨品上架成功!"); | msg("貨品上架成功!"); | ||||
| closeHandler({}, "backdropClick"); | closeHandler({}, "backdropClick"); | ||||
| } | } | ||||
| console.log(res); | |||||
| // console.log(res); | |||||
| // if (res) | // if (res) | ||||
| } catch (e) { | } catch (e) { | ||||
| // server error | // server error | ||||
| @@ -393,7 +409,7 @@ const PutAwayModal: React.FC<Props> = ({ open, onClose, warehouse, stockInLineId | |||||
| lineHeight: "1.2", | lineHeight: "1.2", | ||||
| }, | }, | ||||
| }} | }} | ||||
| defaultValue={itemDetail?.acceptedQty!! - putAwayQty} | |||||
| defaultValue={itemDetail?.demandQty!! - totalPutAwayQty} | |||||
| // defaultValue={itemDetail.demandQty} | // defaultValue={itemDetail.demandQty} | ||||
| onChange={(e) => { | onChange={(e) => { | ||||
| const value = e.target.value; | const value = e.target.value; | ||||
| @@ -0,0 +1,93 @@ | |||||
| "use client"; | |||||
| import { | |||||
| Paper, | |||||
| } from "@mui/material"; | |||||
| import { useEffect, useMemo } from "react"; | |||||
| import StyledDataGrid from "../StyledDataGrid"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { GridColDef } from "@mui/x-data-grid"; | |||||
| import { PutAwayRecord } from "."; | |||||
| type Props = { | |||||
| putAwayHistory : PutAwayRecord[]; | |||||
| }; | |||||
| const PutAwayReviewGrid: React.FC<Props> = ({ putAwayHistory }) => { | |||||
| const { t } = useTranslation("putAway"); | |||||
| const columns: GridColDef[] = useMemo(() => [ | |||||
| { | |||||
| field: "index", | |||||
| headerName: t(""), | |||||
| flex: 0.5, | |||||
| renderCell: (params) => { | |||||
| return (<b>{params.id}.</b>); | |||||
| }, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "poCode", | |||||
| headerName: t("poCode"), | |||||
| flex: 2, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "itemCode", | |||||
| headerName: t("itemCode"), | |||||
| flex: 1, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "itemName", | |||||
| headerName: t("itemName"), | |||||
| flex: 2, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "putQty", | |||||
| headerName: t("putawayQty"), | |||||
| flex: 1, | |||||
| headerAlign: 'right', | |||||
| align: 'right', | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "uom", | |||||
| headerName: t("uom"), | |||||
| flex: 1.5, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| { | |||||
| field: "warehouse", | |||||
| headerName: t("warehouse"), | |||||
| flex: 2, | |||||
| disableColumnMenu: true, | |||||
| }, | |||||
| ], [] | |||||
| ) | |||||
| return (<> | |||||
| <Paper> | |||||
| <StyledDataGrid | |||||
| columns={columns} | |||||
| rows={putAwayHistory} | |||||
| autoHeight | |||||
| sx={{ | |||||
| '& .MuiDataGrid-columnHeaderTitle': { | |||||
| whiteSpace: 'nowrap', | |||||
| overflow: 'visible', | |||||
| textOverflow: 'clip', | |||||
| lineHeight: 'normal', | |||||
| paddingRight: '0px', | |||||
| }, | |||||
| '& .MuiDataGrid-columnHeader': { | |||||
| padding: '0 4px 0 4px', | |||||
| }, | |||||
| }} | |||||
| /> | |||||
| </Paper> | |||||
| </>) | |||||
| } | |||||
| export default PutAwayReviewGrid; | |||||
| @@ -29,6 +29,8 @@ import { | |||||
| import { useSearchParams } from "next/navigation"; | import { useSearchParams } from "next/navigation"; | ||||
| import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | ||||
| import PutAwayModal from "./PutAwayModal"; | import PutAwayModal from "./PutAwayModal"; | ||||
| import { PutAwayRecord } from "."; | |||||
| import PutAwayReviewGrid from "./PutAwayReviewGrid"; | |||||
| type Props = { | type Props = { | ||||
| warehouse : WarehouseResult[]; | warehouse : WarehouseResult[]; | ||||
| @@ -43,6 +45,7 @@ const PutAwayScan: React.FC<Props> = ({ warehouse }) => { | |||||
| const [openPutAwayModal, setOpenPutAwayModal] = useState(false); | const [openPutAwayModal, setOpenPutAwayModal] = useState(false); | ||||
| const [scannedSilId, setScannedSilId] = useState<number>(0); // TODO use QR code info | const [scannedSilId, setScannedSilId] = useState<number>(0); // TODO use QR code info | ||||
| const [scannedWareHouseId, setScannedWareHouseId] = useState<number>(0); // TODO use QR code info | const [scannedWareHouseId, setScannedWareHouseId] = useState<number>(0); // TODO use QR code info | ||||
| const [putAwayHistory, setPutAwayHistory] = useState<PutAwayRecord[]>([]); | |||||
| // QR Code Scanner | // QR Code Scanner | ||||
| const scanner = useQrCodeScannerContext(); | const scanner = useQrCodeScannerContext(); | ||||
| @@ -115,6 +118,12 @@ const PutAwayScan: React.FC<Props> = ({ warehouse }) => { | |||||
| }; | }; | ||||
| } | } | ||||
| const addPutAwayHistory = (putAwayData: PutAwayRecord) => { | |||||
| console.log("%c Added new data to Putaway history: ", "color:orange", putAwayData); | |||||
| const newPutaway = { ...putAwayData, id: putAwayHistory.length + 1 }; | |||||
| setPutAwayHistory([...putAwayHistory, newPutaway]); // Create a new array with the new row | |||||
| // putAwayHistory.push(putAwayData); | |||||
| }; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (scannedSilId > 0) { | if (scannedSilId > 0) { | ||||
| @@ -170,29 +179,38 @@ const PutAwayScan: React.FC<Props> = ({ warehouse }) => { | |||||
| } | } | ||||
| }, [scanner.values]); | }, [scanner.values]); | ||||
| return (<> | |||||
| <Paper sx={{ | |||||
| display: 'flex', | |||||
| flexDirection: 'column', | |||||
| justifyContent: 'center', | |||||
| alignItems: 'center', | |||||
| textAlign: 'center',}} | |||||
| > | |||||
| <Typography variant="h4"> | |||||
| {scanDisplay == "pending" ? t("Pending scan") : t("Rescan")} | |||||
| </Typography> | |||||
| <QrCodeScanner sx={{padding: "10px", fontSize : "150px"}}/> | |||||
| </Paper> | |||||
| <PutAwayModal | |||||
| open={openPutAwayModal} | |||||
| onClose={closeModal} | |||||
| warehouse={warehouse} | |||||
| stockInLineId={scannedSilId} | |||||
| warehouseId={scannedWareHouseId} | |||||
| scanner={scanner} | |||||
| return (<> | |||||
| <Paper sx={{ | |||||
| display: 'flex', | |||||
| flexDirection: 'column', | |||||
| justifyContent: 'center', | |||||
| alignItems: 'center', | |||||
| textAlign: 'center',}} | |||||
| > | |||||
| <Typography variant="h4"> | |||||
| {scanDisplay == "pending" ? t("Pending scan") : t("Rescan")} | |||||
| </Typography> | |||||
| <QrCodeScanner sx={{padding: "10px", fontSize : "150px"}}/> | |||||
| </Paper> | |||||
| {putAwayHistory.length > 0 && (<> | |||||
| <Typography variant="h5"> | |||||
| {t("putAwayHistory")} | |||||
| </Typography> | |||||
| <PutAwayReviewGrid | |||||
| putAwayHistory={putAwayHistory} | |||||
| /> | /> | ||||
| </>) | |||||
| </>)} | |||||
| <PutAwayModal | |||||
| open={openPutAwayModal} | |||||
| onClose={closeModal} | |||||
| warehouse={warehouse} | |||||
| stockInLineId={scannedSilId} | |||||
| warehouseId={scannedWareHouseId} | |||||
| scanner={scanner} | |||||
| addPutAwayHistory={addPutAwayHistory} | |||||
| /> | |||||
| </>) | |||||
| } | } | ||||
| export default PutAwayScan; | export default PutAwayScan; | ||||
| @@ -1 +1,12 @@ | |||||
| export { default } from "./PutAwayScanWrapper" | |||||
| export { default } from "./PutAwayScanWrapper" | |||||
| export interface PutAwayRecord { | |||||
| id: number; | |||||
| itemName: string; | |||||
| itemCode?: string; | |||||
| warehouse: string; | |||||
| putQty: number; | |||||
| lotNo?: string; | |||||
| poCode?: string; | |||||
| uom?: string; | |||||
| }; | |||||
| @@ -25,7 +25,6 @@ | |||||
| "Complete PO": "完成採購訂單", | "Complete PO": "完成採購訂單", | ||||
| "General": "一般", | "General": "一般", | ||||
| "Bind Storage": "綁定倉位", | "Bind Storage": "綁定倉位", | ||||
| "Po No.": "採購訂單編號", | |||||
| "PO No.": "採購訂單編號", | "PO No.": "採購訂單編號", | ||||
| "itemNo": "貨品編號", | "itemNo": "貨品編號", | ||||
| "itemName": "貨品名稱", | "itemName": "貨品名稱", | ||||
| @@ -149,5 +148,7 @@ | |||||
| "value must be integer": "請輸入整數", | "value must be integer": "請輸入整數", | ||||
| "dn and qc info": "來貨及品檢詳情", | "dn and qc info": "來貨及品檢詳情", | ||||
| "Qc Decision": "品檢詳情", | "Qc Decision": "品檢詳情", | ||||
| "Print Qty": "列印數量" | |||||
| "Print Qty": "列印數量", | |||||
| "putawayDatetime": "上架時間", | |||||
| "putawayUser": "上架同事" | |||||
| } | } | ||||
| @@ -9,9 +9,16 @@ | |||||
| "Please scan warehouse qr code": "請掃瞄倉庫二維碼", | "Please scan warehouse qr code": "請掃瞄倉庫二維碼", | ||||
| "scan loading": "載入中,請稍候…", | "scan loading": "載入中,請稍候…", | ||||
| "warehouse": "倉庫", | "warehouse": "倉庫", | ||||
| "putawayQty": "上架數量", | |||||
| "putQty": "是次上架數量", | "putQty": "是次上架數量", | ||||
| "minimal value is 1": "最小為1", | "minimal value is 1": "最小為1", | ||||
| "putQty must not greater than": "上架數量不得大於", | "putQty must not greater than": "上架數量不得大於", | ||||
| "value must be integer": "必須是整數", | "value must be integer": "必須是整數", | ||||
| "value must be a number": "必須是數字" | |||||
| "value must be a number": "必須是數字", | |||||
| "putAwayHistory": "是次上架記錄", | |||||
| "itemName": "貨品名稱", | |||||
| "lotNo": "貨品批號", | |||||
| "poCode": "採購訂單編號", | |||||
| "itemCode": "貨品編號", | |||||
| "uom": "單位" | |||||
| } | } | ||||