From f7b35c13a13e8cfe1d647eafdf976f8c57d41b64 Mon Sep 17 00:00:00 2001 From: kelvinsuen Date: Tue, 19 Aug 2025 19:49:50 +0800 Subject: [PATCH] update stock in modal --- src/app/api/dashboard/actions.ts | 22 +-- src/app/api/po/actions.ts | 13 +- src/app/utils/formatUtil.ts | 4 + .../DashboardPage/QC/SupervisorQcApproval.tsx | 8 +- src/components/PoDetail/PoDetail.tsx | 1 + src/components/PoDetail/PoInputGrid.tsx | 53 +++--- src/components/PoDetail/PoQcStockInModal.tsx | 6 +- src/components/PoDetail/PutawayForm.tsx | 5 +- src/components/PoDetail/QcFormVer2.tsx | 41 +++-- .../PoDetail/QcStockInModalVer2.tsx | 151 ++++++++++++++---- src/components/PoDetail/StockInFormVer2.tsx | 11 +- src/components/PoDetail/dummyQcTemplate.tsx | 12 +- src/components/Swal/CustomAlerts.tsx | 1 + src/i18n/index.tsx | 4 +- src/i18n/zh/dashboard.json | 4 + src/i18n/zh/purchaseOrder.json | 13 +- 16 files changed, 244 insertions(+), 105 deletions(-) diff --git a/src/app/api/dashboard/actions.ts b/src/app/api/dashboard/actions.ts index df54e1c..da6d72d 100644 --- a/src/app/api/dashboard/actions.ts +++ b/src/app/api/dashboard/actions.ts @@ -11,7 +11,7 @@ import { QcItemResult } from "../settings/qcItem"; import { RecordsRes } from "../utils"; // import { BASE_API_URL } from "@/config/api"; -export interface PostStockInLiineResponse { +export interface PostStockInLineResponse { id: number | null; name: string; code: string; @@ -38,6 +38,7 @@ export interface StockInLineEntry { export interface PurchaseQcResult { qcItemId: number; failQty: number; + isPassed: boolean; } export interface StockInInput { status: string; @@ -49,11 +50,12 @@ export interface StockInInput { expiryDate: string; } export interface PurchaseQCInput { - status: string; - acceptedQty: number; - sampleRate: number; - sampleWeight: number; - totalWeight: number; + status?: string; + qcAccept: boolean; + acceptQty: number; + sampleRate?: number; + sampleWeight?: number; + totalWeight?: number; qcResult: PurchaseQcResult[]; } export interface EscalationInput { @@ -92,7 +94,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { export const createStockInLine = async (data: StockInLineEntry) => { console.log(data) const stockInLine = await serverFetchJson< - PostStockInLiineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/create`, { method: "POST", body: JSON.stringify(data), @@ -106,7 +108,7 @@ export const updateStockInLine = async ( data: StockInLineEntry & ModalFormInput, ) => { const stockInLine = await serverFetchJson< - PostStockInLiineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/update`, { method: "POST", body: JSON.stringify(data), @@ -117,7 +119,7 @@ export const updateStockInLine = async ( }; export const startPo = async (poId: number) => { - const po = await serverFetchJson>( + const po = await serverFetchJson>( `${BASE_API_URL}/po/start/${poId}`, { method: "POST", @@ -130,7 +132,7 @@ export const startPo = async (poId: number) => { }; export const checkPolAndCompletePo = async (poId: number) => { - const po = await serverFetchJson>( + const po = await serverFetchJson>( `${BASE_API_URL}/po/check/${poId}`, { method: "POST", diff --git a/src/app/api/po/actions.ts b/src/app/api/po/actions.ts index 9514c66..bd6e972 100644 --- a/src/app/api/po/actions.ts +++ b/src/app/api/po/actions.ts @@ -12,7 +12,7 @@ import { RecordsRes } from "../utils"; import { Uom } from "../settings/uom"; // import { BASE_API_URL } from "@/config/api"; -export interface PostStockInLiineResponse { +export interface PostStockInLineResponse { id: number | null; name: string; code: string; @@ -35,13 +35,16 @@ export interface StockInLineEntry { export interface PurchaseQcResult { qcItemId: number; + isPassed: boolean, failQty: number; + remarks?: string } export interface StockInInput { status: string; poCode: string; productLotNo?: string; dnNo?: string; + dnDate?: string; itemName: string; invoiceNo?: string; receiptDate: string; @@ -107,7 +110,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { export const createStockInLine = async (data: StockInLineEntry) => { const stockInLine = await serverFetchJson< - PostStockInLiineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/create`, { method: "POST", body: JSON.stringify(data), @@ -121,7 +124,7 @@ export const updateStockInLine = async ( data: StockInLineEntry & ModalFormInput, ) => { const stockInLine = await serverFetchJson< - PostStockInLiineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/update`, { method: "POST", body: JSON.stringify(data), @@ -132,7 +135,7 @@ export const updateStockInLine = async ( }; export const startPo = async (poId: number) => { - const po = await serverFetchJson>( + const po = await serverFetchJson>( `${BASE_API_URL}/po/start/${poId}`, { method: "POST", @@ -145,7 +148,7 @@ export const startPo = async (poId: number) => { }; export const checkPolAndCompletePo = async (poId: number) => { - const po = await serverFetchJson>( + const po = await serverFetchJson>( `${BASE_API_URL}/po/check/${poId}`, { method: "POST", diff --git a/src/app/utils/formatUtil.ts b/src/app/utils/formatUtil.ts index 21e61f0..e791833 100644 --- a/src/app/utils/formatUtil.ts +++ b/src/app/utils/formatUtil.ts @@ -54,6 +54,10 @@ export const arrayToDateString = (arr: ConfigType | (number | undefined)[]) => { return arrayToDayjs(arr).format(OUTPUT_DATE_FORMAT); }; +export const arrayToInputDateString = (arr: ConfigType | (number | undefined)[]) => { + return arrayToDayjs(arr).format(INPUT_DATE_FORMAT); +}; + export const dateStringToDayjs = (date: string) => { // Format: YYYY/MM/DD return dayjs(date, OUTPUT_DATE_FORMAT); diff --git a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx b/src/components/DashboardPage/QC/SupervisorQcApproval.tsx index 35a4136..1611b7f 100644 --- a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx +++ b/src/components/DashboardPage/QC/SupervisorQcApproval.tsx @@ -55,10 +55,10 @@ const navigateTo = useCallback( - {t("purchase order code")} - {t("item name")} - {t("escalation level")} - {t("reason")} + {t("Purchase Order Code")} + {t("Item Name")} + {t("Escalation Level")} + {t("Reason")} diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 000602e..14d2d9c 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -823,6 +823,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { setProcessedQty={setProcessedQty} itemDetail={selectedRow} warehouse={warehouse} + fetchPoDetail={fetchPoDetail} /> diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index 11d5452..43c0b03 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -73,6 +73,7 @@ interface Props { itemDetail: PurchaseOrderLine; stockInLine: StockInLine[]; warehouse: WarehouseResult[]; + fetchPoDetail: (poId: string) => void; } export type StockInLineEntryError = { @@ -111,6 +112,7 @@ function PoInputGrid({ itemDetail, stockInLine, warehouse, + fetchPoDetail }: Props) { console.log(itemDetail); const { t } = useTranslation("purchaseOrder"); @@ -272,6 +274,7 @@ const closeNewModal = useCallback(() => { const newParams = new URLSearchParams(searchParams.toString()); newParams.delete("stockInLineId"); // Remove the parameter router.replace(`${pathname}?${newParams.toString()}`); + fetchPoDetail(itemDetail.purchaseOrderId.toString()); setTimeout(() => { setNewOpen(false); // Close the modal first }, 300); // Add a delay to avoid immediate re-trigger of useEffect @@ -413,6 +416,17 @@ const closeNewModal = useCallback(() => { [], ); + const getButtonSx = (status : string) => { + let btnSx = {label:"", color:""}; + switch (status) { + case "received": btnSx = {label: t("putaway processing"), color:"secondary.main"}; break; + case "rejected": + case "completed": btnSx = {label: t("view stockin"), color:"info.main"}; break; + default: btnSx = {label: t("qc processing"), color:"success.main"}; + } + return btnSx + }; + // const handleQrCode = useCallback( // (id: GridRowId, params: any) => () => { // setRowModesModel((prev) => ({ @@ -532,7 +546,7 @@ const closeNewModal = useCallback(() => { { field: "status", headerName: t("Status"), - width: 70, + width: 140, // flex: 0.5, renderCell: (params) => { return t(`${params.row.status}`); @@ -546,20 +560,22 @@ const closeNewModal = useCallback(() => { // )} | ${t("putaway")} | ${t("delete")}`, headerName: "動作", // headerName: "start | qc | escalation | stock in | putaway | delete", - width: 300, + width: 200, // flex: 2, cellClassName: "actions", getActions: (params) => { // console.log(params.row.status); const status = params.row.status.toLowerCase(); + const btnSx = getButtonSx(status); // console.log(stockInLineStatusMap[status]); // console.log(session?.user?.abilities?.includes("APPROVAL")); return [ {t("qc processing")}} + icon={} label="start" sx={{ - color: "primary.main", + // color: "primary.main", // marginRight: 1, }} // disabled={!(stockInLineStatusMap[status] === 0)} @@ -569,20 +585,21 @@ const closeNewModal = useCallback(() => { color="inherit" key="edit" />, - {t("putawayBtn")}} - label="start" - sx={{ - color: "primary.main", - // marginRight: 1, - }} - // disabled={!(stockInLineStatusMap[status] === 0)} - // set _isNew to false after posting - // or check status - onClick={handleStart(params.row.id, params)} - color="inherit" - key="edit" - />, + // {t("putawayBtn")}} + // label="start" + // sx={{ + // color: "primary.main", + // // marginRight: 1, + // }} + // // disabled={!(stockInLineStatusMap[status] === 0)} + // // set _isNew to false after posting + // // or check status + // onClick={handleStart(params.row.id, params)} + // color="inherit" + // key="edit" + // />, + // {t("qc processing")}} // label="start" diff --git a/src/components/PoDetail/PoQcStockInModal.tsx b/src/components/PoDetail/PoQcStockInModal.tsx index 49c0466..0702ca4 100644 --- a/src/components/PoDetail/PoQcStockInModal.tsx +++ b/src/components/PoDetail/PoQcStockInModal.tsx @@ -121,9 +121,9 @@ const PoQcStockInModal: React.FC = ({ const params = useSearchParams(); const [btnIsLoading, setBtnIsLoading] = useState(false); - console.log(params.get("id")); - console.log(itemDetail); - console.log(itemDetail.qcResult); + // console.log(params.get("id")); + // console.log(itemDetail); + // console.log(itemDetail.qcResult); const formProps = useForm({ defaultValues: { ...itemDetail, diff --git a/src/components/PoDetail/PutawayForm.tsx b/src/components/PoDetail/PutawayForm.tsx index 75459a7..69231c5 100644 --- a/src/components/PoDetail/PutawayForm.tsx +++ b/src/components/PoDetail/PutawayForm.tsx @@ -245,8 +245,9 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { }, [scanner.values]); useEffect(() => { - setValue("status", "completed"); - setValue("warehouseId", options[0].value); + setValue("status", "received"); + // setValue("status", "completed"); + setValue("warehouseId", options[0].value); //TODO: save all warehouse entry? }, []); useEffect(() => { diff --git a/src/components/PoDetail/QcFormVer2.tsx b/src/components/PoDetail/QcFormVer2.tsx index 9c615a2..2fe055e 100644 --- a/src/components/PoDetail/QcFormVer2.tsx +++ b/src/components/PoDetail/QcFormVer2.tsx @@ -51,6 +51,7 @@ import StockInFormVer2 from "./StockInFormVer2"; import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; import { ModalFormInput } from "@/app/api/dashboard/actions"; import { escape } from "lodash"; +import { PanoramaSharp } from "@mui/icons-material"; interface Props { itemDetail: StockInLine; @@ -216,7 +217,8 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI } - label="合格" + label="合格" + disabled={itemDetail.status.toLowerCase() == "completed"} sx={{ color: currentValue === true ? "green" : "inherit", "& .Mui-checked": {color: "green"} @@ -226,6 +228,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI value="false" control={} label="不合格" + disabled={itemDetail.status.toLowerCase() == "completed"} sx={{ color: currentValue === false ? "red" : "inherit", "& .Mui-checked": {color: "red"} @@ -237,7 +240,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI }, }, { - field: "failedQty", + field: "failQty", headerName: t("failedQty"), flex: 1, // editable: true, @@ -246,13 +249,13 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI type="number" size="small" value={!params.row.isPassed? (params.value ?? '') : '0'} - disabled={params.row.isPassed} + disabled={params.row.isPassed || itemDetail.status.toLowerCase() == "completed"} onChange={(e) => { const v = e.target.value; const next = v === '' ? undefined : Number(v); if (Number.isNaN(next)) return; setQcItems((prev) => - prev.map((r) => (r.id === params.id ? { ...r, failedQty: next } : r)) + prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r)) ); }} onClick={(e) => e.stopPropagation()} @@ -271,6 +274,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI { const remarks = e.target.value; // const next = v === '' ? undefined : Number(v); @@ -296,10 +300,12 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI // Set initial value for acceptQty useEffect(() => { - if (itemDetail?.acceptedQty !== undefined) { - setValue("acceptQty", itemDetail.acceptedQty); + if (itemDetail?.demandQty > 0) { //!== undefined) { + setValue("acceptQty", itemDetail.demandQty); // THIS NEED TO UPDATE TO NOT USE DEMAND QTY + } else { + setValue("acceptQty", itemDetail?.acceptedQty); } - }, [itemDetail?.acceptedQty, setValue]); + }, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); // const [openCollapse, setOpenCollapse] = useState(false) const [isCollapsed, setIsCollapsed] = useState(false); @@ -365,14 +371,14 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI /> - - {/* + {!qcAccept && ( + - */} + )} )} {tabIndex == 1 && ( @@ -419,14 +425,16 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI field.onChange(value); }} > - } label="接受" /> + } label="接受" /> = ({ qc, itemDetail, disabled, qcItems, setQcI helperText={errors.acceptQty?.message} /> - } label="不接受及上報" /> + } + sx={{"& .Mui-checked": {color: "red"}}} + label="不接受及上報" /> )} /> - {/* + {/* {qcAccept && {t("Escalation Result")} @@ -451,7 +462,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI isCollapsed={isCollapsed} setIsCollapsed={setIsCollapsed} /> - */} + } */} diff --git a/src/components/PoDetail/QcStockInModalVer2.tsx b/src/components/PoDetail/QcStockInModalVer2.tsx index c0ddd89..0a53853 100644 --- a/src/components/PoDetail/QcStockInModalVer2.tsx +++ b/src/components/PoDetail/QcStockInModalVer2.tsx @@ -1,6 +1,6 @@ "use client"; import { StockInLine } from "@/app/api/po"; -import { ModalFormInput, PurchaseQcResult } from "@/app/api/po/actions"; +import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine } from "@/app/api/po/actions"; import { QcItemWithChecks } from "@/app/api/qc"; import { Box, @@ -22,6 +22,9 @@ import PutawayForm from "./PutawayForm"; import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate"; import { useGridApiRef } from "@mui/x-data-grid"; import {submitDialogWithWarning} from "../Swal/CustomAlerts"; +import { PurchaseQCInput, PutawayInput } from "@/app/api/dashboard/actions"; +import { arrayToDateString, arrayToInputDateString, dayjsToInputDateString } from "@/app/utils/formatUtil"; +import dayjs from "dayjs"; const style = { position: "absolute", @@ -73,15 +76,18 @@ const PoQcStockInModalVer2: React.FC = ({ t, i18n: { language }, } = useTranslation("purchaseOrder"); + const [qcItems, setQcItems] = useState(dummyQCData) const formProps = useForm({ defaultValues: { ...itemDetail, + dnDate: dayjsToInputDateString(dayjs()), putawayLine: dummyPutawayLine, // receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT), // warehouseId: itemDetail.defaultWarehouseId || 0 }, }); + const closeHandler = useCallback>( (...args) => { onClose?.(...args); @@ -89,13 +95,34 @@ const [qcItems, setQcItems] = useState(dummyQCData) }, [onClose], ); + + const isPutaway = () => { + if (itemDetail) { + const status = itemDetail.status; + return status == "received"; + + } else return false; + }; + + useEffect(() => { + formProps.reset({ + ...itemDetail, + dnDate: dayjsToInputDateString(dayjs()), + putawayLine: dummyPutawayLine, + }) + setOpenPutaway(isPutaway); + + }, [open]) + const [openPutaway, setOpenPutaway] = useState(false); const onOpenPutaway = useCallback(() => { + setOpenPutaway(true); }, []); const onClosePutaway = useCallback(() => { setOpenPutaway(false); }, []); + // Stock In submission handler const onSubmitStockIn = useCallback>( async (data, event) => { @@ -118,14 +145,16 @@ const [qcItems, setQcItems] = useState(dummyQCData) }, [], ); + // QC submission handler const onSubmitQc = useCallback>( async (data, event) => { console.log("QC Submission:", event!.nativeEvent); + // TODO: Move validation into QC page // Get QC data from the shared form context const qcAccept = data.qcAccept; - const acceptQty = data.acceptQty; + const acceptQty = data.acceptQty as number; // Validate QC data const validationErrors : string[] = []; @@ -137,7 +166,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) // Check if failed items have failed quantity const failedItemsWithoutQty = qcItems.filter(item => - item.isPassed === false && (!item.failedQty || item.failedQty <= 0) + item.isPassed === false && (!item.failQty || item.failQty <= 0) ); if (failedItemsWithoutQty.length > 0) { validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`); @@ -153,6 +182,14 @@ const [qcItems, setQcItems] = useState(dummyQCData) validationErrors.push("Accept quantity must be greater than 0"); } + // Check if dates are input + if (data.productionDate === undefined || data.productionDate == null) { + validationErrors.push("Production Date cannot be null!"); + } + if (data.expiryDate === undefined || data.expiryDate == null) { + validationErrors.push("Expiry Date cannot be null!"); + } + if (validationErrors.length > 0) { console.error("QC Validation failed:", validationErrors); alert(`未完成品檢: ${validationErrors}`); @@ -160,35 +197,75 @@ const [qcItems, setQcItems] = useState(dummyQCData) } const qcData = { - qcAccept: qcAccept, - acceptQty: acceptQty, - qcItems: qcItems.map(item => ({ - id: item.id, - qcItem: item.qcItem, - qcDescription: item.qcDescription, - isPassed: item.isPassed, - failedQty: (item.failedQty && !item.isPassed) || 0, + dnNo : data.dnNo? data.dnNo : "DN00000", + dnDate : data.dnDate? arrayToInputDateString(data.dnDate) : dayjsToInputDateString(dayjs()), + productionDate : arrayToInputDateString(data.productionDate), + expiryDate : arrayToInputDateString(data.expiryDate), + receiptDate : arrayToInputDateString(data.receiptDate), + + qcAccept: qcAccept? qcAccept : false, + acceptQty: acceptQty? acceptQty : 0, + qcResult: qcItems.map(item => ({ + qcItemId: item.id, + // qcItem: item.qcItem, + // qcDescription: item.qcDescription, + isPassed: item.isPassed? item.isPassed : false, + failQty: (item.failQty && !item.isPassed) ? item.failQty : 0, + // failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, remarks: item.remarks || '' })) }; // const qcData = data; console.log("QC Data for submission:", qcData); - // await submitQcData(qcData); - - if (!qcData.qcItems.every((qc) => qc.isPassed) && qcData.qcAccept) { - submitDialogWithWarning(onOpenPutaway, t, {title:"有不合格檢查項目,確認接受收貨?", confirmButtonText: "Confirm", html: ""}); + + if (!qcData.qcResult.every((qc) => qc.isPassed) && qcData.qcAccept) { + submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?", + confirmButtonText: t("confirm putaway"), html: ""}); return; } - - if (qcData.qcAccept) { - onOpenPutaway(); - } else { - onClose(); - } + await postStockInLineWithQc(qcData); + // return; }, [onOpenPutaway, qcItems], ); + + const postStockInLineWithQc = useCallback(async (qcData: PurchaseQCInput) => { + const args = { + ...qcData + // id: itemDetail.id, + // purchaseOrderId: itemDetail.purchaseOrderId, + // purchaseOrderLineId: itemDetail.purchaseOrderLineId, + // itemId: itemDetail.itemId, + // ...data, + // productionDate: productionDate, + // expiryDate: expiryDate, + // receiptDate: receiptDate, + } as ModalFormInput; + + await postStockInLine(args); + + if (qcData.qcAccept) { + // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", + // confirmButtonText: t("confirm putaway"), html: ""}); + onOpenPutaway(); + } else { + closeHandler({}, "backdropClick"); + } + return ; + },[onOpenPutaway,closeHandler]); + + const postStockInLine = useCallback(async (args: ModalFormInput) => { + const submitData = { + ...itemDetail, ...args + } as StockInLineEntry & ModalFormInput; + console.log(submitData); + + const res = await updateStockInLine(submitData); + console.log("result ", res); + return res; + },[]) + // Email supplier handler const onSubmitEmailSupplier = useCallback>( async (data, event) => { @@ -222,12 +299,22 @@ const [qcItems, setQcItems] = useState(dummyQCData) // binLocation: data.binLocation, // putawayQuantity: data.putawayQuantity, // putawayNotes: data.putawayNotes, - data: data, + acceptQty: itemDetail.demandQty? itemDetail.demandQty : itemDetail.acceptedQty, + ...data, + + dnDate : data.dnDate? arrayToInputDateString(data.dnDate) : dayjsToInputDateString(dayjs()), + productionDate : arrayToInputDateString(data.productionDate), + expiryDate : arrayToInputDateString(data.expiryDate), + receiptDate : arrayToInputDateString(data.receiptDate), // Add other putaway specific fields - }; + } as ModalFormInput; console.log("Putaway Data:", putawayData); + // Handle putaway submission logic here + const res = await postStockInLine(putawayData); + console.log("result ", res); + // Close modal after successful putaway closeHandler({}, "backdropClick"); }, @@ -239,6 +326,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) // Handle print logic here window.print(); }, []); + const acceptQty = formProps.watch("acceptedQty") const checkQcIsPassed = useCallback((qcItems: QcData[]) => { @@ -272,7 +360,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) marginRight: 3, }} > - {openPutaway ? ( + {openPutaway ? ( {t("confirm putaway")} @@ -320,7 +409,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) - + {/* - + */} - - + {t("confirm qc result")} + )} )} diff --git a/src/components/PoDetail/StockInFormVer2.tsx b/src/components/PoDetail/StockInFormVer2.tsx index a9e02c5..4e93583 100644 --- a/src/components/PoDetail/StockInFormVer2.tsx +++ b/src/components/PoDetail/StockInFormVer2.tsx @@ -123,7 +123,7 @@ const StockInFormVer2: React.FC = ({ {...register("dnNo", { // required: "productLotNo required!", })} - disabled={true} + disabled={itemDetail.status.toLowerCase() == "completed"} // error={Boolean(errors.productLotNo)} // helperText={errors.productLotNo?.message} /> @@ -205,7 +205,7 @@ const StockInFormVer2: React.FC = ({ {...register("productLotNo", { // required: "productLotNo required!", })} - disabled={disabled} + disabled={itemDetail.status.toLowerCase() == "completed"} error={Boolean(errors.productLotNo)} helperText={errors.productLotNo?.message} /> @@ -226,7 +226,7 @@ const StockInFormVer2: React.FC = ({ sx={{ width: "100%" }} label={t("productionDate")} value={productionDate ? dayjs(productionDate) : undefined} - disabled={disabled} + disabled={itemDetail.status.toLowerCase() == "completed"} onChange={(date) => { if (!date) return; setValue( @@ -275,7 +275,7 @@ const StockInFormVer2: React.FC = ({ sx={{ width: "100%" }} label={t("expiryDate")} value={expiryDate ? dayjs(expiryDate) : undefined} - disabled={disabled} + disabled={itemDetail.status.toLowerCase() == "completed"} onChange={(date) => { console.log(date); if (!date) return; @@ -322,10 +322,11 @@ const StockInFormVer2: React.FC = ({ { // console.log(props) diff --git a/src/i18n/index.tsx b/src/i18n/index.tsx index b404524..6428f12 100644 --- a/src/i18n/index.tsx +++ b/src/i18n/index.tsx @@ -6,8 +6,8 @@ import { authOptions } from "@/config/authConfig"; import I18nClientProvider from "./I18nClientProvider"; import universalLanguageDetect from "@unly/universal-language-detector"; -const FALLBACK_LANG = "en"; -const SUPPORTED_LANGUAGES = ["en", "zh"]; +const FALLBACK_LANG = "zh"; +const SUPPORTED_LANGUAGES = ["zh"]; export const detectLanguage = async (): Promise => { // Logic to get language preference from cookies/headers/session diff --git a/src/i18n/zh/dashboard.json b/src/i18n/zh/dashboard.json index bccb67c..0c2df71 100644 --- a/src/i18n/zh/dashboard.json +++ b/src/i18n/zh/dashboard.json @@ -14,6 +14,10 @@ "Humidity status": "濕度狀態", "Warehouse status": "倉庫狀態", "Progress chart": "進度圖表", + "Purchase Order Code": "採購單號", + "Item Name": "貨品名稱", + "Escalation Level": "上報等級", + "Reason": "原因", "Order completion": "訂單完成度", "Raw material": "原料", "Consumable": "消耗品", diff --git a/src/i18n/zh/purchaseOrder.json b/src/i18n/zh/purchaseOrder.json index 2d41589..d60cfab 100644 --- a/src/i18n/zh/purchaseOrder.json +++ b/src/i18n/zh/purchaseOrder.json @@ -19,6 +19,7 @@ "Start Fail": "開始失敗", "Start PO": "開始採購訂單", "Do you want to complete?": "確定完成嗎?", + "Cancel": "取消", "Complete": "完成", "Complete Success": "完成成功", "Complete Fail": "完成失敗", @@ -64,9 +65,9 @@ "determine2": "上報2", "determine3": "上報3", "receiving": "收貨中", - "received": "已收貨", - "completed": "已完成", - "rejected": "已拒絕", + "received": "已檢收", + "completed": "已上架", + "rejected": "已拒絕及上報", "status": "狀態", "acceptedQty must not greater than": "接受數量不得大於", @@ -107,6 +108,9 @@ "Accept submit": "接受來貨", "qc processing": "處理來貨及品檢", + "putaway processing": "處理來貨及上架", + "view stockin": "查看收貨及品檢", + "putaway processing": "處理來貨及上架", "putawayBtn": "上架", "dnNo": "送貨單編號", "dnDate": "送貨單日期", @@ -120,9 +124,10 @@ "update qc info": "更新品檢資料", "email supplier": "電郵供應商", "confirm putaway": "確定及上架", + "confirm qc result": "確定品檢結果", "warehouse": "倉庫", - "qcItem": "檢查項目", + "qcItem": "品檢項目", "passed": "接受", "failed": "不接受", "failedQty": "不合格數",