| @@ -11,7 +11,7 @@ import { Suspense } from "react"; | |||
| type Props = {} & SearchParams; | |||
| const PoEdit: React.FC<Props> = async ({ searchParams }) => { | |||
| const type = "po"; | |||
| const type = "purchaseOrder"; | |||
| const { t } = await getServerI18n(type); | |||
| console.log(searchParams["id"]); | |||
| const id = isString(searchParams["id"]) | |||
| @@ -1,7 +1,7 @@ | |||
| import { preloadClaims } from "@/app/api/claims"; | |||
| import ClaimSearch from "@/components/ClaimSearch"; | |||
| import PoSearch from "@/components/PoSearch"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import { getServerI18n, I18nProvider } from "@/i18n"; | |||
| import Add from "@mui/icons-material/Add"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| @@ -20,6 +20,7 @@ const PurchaseOrder: React.FC = async () => { | |||
| return ( | |||
| <> | |||
| <I18nProvider namespaces={["purchaseOrder", "common"]}> | |||
| <Stack | |||
| direction="row" | |||
| justifyContent="space-between" | |||
| @@ -38,6 +39,7 @@ const PurchaseOrder: React.FC = async () => { | |||
| <Suspense fallback={<PoSearch.Loading />}> | |||
| <PoSearch /> | |||
| </Suspense> | |||
| </I18nProvider> | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -49,7 +49,7 @@ const EscalationForm: React.FC<Props> = ({ | |||
| itemDetail, | |||
| disabled | |||
| }) => { | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const { | |||
| register, | |||
| @@ -91,14 +91,14 @@ type EntryError = | |||
| const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
| const cameras = useContext(CameraContext); | |||
| console.log(cameras); | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const [purchaseOrder, setPurchaseOrder] = useState({ ...po }); | |||
| const [rows, setRows] = useState<PurchaseOrderLine[]>( | |||
| purchaseOrder.pol || [] | |||
| ); | |||
| const params = useSearchParams(); | |||
| const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status); | |||
| // const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status); | |||
| const handleCompletePo = useCallback(async () => { | |||
| const checkRes = await checkPolAndCompletePo(purchaseOrder.id); | |||
| @@ -167,7 +167,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
| {/* <TableCell align="left">{weightUnit}</TableCell> */} | |||
| <TableCell align="left">{row.price}</TableCell> | |||
| {/* <TableCell align="left">{row.expiryDate}</TableCell> */} | |||
| <TableCell align="left">{currStatus}</TableCell> | |||
| <TableCell align="left">{t(`${currStatus.toLowerCase()}`)}</TableCell> | |||
| </TableRow> | |||
| <TableRow> | |||
| {/* <TableCell /> */} | |||
| @@ -351,7 +351,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
| <TableCell>{t("itemNo")}</TableCell> | |||
| <TableCell align="left">{t("itemName")}</TableCell> | |||
| <TableCell align="left">{t("qty")}</TableCell> | |||
| <TableCell align="left">processed</TableCell> | |||
| <TableCell align="left">{t("processed")}</TableCell> | |||
| <TableCell align="left">{t("uom")}</TableCell> | |||
| <TableCell align="left">{t("total weight")}</TableCell> | |||
| {/* <TableCell align="left">{t("weight unit")}</TableCell> */} | |||
| @@ -110,7 +110,7 @@ function PoInputGrid({ | |||
| warehouse, | |||
| }: Props) { | |||
| console.log(itemDetail); | |||
| const { t } = useTranslation("home"); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({}); | |||
| const getRowId = useCallback<GridRowIdGetter<StockInLineRow>>( | |||
| @@ -369,15 +369,17 @@ function PoInputGrid({ | |||
| () => [ | |||
| { | |||
| field: "itemNo", | |||
| headerName: t("itemNo"), | |||
| flex: 0.4, | |||
| }, | |||
| { | |||
| field: "itemName", | |||
| headerName: t("itemName"), | |||
| flex: 0.6, | |||
| }, | |||
| { | |||
| field: "acceptedQty", | |||
| headerName: "qty", | |||
| headerName: t("acceptedQty"), | |||
| flex: 0.5, | |||
| type: "number", | |||
| editable: true, | |||
| @@ -385,7 +387,7 @@ function PoInputGrid({ | |||
| }, | |||
| { | |||
| field: "uom", | |||
| headerName: "uom", | |||
| headerName: t("uom"), | |||
| flex: 0.5, | |||
| renderCell: (params) => { | |||
| return params.row.uom.code; | |||
| @@ -393,7 +395,7 @@ function PoInputGrid({ | |||
| }, | |||
| { | |||
| field: "weight", | |||
| headerName: "weight", | |||
| headerName: t("weight"), | |||
| flex: 0.5, | |||
| renderCell: (params) => { | |||
| const weight = calculateWeight( | |||
| @@ -406,13 +408,18 @@ function PoInputGrid({ | |||
| }, | |||
| { | |||
| field: "status", | |||
| headerName: t("status"), | |||
| flex: 0.5, | |||
| renderCell: (params) => { | |||
| return t(`${params.row.status}`) | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "actions", | |||
| type: "actions", | |||
| headerName: "start | qc | escalation | stock in | putaway | delete", | |||
| headerName: `${t("start")} | ${t("qc")} | ${t("escalation")} | ${t("stock in")} | ${t("putaway")} | ${t("delete")}`, | |||
| // headerName: "start | qc | escalation | stock in | putaway | delete", | |||
| flex: 1.5, | |||
| cellClassName: "actions", | |||
| getActions: (params) => { | |||
| @@ -578,7 +585,7 @@ function PoInputGrid({ | |||
| console.log(newRow); | |||
| console.log(currQty); | |||
| if (newRow.acceptedQty && newRow.acceptedQty > itemDetail.qty) { | |||
| error["acceptedQty"] = "qty cannot be greater than remaining qty"; | |||
| error["acceptedQty"] = t("qty cannot be greater than remaining qty"); | |||
| } | |||
| return Object.keys(error).length > 0 ? error : undefined; | |||
| }, | |||
| @@ -91,11 +91,13 @@ const style = { | |||
| top: "50%", | |||
| left: "50%", | |||
| transform: "translate(-50%, -50%)", | |||
| overflow: "scroll", | |||
| bgcolor: "background.paper", | |||
| pt: 5, | |||
| px: 5, | |||
| pb: 10, | |||
| width: { xs: "80%", sm: "80%", md: "80%" }, | |||
| display: "block", | |||
| width: { xs: "60%", sm: "60%", md: "60%" }, | |||
| }; | |||
| const PoQcStockInModal: React.FC<Props> = ({ | |||
| @@ -113,7 +115,7 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
| const { setIsUploading } = useUploadContext(); | |||
| const [serverError, setServerError] = useState(""); | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const params = useSearchParams(); | |||
| const [btnIsLoading, setBtnIsLoading] = useState(false); | |||
| @@ -371,10 +373,11 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
| // useEffect(() => { | |||
| // console.log(renderSubmitButton) | |||
| // }, [renderSubmitButton]) | |||
| return ( | |||
| <> | |||
| <FormProvider {...formProps}> | |||
| <Modal open={open} onClose={closeHandler}> | |||
| <Modal open={open} onClose={closeHandler} sx={{ overflow: "scroll" }}> | |||
| <Box | |||
| sx={style} | |||
| component="form" | |||
| @@ -387,14 +390,14 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||
| disabled={!renderSubmitButton} | |||
| /> | |||
| )} | |||
| {itemDetail !== undefined && type === "stockIn" && ( | |||
| <StockInForm | |||
| {itemDetail !== undefined && type === "escalation" && ( | |||
| <EscalationForm | |||
| itemDetail={itemDetail} | |||
| disabled={!renderSubmitButton} | |||
| /> | |||
| )} | |||
| {itemDetail !== undefined && type === "escalation" && ( | |||
| <EscalationForm | |||
| {itemDetail !== undefined && type === "stockIn" && ( | |||
| <StockInForm | |||
| itemDetail={itemDetail} | |||
| disabled={!renderSubmitButton} | |||
| /> | |||
| @@ -73,7 +73,7 @@ const style = { | |||
| }; | |||
| const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const { | |||
| register, | |||
| @@ -286,7 +286,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("item name")} | |||
| label={t("itemName")} | |||
| fullWidth | |||
| value={itemDetail.itemName} | |||
| disabled | |||
| @@ -294,7 +294,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("item no")} | |||
| label={t("itemNo")} | |||
| fullWidth | |||
| value={itemDetail.itemNo} | |||
| disabled | |||
| @@ -51,7 +51,7 @@ type EntryError = | |||
| type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>; | |||
| // fetchQcItemCheck | |||
| const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const { | |||
| register, | |||
| @@ -74,19 +74,19 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| console.log(accQty); | |||
| if (accQty > itemDetail.acceptedQty) { | |||
| setError("acceptedQty", { | |||
| message: `acceptedQty must not greater than ${itemDetail.acceptedQty}`, | |||
| message: `${t("acceptedQty must not greater than")} ${itemDetail.acceptedQty}`, | |||
| type: "required", | |||
| }); | |||
| } | |||
| if (accQty < 1) { | |||
| setError("acceptedQty", { | |||
| message: `minimal value is 1`, | |||
| message: t("minimal value is 1"), | |||
| type: "required", | |||
| }); | |||
| } | |||
| if (isNaN(accQty)) { | |||
| setError("acceptedQty", { | |||
| message: `value must be a number`, | |||
| message: t("value must be a number"), | |||
| type: "required", | |||
| }); | |||
| } | |||
| @@ -101,7 +101,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| () => [ | |||
| { | |||
| field: "qcItemId", | |||
| headerName: "qc Check", | |||
| headerName: t("qc Check"), | |||
| flex: 1, | |||
| editable: !disabled, | |||
| valueFormatter(params) { | |||
| @@ -139,7 +139,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| /> | |||
| ); | |||
| return errorMessage ? ( | |||
| <Tooltip title={t(errorMessage)}> | |||
| <Tooltip title={errorMessage}> | |||
| <Box width="100%">{content}</Box> | |||
| </Tooltip> | |||
| ) : ( | |||
| @@ -149,7 +149,7 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| }, | |||
| { | |||
| field: "failQty", | |||
| headerName: "failQty", | |||
| headerName: t("failQty"), | |||
| flex: 1, | |||
| editable: !disabled, | |||
| type: "number", | |||
| @@ -179,13 +179,13 @@ const QcForm: React.FC<Props> = ({ qc, itemDetail, disabled }) => { | |||
| const error: EntryError = {}; | |||
| const { qcItemId, failQty } = newRow; | |||
| if (!qcItemId || qcItemId <= 0) { | |||
| error["qcItemId"] = "select qc"; | |||
| error["qcItemId"] = t("select qc"); | |||
| } | |||
| if (!failQty || failQty <= 0) { | |||
| error["failQty"] = "enter a failQty"; | |||
| error["failQty"] = t("enter a failQty"); | |||
| } | |||
| if (failQty && failQty > itemDetail.acceptedQty) { | |||
| error["failQty"] = "qty too big"; | |||
| error["failQty"] = t("qty too big"); | |||
| } | |||
| return Object.keys(error).length > 0 ? error : undefined; | |||
| }, | |||
| @@ -49,7 +49,7 @@ const RejectForm: React.FC<Props> = ({ | |||
| itemDetail, | |||
| disabled | |||
| }) => { | |||
| const { t } = useTranslation(); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const { | |||
| register, | |||
| @@ -61,7 +61,7 @@ const StockInForm: React.FC<Props> = ({ | |||
| const { | |||
| t, | |||
| i18n: { language }, | |||
| } = useTranslation(); | |||
| } = useTranslation("purchaseOrder"); | |||
| const apiRef = useGridApiRef(); | |||
| const { | |||
| register, | |||
| @@ -22,7 +22,7 @@ type SearchParamNames = keyof SearchQuery; | |||
| const PoSearch: React.FC<Props> = ({ po, warehouse }) => { | |||
| const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); | |||
| const { t } = useTranslation("po"); | |||
| const { t } = useTranslation("purchaseOrder"); | |||
| const router = useRouter(); | |||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { | |||
| @@ -146,10 +146,12 @@ function SearchResults<T extends ResultWithId>({ | |||
| const [page, setPage] = React.useState(0); | |||
| const [rowsPerPage, setRowsPerPage] = React.useState(10); | |||
| /// this | |||
| const handleChangePage: TablePaginationProps["onPageChange"] = ( | |||
| _event, | |||
| newPage, | |||
| ) => { | |||
| console.log(_event) | |||
| setPage(newPage); | |||
| if (setPagingController) { | |||
| setPagingController({ | |||
| @@ -157,11 +159,12 @@ function SearchResults<T extends ResultWithId>({ | |||
| pageNum: newPage + 1, | |||
| }) | |||
| } | |||
| }; | |||
| } | |||
| const handleChangeRowsPerPage: TablePaginationProps["onRowsPerPageChange"] = ( | |||
| event, | |||
| ) => { | |||
| console.log(event) | |||
| setRowsPerPage(+event.target.value); | |||
| setPage(0); | |||
| if (setPagingController) { | |||
| @@ -0,0 +1 @@ | |||
| {} | |||
| @@ -1 +1,7 @@ | |||
| {} | |||
| { | |||
| "Search Criteria": "搜尋條件", | |||
| "All": "全部", | |||
| "No options": "沒有選項", | |||
| "Reset": "重置", | |||
| "Search": "搜尋" | |||
| } | |||
| @@ -0,0 +1,85 @@ | |||
| { | |||
| "Purchase Order": "採購訂單", | |||
| "Code": "編號", | |||
| "OrderDate": "下單日期", | |||
| "Details": "詳情", | |||
| "Supplier": "供應商", | |||
| "Status": "狀態", | |||
| "Escalated": "已上報", | |||
| "Do you want to start?": "確定開始嗎?", | |||
| "Start": "開始", | |||
| "Start Success": "開始成功", | |||
| "Start Fail": "開始失敗", | |||
| "Start PO": "開始採購訂單", | |||
| "Do you want to complete?": "確定完成嗎?", | |||
| "Complete": "完成", | |||
| "Complete Success": "完成成功", | |||
| "Complete Fail": "完成失敗", | |||
| "Complete PO": "完成採購訂單", | |||
| "General": "一般", | |||
| "Bind Storage": "綁定倉位", | |||
| "itemNo": "項目編號", | |||
| "itemName": "項目名稱", | |||
| "qty": "數量", | |||
| "uom": "計量單位", | |||
| "total weight": "總重量", | |||
| "weight unit": "重量單位", | |||
| "price": "價格", | |||
| "processed": "已入倉", | |||
| "expiryDate": "到期日", | |||
| "acceptedQty": "接受數量", | |||
| "weight": "重量", | |||
| "status": "狀態", | |||
| "start": "開始", | |||
| "qc": "質量控制", | |||
| "escalation": "上報", | |||
| "stock in": "入庫", | |||
| "putaway": "上架", | |||
| "delete": "刪除", | |||
| "qty cannot be greater than remaining qty": "數量不能大於剩餘數量", | |||
| "Record pol": "記錄採購訂單", | |||
| "Add some entries!": "添加條目!", | |||
| "draft": "草稿", | |||
| "pending": "待處理", | |||
| "determine1": "上報1", | |||
| "determine2": "上報2", | |||
| "determine3": "上報3", | |||
| "receiving": "收貨中", | |||
| "received": "已收貨", | |||
| "completed": "已完成", | |||
| "rejected": "已拒絕", | |||
| "acceptedQty must not greater than": "接受數量不得大於", | |||
| "minimal value is 1": "最小值為1", | |||
| "value must be a number": "值必須是數字", | |||
| "qc Check": "質量控制檢查", | |||
| "Please select QC": "請選擇質量控制", | |||
| "failQty": "失敗數量", | |||
| "select qc": "選擇質量控制", | |||
| "enter a failQty": "請輸入失敗數量", | |||
| "qty too big": "數量過大", | |||
| "sampleRate": "抽樣率", | |||
| "sampleWeight": "樣本重量", | |||
| "totalWeight": "總重量", | |||
| "Escalation": "上報", | |||
| "to be processed": "待處理", | |||
| "Stock In Detail": "入庫詳情", | |||
| "productLotNo": "產品批號", | |||
| "receiptDate": "收貨日期", | |||
| "acceptedWeight": "接受重量", | |||
| "productionDate": "生產日期", | |||
| "Select warehouse": "選擇倉庫", | |||
| "Putaway Detail": "上架詳情", | |||
| "LotNo": "批號", | |||
| "Po Code": "採購訂單編號", | |||
| "No Warehouse": "沒有倉庫", | |||
| "Please scan warehouse qr code.": "請掃描倉庫 QR 碼。", | |||
| "Reject": "拒絕", | |||
| "submit": "提交", | |||
| "print": "列印" | |||
| } | |||