diff --git a/src/app/(main)/jo/page.tsx b/src/app/(main)/jo/page.tsx index 1020c94..6a4349e 100644 --- a/src/app/(main)/jo/page.tsx +++ b/src/app/(main)/jo/page.tsx @@ -26,7 +26,7 @@ const jo: React.FC = async () => { {t("Job Order")} - + {/* TODO: Improve */} }> diff --git a/src/app/api/jo/actions.ts b/src/app/api/jo/actions.ts index e3685d8..f2a6c89 100644 --- a/src/app/api/jo/actions.ts +++ b/src/app/api/jo/actions.ts @@ -2,7 +2,7 @@ import { cache } from 'react'; import { Pageable, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; -import { JoStatus, Machine, Operator } from "."; +import { JobOrder, JoStatus, Machine, Operator } from "."; import { BASE_API_URL } from "@/config/api"; import { revalidateTag } from "next/cache"; import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; @@ -21,14 +21,15 @@ export interface SaveJoResponse { export interface SearchJoResultRequest extends Pageable { code: string; - name: string; + itemName?: string; } export interface SearchJoResultResponse { - records: SearchJoResult[]; + records: JobOrder[]; total: number; } +// DEPRECIATED export interface SearchJoResult { id: number; code: string; @@ -39,6 +40,11 @@ export interface SearchJoResult { status: JoStatus; } +export interface UpdateJoRequest { + id: number; + status: string; +} + // For Jo Button Actions export interface CommonActionJoRequest { id: number; @@ -79,6 +85,7 @@ export interface JobOrderDetail { pickLines: any[]; status: string; } + export interface UnassignedJobOrderPickOrder { pickOrderId: number; pickOrderCode: string; @@ -223,6 +230,7 @@ export const fetchCompletedJobOrderPickOrderRecords = cache(async (userId: numbe }, ); }); + export const fetchJobOrderDetailByCode = cache(async (code: string) => { return serverFetchJson( `${BASE_API_URL}/jo/detailByCode/${code}`, @@ -275,6 +283,15 @@ export const fetchJos = cache(async (data?: SearchJoResultRequest) => { return response }) +export const updateJo = cache(async (data: UpdateJoRequest) => { + return serverFetchJson(`${BASE_API_URL}/jo/update`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }) +}) + export const releaseJo = cache(async (data: CommonActionJoRequest) => { const response = serverFetchJson(`${BASE_API_URL}/jo/release`, { diff --git a/src/app/api/jo/index.ts b/src/app/api/jo/index.ts index 080cbef..3a1d60b 100644 --- a/src/app/api/jo/index.ts +++ b/src/app/api/jo/index.ts @@ -3,6 +3,8 @@ import { serverFetchJson } from "@/app/utils/fetchUtil"; import { BASE_API_URL } from "@/config/api"; import { cache } from "react"; +import { Item } from "../settings/item"; +import { Uom } from "../settings/uom"; export type JoStatus = "planning" | "pending" | "processing" | "packaging" | "storing" | "completed" export type JoBomMaterialStatus = "pending" | "completed" @@ -13,6 +15,24 @@ export interface Operator { username: string; } +export interface JobOrder { + id: number; + code: string; + reqQty: number; + item: Item; + itemName: string; + // uom: Uom; + pickLines?: JoDetailPickLine[]; + status: JoStatus; + planStart?: number[]; + planEnd?: number[]; + type: string; + // TODO pack below into StockInLineInfo + stockInLineId?: number; + stockInLineStatus?: string; + silHandlerId?: number; +} + export interface Machine { id: number; name: string; @@ -24,14 +44,17 @@ export interface JoDetail { id: number; code: string; itemCode: string; + itemName?: string; name: string; reqQty: number; + // itemId: number; uom: string; pickLines: JoDetailPickLine[]; status: JoStatus; planStart: number[]; planEnd: number[]; type: string; + // item?: Item; } export interface JoDetailPickLine { @@ -52,7 +75,7 @@ export interface JoDetailPickedLotNo { } export const fetchJoDetail = cache(async (id: number) => { - return serverFetchJson(`${BASE_API_URL}/jo/detail/${id}`, + return serverFetchJson(`${BASE_API_URL}/jo/detail/${id}`, { method: "GET", headers: { "Content-Type": "application/json"}, diff --git a/src/app/api/settings/item/index.ts b/src/app/api/settings/item/index.ts index bee66f1..57bd464 100644 --- a/src/app/api/settings/item/index.ts +++ b/src/app/api/settings/item/index.ts @@ -5,6 +5,7 @@ import "server-only"; import { serverFetchJson } from "../../../utils/fetchUtil"; import { BASE_API_URL } from "../../../../config/api"; import { QcCategoryResult } from "../qcCategory"; +import { Uom } from "../uom"; // import { TypeInputs, UomInputs, WeightUnitInputs } from "./actions"; @@ -24,6 +25,19 @@ export type ItemsResultResponse = { total: number; }; +export type Item = { + id: number; + code: string; + name: string; + description?: string; + remarks?: string; + type?: string; + shelfLife?: number; + countryOfOrigin?: string; + qcCategory?: QcCategoryResult; + uom: Uom; +} + export type ItemsResult = { id: string | number; code: string; diff --git a/src/app/api/stockIn/actions.ts b/src/app/api/stockIn/actions.ts index 61a26da..e94ce20 100644 --- a/src/app/api/stockIn/actions.ts +++ b/src/app/api/stockIn/actions.ts @@ -30,6 +30,7 @@ export interface StockInLineEntry { acceptedQty: number; purchaseOrderId?: number; purchaseOrderLineId?: number; + jobOrderId?: number; status?: string; expiryDate?: string; productLotNo?: string; diff --git a/src/app/api/stockIn/index.ts b/src/app/api/stockIn/index.ts index 9ef5cec..aacd62b 100644 --- a/src/app/api/stockIn/index.ts +++ b/src/app/api/stockIn/index.ts @@ -101,6 +101,7 @@ export interface StockInLine { stockInId?: number; purchaseOrderId?: number; purchaseOrderLineId: number; + jobOrderId: number; itemId: number; itemNo: string; itemName: string; diff --git a/src/components/DashboardPage/escalation/EscalationLogTable.tsx b/src/components/DashboardPage/escalation/EscalationLogTable.tsx index 68866f9..83a6417 100644 --- a/src/components/DashboardPage/escalation/EscalationLogTable.tsx +++ b/src/components/DashboardPage/escalation/EscalationLogTable.tsx @@ -40,7 +40,11 @@ const EscalationLogTable: React.FC = ({ const [escalationLogs, setEscalationLogs] = useState([]); const useCardFilter = useContext(CardFilterContext); - const showCompleted = useCardFilter.filter; + const showCompleted = useMemo(() => { + if (type === "dashboard") { + return useCardFilter.filter; + } else { return true} + }, [useCardFilter.filter]); useEffect(() => { if (showCompleted) { diff --git a/src/components/JoSearch/JoCreateFormModal.tsx b/src/components/JoSearch/JoCreateFormModal.tsx index df15cbf..76ae5f5 100644 --- a/src/components/JoSearch/JoCreateFormModal.tsx +++ b/src/components/JoSearch/JoCreateFormModal.tsx @@ -11,6 +11,7 @@ import { isFinite } from "lodash"; import React, { SetStateAction, SyntheticEvent, useCallback, useEffect } from "react"; import { Controller, FormProvider, SubmitErrorHandler, SubmitHandler, useForm, useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { msg } from "../Swal/CustomAlerts"; interface Props { open: boolean; @@ -54,6 +55,7 @@ const JoCreateFormModal: React.FC = ({ const response = await manualCreateJo(data) if (response) { onSearch(); + msg(t("update success")); onModalClose(); } }, []) diff --git a/src/components/JoSearch/JoSearch.tsx b/src/components/JoSearch/JoSearch.tsx index 0de8c3c..be7308b 100644 --- a/src/components/JoSearch/JoSearch.tsx +++ b/src/components/JoSearch/JoSearch.tsx @@ -1,34 +1,41 @@ "use client" -import { SearchJoResult, SearchJoResultRequest, fetchJos } from "@/app/api/jo/actions"; +import { SearchJoResultRequest, fetchJos, updateJo } from "@/app/api/jo/actions"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Criterion } from "../SearchBox"; import SearchResults, { Column, defaultPagingController } from "../SearchResults/SearchResults"; import { EditNote } from "@mui/icons-material"; -import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; +import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil"; import { orderBy, uniqBy, upperFirst } from "lodash"; import SearchBox from "../SearchBox/SearchBox"; import { useRouter } from "next/navigation"; import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; -import { JoDetail } from "@/app/api/jo"; +import { StockInLineInput } from "@/app/api/stockIn"; +import { JobOrder, JoStatus } from "@/app/api/jo"; import { Button, Stack } from "@mui/material"; import { BomCombo } from "@/app/api/bom"; import JoCreateFormModal from "./JoCreateFormModal"; import AddIcon from '@mui/icons-material/Add'; +import QcStockInModal from "../PoDetail/QcStockInModal"; +import { useSession } from "next-auth/react"; +import { SessionWithTokens } from "@/config/authConfig"; +import { createStockInLine } from "@/app/api/stockIn/actions"; +import { msg } from "../Swal/CustomAlerts"; +import dayjs from "dayjs"; interface Props { defaultInputs: SearchJoResultRequest, bomCombo: BomCombo[] } -type SearchQuery = Partial>; +type SearchQuery = Partial>; type SearchParamNames = keyof SearchQuery; const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { const { t } = useTranslation("jo"); const router = useRouter() - const [filteredJos, setFilteredJos] = useState([]); + const [filteredJos, setFilteredJos] = useState([]); const [inputs, setInputs] = useState(defaultInputs); const [pagingController, setPagingController] = useState( defaultPagingController @@ -38,28 +45,28 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { const searchCriteria: Criterion[] = useMemo(() => [ { label: t("Code"), paramName: "code", type: "text" }, - { label: t("Item Name"), paramName: "name", type: "text" }, + { label: t("Item Name"), paramName: "itemName", type: "text" }, ], [t]) - const columns = useMemo[]>( + const columns = useMemo[]>( () => [ - { - name: "id", - label: t("Details"), - onClick: (record) => onDetailClick(record), - buttonIcon: , - }, { name: "code", label: t("Code") }, { - name: "itemCode", - label: t("Item Code") + name: "item", + label: t("Item Code"), + renderCell: (row) => { + return t(row.item.code) + } }, { - name: "name", + name: "itemName", label: t("Item Name"), + renderCell: (row) => { + return t(row.item.name) + } }, { name: "reqQty", @@ -71,12 +78,12 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { } }, { - name: "uom", + name: "item", label: t("UoM"), align: "left", headerAlign: "left", renderCell: (row) => { - return t(row.uom) + return t(row.item.uom.udfudesc) } }, { @@ -85,17 +92,69 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { renderCell: (row) => { return t(upperFirst(row.status)) } - } + }, + { + // TODO put it inside Action Buttons + name: "id", + label: t("Actions"), + // onClick: (record) => onDetailClick(record), + // buttonIcon: , + renderCell: (row) => { + const btnSx = getButtonSx(row); + return ( + + ) + } + }, ], [] ) + const handleUpdate = useCallback(async (jo: JobOrder) => { + console.log(jo); + try { + // setIsUploading(true) + if (jo.id) { + const response = await updateJo({ id: jo.id, status: "storing" }); + console.log(`%c Updated JO:`, "color:lime", response); + const postData = { + itemId: jo?.item?.id!!, + acceptedQty: jo?.reqQty ?? 1, + productLotNo: jo?.code, + productionDate: arrayToDateString(dayjs(), "input"), + jobOrderId: jo?.id, + // acceptedQty: secondReceiveQty || 0, + // acceptedQty: row.acceptedQty, + }; + const res = await createStockInLine(postData); + console.log(`%c Created Stock In Line`, "color:lime", res); + msg(t("update success")); + refetchData(defaultInputs, "search"); + } + + } catch (e) { + // backend error + // setServerError(t("An error has occurred. Please try again later.")); + console.log(e); + } finally { + // setIsUploading(false) + } + }, []) + const refetchData = useCallback(async ( query: Record | SearchJoResultRequest, actionType: "reset" | "search" | "paging", ) => { const params: SearchJoResultRequest = { code: query.code, - name: query.name, + itemName: query.itemName, pageNum: pagingController.pageNum - 1, pageSize: pagingController.pageSize, } @@ -124,14 +183,69 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { searchDataByPage(); }, [pagingController]); - const onDetailClick = useCallback((record: SearchJoResult) => { - router.push(`/jo/edit?id=${record.id}`) + const getButtonSx = (jo : JobOrder) => { // TODO put it in ActionButtons.ts + const joStatus = jo.status?.toLowerCase(); + const silStatus = jo.stockInLineStatus?.toLowerCase(); + let btnSx = {label:"", color:""}; + switch (joStatus) { + case "planning": btnSx = {label: t("release jo"), color:"primary.main"}; break; + case "pending": btnSx = {label: t("scan picked material"), color:"error.main"}; break; + case "processing": btnSx = {label: t("complete jo"), color:"warning.main"}; break; + // case "packaging": + // case "storing": btnSx = {label: t("view putaway"), color:"secondary.main"}; break; + case "storing": + switch (silStatus) { + case "pending": btnSx = {label: t("process epqc"), color:"primary.main"}; break; + case "received": btnSx = {label: t("view putaway"), color:"secondary.main"}; break; + case "escalated": + if (sessionToken?.id == jo.silHandlerId) { + btnSx = {label: t("escalation processing"), color:"warning.main"}; + break; + } + default: btnSx = {label: t("view stockin"), color:"info.main"}; + } + break; + case "completed": btnSx = {label: t("view stockin"), color:"info.main"}; break; + default: btnSx = {label: t("scan picked material"), color:"success.main"}; + } + return btnSx + }; + + const { data: session } = useSession(); + const sessionToken = session as SessionWithTokens | null; + + const [openModal, setOpenModal] = useState(false); + const [modalInfo, setModalInfo] = useState(); + + const onDetailClick = useCallback((record: JobOrder) => { + + if (record.status == "processing") { + handleUpdate(record) + } else if (record.status == "storing" || record.status == "completed") { + if (record.stockInLineId != null) { + const data = { + id: record.stockInLineId, + } + setModalInfo(data); + setOpenModal(true); + } else { alert('Invalid Stock In Line Id'); } + } else { + router.push(`/jo/edit?id=${record.id}`) + } }, []) + const closeNewModal = useCallback(() => { + // const response = updateJo({ id: 1, status: "storing" }); + setOpenModal(false); // Close the modal first + // setTimeout(() => { + // }, 300); // Add a delay to avoid immediate re-trigger of useEffect + refetchData(defaultInputs, "search"); + }, []); + const onSearch = useCallback((query: Record) => { setInputs(() => ({ code: query.code, - name: query.name + itemName: query.itemName })) refetchData(query, "search"); }, []) @@ -170,7 +284,7 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { onSearch={onSearch} onReset={onReset} /> - + items={filteredJos} columns={columns} setPagingController={setPagingController} @@ -184,6 +298,15 @@ const JoSearch: React.FC = ({ defaultInputs, bomCombo }) => { onClose={onCloseCreateJoModal} onSearch={searchDataByPage} /> + + } diff --git a/src/components/PoDetail/PutAwayForm.tsx b/src/components/PoDetail/PutAwayForm.tsx index 89ee121..646d59a 100644 --- a/src/components/PoDetail/PutAwayForm.tsx +++ b/src/components/PoDetail/PutAwayForm.tsx @@ -392,9 +392,9 @@ const PutAwayForm: React.FC = ({ itemDetail, warehouse=[], disabled, setR diff --git a/src/components/PoDetail/QcComponent.tsx b/src/components/PoDetail/QcComponent.tsx index 4802529..eb227a3 100644 --- a/src/components/PoDetail/QcComponent.tsx +++ b/src/components/PoDetail/QcComponent.tsx @@ -104,6 +104,11 @@ const QcComponent: React.FC = ({ itemDetail, disabled = false }) => { const [qcHistory, setQcHistory] = useState([]); const [qcResult, setQcResult] = useState([]); + const detailMode = useMemo(() => { + const isDetailMode = itemDetail.status == "escalated" || isNaN(itemDetail.jobOrderId); + return isDetailMode; + }, [itemDetail]); + // const [qcAccept, setQcAccept] = useState(true); // const [qcItems, setQcItems] = useState(dummyQCData) @@ -610,7 +615,7 @@ const QcComponent: React.FC = ({ itemDetail, disabled = false }) => { } label="接受來貨" /> - {(itemDetail.status == "escalated"|| (disabled && accQty != itemDetail.acceptedQty && qcDecision == 1)) && ( //TODO Improve + {(detailMode || (disabled && accQty != itemDetail.acceptedQty && qcDecision == 1)) && ( //TODO Improve = ({ itemDetail, disabled = false }) => { label={t("rejectQty")} sx={{ width: '150px' }} value={ - (!Boolean(errors.acceptQty)) ? + (!Boolean(errors.acceptQty) && qcDecision !== undefined) ? (qcDecision == 1 ? itemDetail.acceptedQty - accQty : itemDetail.acceptedQty) : "" } @@ -673,7 +678,7 @@ const QcComponent: React.FC = ({ itemDetail, disabled = false }) => { } sx={{"& .Mui-checked": {color: "red"}}} - label= {itemDetail.status == "escalated" ? "全部拒絕並退貨" : "不接受並退貨"} /> + label= {detailMode ? "全部拒絕並退貨" : "不接受並退貨"} /> {(itemDetail.status == "pending" || disabled) && (<> { warehouse?: any[]; printerCombo: PrinterCombo[]; onClose: () => void; + skipQc?: Boolean; } interface Props extends CommonProps { // itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; @@ -76,6 +78,7 @@ const PoQcStockInModalVer2: React.FC = ({ session, warehouse, printerCombo, + skipQc = false, }) => { const { t, @@ -84,6 +87,7 @@ const PoQcStockInModalVer2: React.FC = ({ const [stockInLineInfo, setStockInLineInfo] = useState(); const [isLoading, setIsLoading] = useState(false); + // const [skipQc, setSkipQc] = useState(false); // const [viewOnly, setViewOnly] = useState(false); // Select Printer @@ -110,6 +114,8 @@ const PoQcStockInModalVer2: React.FC = ({ } else throw("Result is undefined"); } catch (e) { console.log("%c Error when fetching Stock In Line: ", "color:red", e); + alert("Something went wrong, please retry"); + closeHandler({}, "backdropClick"); } },[fetchStockInLineInfo, inputDetail] ); @@ -129,6 +135,8 @@ const PoQcStockInModalVer2: React.FC = ({ // } else throw("Result is undefined"); } catch (e) { console.log("%c Error when fetching Qc Result: ", "color:red", e); + // alert("Something went wrong, please retry"); + // closeHandler({}, "backdropClick"); } },[fetchQcResult] ); @@ -145,6 +153,8 @@ const PoQcStockInModalVer2: React.FC = ({ } else throw("Result is undefined"); } catch (e) { console.log("%c Error when fetching EscalationLog: ", "color:red", e); + // alert("Something went wrong, please retry"); + // closeHandler({}, "backdropClick"); } },[fetchEscalationLogsByStockInLines] ); @@ -334,10 +344,10 @@ const PoQcStockInModalVer2: React.FC = ({ } } // Check if dates are input - if (data.productionDate === undefined || data.productionDate == null) { - alert("請輸入生產日期!"); - return; - } + // if (data.productionDate === undefined || data.productionDate == null) { + // alert("請輸入生產日期!"); + // return; + // } if (data.expiryDate === undefined || data.expiryDate == null) { alert("請輸入到期日!"); return; @@ -357,7 +367,7 @@ const PoQcStockInModalVer2: React.FC = ({ // validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(', ')}`); } - if (validationErrors.length > 0) { + if (validationErrors.length > 0 && !skipQc) { console.error("QC Validation failed:", validationErrors); alert(`未完成品檢: ${validationErrors}`); return; @@ -531,6 +541,25 @@ const PoQcStockInModalVer2: React.FC = ({ // return isPassed // }, [acceptQty, formProps]) + const printQrcode = useCallback( + async () => { + setIsPrinting(true); + try { + const postData = { stockInLineIds: [stockInLineInfo?.id] }; + const response = await fetchPoQrcode(postData); + if (response) { + console.log(response); + downloadFile(new Uint8Array(response.blobValue), response.filename!); + } + } catch (e) { + console.log("%c Error downloading QR Code", "color:red", e); + } finally { + setIsPrinting(false); + } + }, + [stockInLineInfo], + ); + return ( <> @@ -577,12 +606,17 @@ const PoQcStockInModalVer2: React.FC = ({ {t("Delivery Detail")} - - {stockInLineInfo.qcResult ? + {stockInLineInfo.jobOrderId ? ( + + ) : ( + + ) + } + {skipQc === false && (stockInLineInfo.qcResult ? : + /> : ) } {(!viewOnly && !showPutaway) && ()} @@ -653,6 +687,17 @@ const PoQcStockInModalVer2: React.FC = ({ > {isPrinting ? t("Printing") : t("print")} + )} ) : } diff --git a/src/components/PutAwayScan/PutAwayModal.tsx b/src/components/PutAwayScan/PutAwayModal.tsx index 4c9268a..c337849 100644 --- a/src/components/PutAwayScan/PutAwayModal.tsx +++ b/src/components/PutAwayScan/PutAwayModal.tsx @@ -35,6 +35,7 @@ import { arrayToDateString, INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import { QrCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; import { msg } from "../Swal/CustomAlerts"; import { PutAwayRecord } from "."; +import FgStockInForm from "../StockIn/FgStockInForm"; interface Props extends Omit { @@ -337,7 +338,11 @@ const PutAwayModal: React.FC = ({ open, onClose, warehouse, stockInLineId 處理上架 - + {itemDetail.jobOrderId ? ( + + ) : ( + + )} , EntryError>; + +const textfieldSx = { + width: "100%", + "& .MuiInputBase-root": { + // height: "120", // Scales with root font size + height: "5rem", // Scales with root font size + }, + "& .MuiInputBase-input": { + height: "100%", + boxSizing: "border-box", + padding: "0.75rem", + fontSize: 24, + }, + "& .MuiInputLabel-root": { + fontSize: 24, + transform: "translate(14px, 1.5rem) scale(1)", + "&.MuiInputLabel-shrink": { + fontSize: 18, + transform: "translate(14px, -9px) scale(1)", + }, + // [theme.breakpoints.down("sm")]: { + // fontSize: "1rem", + // transform: "translate(14px, 1.5rem) scale(1)", + // "&.MuiInputLabel-shrink": { + // fontSize: "0.875rem", + // }, + // }, + }, +}; + +const FgStockInForm: React.FC = ({ + // qc, + itemDetail, + disabled, + putawayMode = false, +}) => { + const { + t, + i18n: { language }, + } = useTranslation("purchaseOrder"); + const apiRef = useGridApiRef(); + const { + register, + formState: { errors, defaultValues, touchedFields }, + watch, + control, + setValue, + getValues, + reset, + resetField, + setError, + clearErrors, + } = useFormContext(); + // console.log(itemDetail); + + useEffect(() => { + // console.log("triggered"); + // // receiptDate default tdy + // setValue("receiptDate", dayjs().add(0, "month").format(INPUT_DATE_FORMAT)); + // setValue("status", "received"); + }, [setValue]); + + useEffect(() => { + console.log(errors); + }, [errors]); + + const productionDate = watch("productionDate"); + const expiryDate = watch("expiryDate"); + const uom = watch("uom"); + + //// TODO : Add Checking //// + // Check if dates are input + // if (data.productionDate === undefined || data.productionDate == null) { + // validationErrors.push("請輸入生產日期!"); + // } + // if (data.expiryDate === undefined || data.expiryDate == null) { + // validationErrors.push("請輸入到期日!"); + // } + + useEffect(() => { + // console.log(uom); + // console.log(productionDate); + // console.log(expiryDate); + if (expiryDate) clearErrors(); + if (productionDate) clearErrors(); + }, [productionDate, expiryDate, clearErrors]); + + useEffect(() => { + console.log("%c StockInForm itemDetail update: ", "color: brown", itemDetail); + }, [itemDetail]); + + return ( + + {/* + + {t("Stock In Detail")} + + */} + + {putawayMode && ( + + + + ) + } + + + + + {putawayMode || ( + <> + + { + return ( + + { + if (!date) return; + // setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); + field.onChange(date); + }} + inputRef={field.ref} + slotProps={{ + textField: { + // required: true, + error: Boolean(errors.receiptDate?.message), + helperText: errors.receiptDate?.message, + }, + }} + /> + + ); + }} + /> + + + )} + + {putawayMode ? ( + ) : ( + + ) + } + + {/* {putawayMode || (<> + + { + return ( + + { + if (!date) return; + setValue( + "productionDate", + date.format(INPUT_DATE_FORMAT), + ); + // field.onChange(date); + }} + inputRef={field.ref} + slotProps={{ + textField: { + // required: true, + error: Boolean(errors.productionDate?.message), + helperText: errors.productionDate?.message, + }, + }} + /> + + ); + }} + /> + + + + + )} */} + + { + return ( + + { + if (!date) return; + console.log(date.format(INPUT_DATE_FORMAT)); + setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); + // field.onChange(date); + }} + inputRef={field.ref} + slotProps={{ + textField: { + // required: true, + error: Boolean(errors.expiryDate?.message), + helperText: errors.expiryDate?.message, + }, + }} + /> + + ); + }} + /> + + {/* + {putawayMode ? ( + + ) : ( + + )} + */} + + + + + {putawayMode ? ( + sum + p.qty, 0) ?? 0} + // disabled={true} + // disabled={disabled} + // error={Boolean(errors.acceptedQty)} + // helperText={errors.acceptedQty?.message} + /> + ) : ( + + )} + + {/* + + */} + + + {/* + + apiRef={apiRef} + checkboxSelection={false} + _formKey={"qcCheck"} + columns={columns} + validateRow={validationTest} + /> + */} + + + ); +}; +export default FgStockInForm; diff --git a/src/i18n/zh/jo.json b/src/i18n/zh/jo.json index 2f21018..70b2997 100644 --- a/src/i18n/zh/jo.json +++ b/src/i18n/zh/jo.json @@ -3,25 +3,37 @@ "Create Job Order": "創建工單", "Edit Job Order Detail": "編輯工單", "Details": "細節", + "Actions": "操作", "Code": "工單編號", "Name": "成品/半成品名稱", "Picked Qty": "已提料數量", "Req. Qty": "需求數量", "UoM": "銷售單位", - "Status": "來貨狀態", + "Status": "工單狀態", "Lot No.": "批號", "Bom": "物料清單", "Release": "放單", "Pending": "待掃碼", "Pending for pick": "待提料", "Planning": "計劃中", - "Scanned": "已掃碼", "Processing": "已開始工序", - "Storing": "入倉中", + "Storing": "成品入倉中", "completed": "已完成", "Completed": "已完成", "Cancel": "取消", "Create": "創建", + + "view stockin": "查看入倉詳情", + "view putaway": "查看上架詳情", + "process epqc": "進行成品檢驗", + "scan picked material": "掃碼確認提料", + "escalation processing": "處理上報記錄", + "process stockIn": "進行收貨程序", + "release jo": "確認發佈工單", + "complete jo": "完成工單", + "update success": "成功更新資料", + + "Scanned": "已掃碼", "Scan Status": "掃碼狀態", "Start Job Order": "開始工單", "Target Production Date" : "預計生產日期", @@ -80,7 +92,7 @@ "Scanning...": "掃碼中", "Unassigned Job Orders": "未分配工單", "Please scan the item qr code": "請掃描物料二維碼", - "Please make sure the qty is enough": "請確保物料數量是足夠", + "Please make sure the qty is enough": "物料數量不足", "Please make sure all required items are picked": "請確保所有物料已被提取", "Do you want to start job order": "是否開始工單", "Submit": "提交", diff --git a/src/i18n/zh/purchaseOrder.json b/src/i18n/zh/purchaseOrder.json index 2fbe0b7..b69bb24 100644 --- a/src/i18n/zh/purchaseOrder.json +++ b/src/i18n/zh/purchaseOrder.json @@ -45,6 +45,7 @@ "processedQty": "已上架數量", "expiryDate": "到期日", "acceptedQty": "本批收貨數量", + "acceptedPutawayQty": "本批上架數量", "putawayQty": "上架數量", "acceptQty": "揀收數量", "printQty": "列印數量", @@ -151,5 +152,9 @@ "Qc Decision": "品檢詳情", "Print Qty": "列印數量", "putawayDatetime": "上架時間", - "putawayUser": "上架同事" + "putawayUser": "上架同事", + "joCode": "工單編號", + "salesUnit": "銷售單位", + "download Qr Code": "下載QR碼", + "downloading": "下載中" }