From a6ad0f36a6bdcce4c4e207d0ba210ee0814fdccd Mon Sep 17 00:00:00 2001 From: "MSI\\derek" Date: Fri, 23 May 2025 17:53:07 +0800 Subject: [PATCH] update --- src/app/api/po/index.ts | 5 +- src/app/api/settings/uom/index.ts | 20 ++++++ src/app/utils/formatUtil.ts | 13 +++- src/components/PoDetail/PoDetail.tsx | 27 ++++++-- src/components/PoDetail/PoInputGrid.tsx | 39 ++++++++--- src/components/PoDetail/PoQcStockInModal.tsx | 64 +++++++++---------- src/components/PoDetail/PutawayForm.tsx | 15 +++++ src/components/PoDetail/QcForm.tsx | 30 ++++----- src/components/QrCode/QrCode.tsx | 15 +++++ src/components/QrCode/index.ts | 1 + .../RoughSchedule/RoughScheduleWrapper.tsx | 22 ++++--- 11 files changed, 176 insertions(+), 75 deletions(-) create mode 100644 src/app/api/settings/uom/index.ts create mode 100644 src/components/QrCode/QrCode.tsx create mode 100644 src/components/QrCode/index.ts diff --git a/src/app/api/po/index.ts b/src/app/api/po/index.ts index 4e6a055..c10cbe4 100644 --- a/src/app/api/po/index.ts +++ b/src/app/api/po/index.ts @@ -2,6 +2,7 @@ import { cache } from "react"; import "server-only"; import { serverFetchJson } from "@/app/utils/fetchUtil"; import { BASE_API_URL } from "@/config/api"; +import { Uom } from "../settings/uom"; export interface PoResult { id: number @@ -21,7 +22,7 @@ export interface PurchaseOrderLine { itemName: string qty: number processed: number - uom?: string + uom: Uom price: number status: string stockInLine: StockInLine[] @@ -35,6 +36,7 @@ export interface StockInLine { itemId: number itemNo: string itemName: string + itemType: string demandQty: number acceptedQty: number price: number @@ -45,6 +47,7 @@ export interface StockInLine { supplier: string lotNo: string poCode: string + uom: Uom } export const fetchPoList = cache(async () => { diff --git a/src/app/api/settings/uom/index.ts b/src/app/api/settings/uom/index.ts new file mode 100644 index 0000000..67e91a4 --- /dev/null +++ b/src/app/api/settings/uom/index.ts @@ -0,0 +1,20 @@ +import { cache } from "react"; +import "server-only"; +import { serverFetchJson } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; + +export interface Uom { + id: number + code: string + name: string + unit1: string + unit1Qty: number + unit2?: string + unit2Qty: number + unit3?: string + unit3Qty: number + unit4?: string + unit4Qty: number + sizeInGram: number + gramPerSmallestUnit: number +} diff --git a/src/app/utils/formatUtil.ts b/src/app/utils/formatUtil.ts index 760885e..802a8a0 100644 --- a/src/app/utils/formatUtil.ts +++ b/src/app/utils/formatUtil.ts @@ -1,3 +1,5 @@ +import { Uom } from "../api/settings/uom"; + export const manhourFormatter = new Intl.NumberFormat("en-HK", { minimumFractionDigits: 2, maximumFractionDigits: 2, @@ -27,4 +29,13 @@ export const stockInLineStatusMap: { [status: string]: number } = { "received": 7, "completed": 8, "rejected": 9, -}; \ No newline at end of file +}; + +export const calculateWeight = (qty: number, uom: Uom) => { + return qty * (uom.unit2Qty || 1) * (uom.unit3Qty || 1) * (uom.unit4Qty || 1); +} + +export const returnWeightUnit = (uom: Uom) => { + return uom.unit4 || uom.unit3 || uom.unit2 || uom.unit1; +} + diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 37053c5..6696086 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -41,6 +41,7 @@ import PoInputGrid from "./PoInputGrid"; import { QcItemWithChecks } from "@/app/api/qc"; import { useSearchParams } from "next/navigation"; import { WarehouseResult } from "@/app/api/warehouse"; +import { calculateWeight, returnWeightUnit } from "@/app/utils/formatUtil"; type Props = { po: PoResult; @@ -65,7 +66,19 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { const { row } = props; const [open, setOpen] = useState(false); const [processedQty, setProcessedQty] = useState(row.processed); + const [currStatus, setCurrStatus] = useState(row.status); + useEffect(() => { + if (processedQty === row.qty) { + setCurrStatus("completed".toUpperCase()); + } else if (processedQty > 0) { + setCurrStatus("receiving".toUpperCase()); + } else { + setCurrStatus("pending".toUpperCase()); + } + }, [processedQty]); + const totalWeight = useMemo(() => calculateWeight(row.qty, row.uom), []); + const weightUnit = useMemo(() => returnWeightUnit(row.uom), []); return ( <> *": { borderBottom: "unset" }, color: "black" }}> @@ -82,14 +95,18 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { {row.itemName} {row.qty} {processedQty} - {row.uom} + {row.uom?.code} + + {totalWeight} {weightUnit} + + {/* {weightUnit} */} {row.price} {/* {row.expiryDate} */} - {row.status} + {currStatus} - {/* */} - + {/* */} + @@ -139,6 +156,8 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { {t("qty")} processed {t("uom")} + {t("total weight")} + {/* {t("weight unit")} */} {t("price")} {/* {t("expiryDate")} */} {t("status")} diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index dd86171..f27c363 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -35,7 +35,7 @@ import PlayArrowIcon from "@mui/icons-material/PlayArrow"; import { PurchaseOrderLine, StockInLine } from "@/app/api/po"; import { createStockInLine, testFetch } from "@/app/api/po/actions"; import { useSearchParams } from "next/navigation"; -import { stockInLineStatusMap } from "@/app/utils/formatUtil"; +import { returnWeightUnit, calculateWeight, stockInLineStatusMap } from "@/app/utils/formatUtil"; import PoQcStockInModal from "./PoQcStockInModal"; import NotificationImportantIcon from "@mui/icons-material/NotificationImportant"; import { WarehouseResult } from "@/app/api/warehouse"; @@ -43,7 +43,7 @@ import LooksOneIcon from '@mui/icons-material/LooksOne'; import LooksTwoIcon from '@mui/icons-material/LooksTwo'; import Looks3Icon from '@mui/icons-material/Looks3'; import axiosInstance from "@/app/(main)/axios/axiosInstance"; -import axios, { AxiosRequestConfig } from "axios"; +// import axios, { AxiosRequestConfig } from "axios"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; import qs from 'qs'; import QrCodeIcon from '@mui/icons-material/QrCode'; @@ -172,11 +172,12 @@ function PoInputGrid({ const fetchQcDefaultValue = useCallback(async () => { const authHeader = axiosInstance.defaults.headers['Authorization']; if (!authHeader) { - return; // Exit the function if the token is not set + return; // Exit the function if the token is not set } - const res = await axios.get(`${NEXT_PUBLIC_API_URL}/qcResult/${itemDetail.id}`) + console.log(authHeader) + const res = await axiosInstance.get(`${NEXT_PUBLIC_API_URL}/qcResult/${itemDetail.id}`) console.log(res) - }, [axiosInstance, axios]) + }, [axiosInstance]) const handleQC = useCallback( (id: GridRowId, params: any) => async () => { @@ -320,6 +321,24 @@ function PoInputGrid({ editable: true, // replace with tooltip + content }, + { + field: "uom", + headerName: "uom", + flex: 0.5, + renderCell: (params) => { + return params.row.uom.code; + }, + }, + { + field: "weight", + headerName: "weight", + flex: 0.5, + renderCell: (params) => { + const weight = calculateWeight(params.row.acceptedQty, params.row.uom); + const weightUnit = returnWeightUnit(params.row.uom); + return `${weight} ${weightUnit}`; + }, + }, { field: "status", flex: 0.5, @@ -329,7 +348,7 @@ function PoInputGrid({ field: "actions", type: "actions", headerName: "start | qc | escalation | stock in | putaway | delete", - flex: 1.5, + flex: 1, cellClassName: "actions", getActions: (params) => { console.log(params.row.status); @@ -357,9 +376,7 @@ function PoInputGrid({ // marginRight: 1, }} disabled={ - // stockInLineStatusMap[status] <= 0 || - // stockInLineStatusMap[status] >= 5 - stockInLineStatusMap[status] != 1 + stockInLineStatusMap[status] < 1 } // set _isNew to false after posting // or check status @@ -405,7 +422,7 @@ function PoInputGrid({ color: "primary.main", // marginRight: 1, }} - disabled={stockInLineStatusMap[status] !== 7} + disabled={stockInLineStatusMap[status] < 7} // set _isNew to false after posting // or check status onClick={handlePutAway(params.row.id, params)} @@ -446,6 +463,7 @@ function PoInputGrid({ ); const addRow = useCallback(() => { + console.log(itemDetail) const newEntry = { id: Date.now(), _isNew: true, @@ -455,6 +473,7 @@ function PoInputGrid({ itemNo: itemDetail.itemNo, itemName: itemDetail.itemName, acceptedQty: itemDetail.qty - currQty, // this bug + uom: itemDetail.uom, status: "draft", }; setEntries((e) => [...e, newEntry]); diff --git a/src/components/PoDetail/PoQcStockInModal.tsx b/src/components/PoDetail/PoQcStockInModal.tsx index 36c6d43..16fb7fe 100644 --- a/src/components/PoDetail/PoQcStockInModal.tsx +++ b/src/components/PoDetail/PoQcStockInModal.tsx @@ -14,6 +14,7 @@ import { StockInLineRow } from "./PoInputGrid"; import EscalationForm from "./EscalationForm"; import StockInForm from "./StockInForm"; import PutawayForm from "./PutawayForm"; +import { stockInLineStatusMap } from "@/app/utils/formatUtil"; interface CommonProps extends Omit { setEntries: Dispatch> @@ -88,7 +89,6 @@ const PoQcStockInModal: React.FC = ({ const onSubmit = useCallback>( async (data, event) => { let hasErrors = false; - console.log("errors"); console.log(errors); console.log(data); console.log(itemDetail); @@ -105,14 +105,6 @@ const PoQcStockInModal: React.FC = ({ if (data.qcResult) { acceptedQty = itemDetail.acceptedQty - data.qcResult.reduce((acc, curr) => acc + curr.failQty, 0) } - console.log(acceptedQty) - // if (data.acceptedQty) { - // console.log("1") - // acceptedQty = parseInt(data.acceptedQty.toString()) - // } else { - // console.log("2") - // acceptedQty = data.sampleRate - // } const args = { id: itemDetail.id, purchaseOrderId: parseInt(params.get("id")!!), @@ -130,7 +122,7 @@ const PoQcStockInModal: React.FC = ({ } const res = await updateStockInLine(args) if (Boolean(res.id)) { - // set entries + // update entries const newEntries = res.entity as StockInLine[] setEntries((prev) => { const updatedEntries = [...prev]; // Create a new array @@ -149,7 +141,6 @@ const PoQcStockInModal: React.FC = ({ // add loading closeHandler({}, "backdropClick") } - console.log(res) // if (res) } catch (e) { @@ -161,20 +152,20 @@ const PoQcStockInModal: React.FC = ({ [t, itemDetail] ); - const canSubmit = useMemo(() => { - if (type === "qc") { - // console.log(itemDetail.status) - return formProps.formState.isValid - } - if (type === "stockIn") { - return formProps.formState.isValid - } - if (type === "putaway") { - return formProps.formState.isValid - } - return true + const renderSubmitButton = useMemo((): Boolean => { + if (itemDetail) { + const status = itemDetail.status + switch (type) { + case "qc": + return stockInLineStatusMap[status] === 1 + case "putaway": + return stockInLineStatusMap[status] === 7 + default: + return false; // Handle unexpected type + } + } else return false }, [type, itemDetail]) - console.log(canSubmit) + renderSubmitButton return ( <> @@ -188,17 +179,20 @@ const PoQcStockInModal: React.FC = ({ {type === "stockIn" && } {type === "escalation" && } {type === "putaway" && } - - - + {renderSubmitButton ? ( + + + + ) : undefined + } diff --git a/src/components/PoDetail/PutawayForm.tsx b/src/components/PoDetail/PutawayForm.tsx index 103fba2..adc7df9 100644 --- a/src/components/PoDetail/PutawayForm.tsx +++ b/src/components/PoDetail/PutawayForm.tsx @@ -35,6 +35,8 @@ import { GridEditInputCell } from "@mui/x-data-grid"; import { StockInLine } from "@/app/api/po"; import { WarehouseResult } from "@/app/api/warehouse"; import { stockInLineStatusMap } from "@/app/utils/formatUtil"; +import { QRCodeSVG } from 'qrcode.react'; +import { QrCode } from "../QrCode"; interface Props { itemDetail: StockInLine; @@ -106,6 +108,15 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse }) => { [] ); + const qrContent = useMemo(() => ({ + itemId: itemDetail.itemId, + lotNo: itemDetail.lotNo, + // expiryDate: itemDetail.expiryDate, + // productionDate: itemDetail.productionDate, + // supplier: itemDetail.supplier, + // poCode: itemDetail.poCode, + }),[itemDetail]) + useEffect(() => { setValue("status", "completed") }, []) @@ -197,6 +208,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse }) => { max: itemDetail.acceptedQty, valueAsNumber: true, })} + defaultValue={itemDetail.acceptedQty} error={Boolean(errors.acceptedQty)} helperText={errors.acceptedQty?.message} /> @@ -215,6 +227,9 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse }) => { /> + + + = ({ qc, itemDetail }) => { console.log(itemDetail); // const [qc, setQc] = useState([]) - // const fetchQcCheck = useCallback(async () => { - // const authHeader = axiosInstance.defaults.headers['Authorization']; - // if (!authHeader) { - // return; // Exit the function if the token is not set - // } - // const params = { - // itemId: itemDetail.itemId - // } - // console.log(params) - // const res = await axios.get(`${NEXT_PUBLIC_API_URL}/qcCheck`, { params }) - // console.log(res) - // }, [axios]) - // useEffect(() => { - // fetchQcCheck() - // }, [fetchQcCheck]) + const fetchQcCheck = useCallback(async () => { + const authHeader = axiosInstance.defaults.headers['Authorization']; + if (!authHeader) { + return; // Exit the function if the token is not set + } + const params = { + itemId: itemDetail.itemId + } + console.log(params) + const res = await axios.get(`${NEXT_PUBLIC_API_URL}/qcCheck`, { params }) + console.log(res) + }, [axios]) + useEffect(() => { + fetchQcCheck() + }, [fetchQcCheck]) const [recordQty, setRecordQty] = useState(0); const columns = useMemo( diff --git a/src/components/QrCode/QrCode.tsx b/src/components/QrCode/QrCode.tsx new file mode 100644 index 0000000..dd0189c --- /dev/null +++ b/src/components/QrCode/QrCode.tsx @@ -0,0 +1,15 @@ +"use client" + +import { QRCodeSVG } from 'qrcode.react'; +import { CSSProperties } from 'react'; + +interface Props { + content: any; + sx?: CSSProperties; +} + +export default function QrCode({ content, sx }: Props) { + console.log(content); + const jsonStr = JSON.stringify(content); + return ; +} diff --git a/src/components/QrCode/index.ts b/src/components/QrCode/index.ts new file mode 100644 index 0000000..3833923 --- /dev/null +++ b/src/components/QrCode/index.ts @@ -0,0 +1 @@ +export {default as QrCode} from "./QrCode" \ No newline at end of file diff --git a/src/components/RoughSchedule/RoughScheduleWrapper.tsx b/src/components/RoughSchedule/RoughScheduleWrapper.tsx index 2a4ba2b..0f68994 100644 --- a/src/components/RoughSchedule/RoughScheduleWrapper.tsx +++ b/src/components/RoughSchedule/RoughScheduleWrapper.tsx @@ -1,17 +1,21 @@ -import { fetchAllItems, } from "@/app/api/settings/item"; -import {RoughScheduleLoading} from "./RoughScheduleLoading"; +import { fetchAllItems } from "@/app/api/settings/item"; +import { RoughScheduleLoading } from "./RoughScheduleLoading"; import RSOverview from "./RoughSchedileSearchView"; interface SubComponents { - Loading: typeof RoughScheduleLoading; + Loading: typeof RoughScheduleLoading; } -const RoughScheduleWrapper: ({}: {}) => Promise = async ({ - // type, - }) => { - // console.log(type) - var result = await fetchAllItems() - return ; +type Props = {}; + +const RoughScheduleWrapper: React.FC & SubComponents = async ( + { + // type, + } +) => { + // console.log(type) + var result = await fetchAllItems(); + return ; }; RoughScheduleWrapper.Loading = RoughScheduleLoading;