From 396c00bfe6a8a28e6984d22779742db77e7ac0e1 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Mon, 29 Sep 2025 19:01:51 +0800 Subject: [PATCH 1/2] update job order --- src/app/api/jo/actions.ts | 20 ++++++++++++---- src/components/JoSave/ActionButtons.tsx | 21 +++++++++++----- src/components/JoSave/JoSave.tsx | 32 +++++++++++++++++++++---- src/components/JoSave/PickTable.tsx | 7 +++--- src/i18n/zh/jo.json | 12 ++++++++-- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/app/api/jo/actions.ts b/src/app/api/jo/actions.ts index 8113b1d..217bbc0 100644 --- a/src/app/api/jo/actions.ts +++ b/src/app/api/jo/actions.ts @@ -38,15 +38,17 @@ export interface SearchJoResult { status: JoStatus; } -export interface ReleaseJoRequest { +// For Jo Button Actions +export interface CommonActionJoRequest { id: number; } -export interface ReleaseJoResponse { +export interface CommonActionJoResponse { id: number; entity: { status: JoStatus } } +// For Jo Process export interface IsOperatorExistResponse { id: number | null; name: string; @@ -251,8 +253,17 @@ export const fetchJos = cache(async (data?: SearchJoResultRequest) => { return response }) -export const releaseJo = cache(async (data: ReleaseJoRequest) => { - return serverFetchJson(`${BASE_API_URL}/jo/release`, +export const releaseJo = cache(async (data: CommonActionJoRequest) => { + return serverFetchJson(`${BASE_API_URL}/jo/release`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }) +}) + +export const startJo = cache(async (data: CommonActionJoRequest) => { + return serverFetchJson(`${BASE_API_URL}/jo/start`, { method: "POST", body: JSON.stringify(data), @@ -261,7 +272,6 @@ export const releaseJo = cache(async (data: ReleaseJoRequest) => { }) export const manualCreateJo = cache(async (data: SaveJo) => { - console.log(data) return serverFetchJson(`${BASE_API_URL}/jo/manualCreate`, { method: "POST", body: JSON.stringify(data), diff --git a/src/components/JoSave/ActionButtons.tsx b/src/components/JoSave/ActionButtons.tsx index 480576d..12e0892 100644 --- a/src/components/JoSave/ActionButtons.tsx +++ b/src/components/JoSave/ActionButtons.tsx @@ -14,6 +14,7 @@ type Props = { interface ErrorEntry { qtyErr: boolean; scanErr: boolean; + pickErr: boolean; } const ActionButtons: React.FC = ({ @@ -36,24 +37,31 @@ const ActionButtons: React.FC = ({ const errors: ErrorEntry = useMemo(() => { let qtyErr = false; let scanErr = false; + let pickErr = false pickLines.forEach((line) => { if (!qtyErr) { const pickedQty = line.pickedLotNo?.reduce((acc, cur) => acc + cur.qty, 0) ?? 0 - qtyErr = pickedQty > 0 && pickedQty >= line.reqQty + qtyErr = pickedQty <= 0 || pickedQty < line.reqQty } if (!scanErr) { scanErr = line.pickedLotNo?.some((lotNo) => Boolean(lotNo.isScanned) === false) ?? false // default false } + + if (!pickErr) { + pickErr = line.pickedLotNo === null + } }) return { qtyErr: qtyErr, - scanErr: scanErr + scanErr: scanErr, + pickErr: pickErr } - }, [pickLines]) + }, [pickLines, status]) + console.log(pickLines) return ( {status === "planning" && ( @@ -71,12 +79,13 @@ const ActionButtons: React.FC = ({ variant="outlined" startIcon={} onClick={handleStart} - disabled={errors.qtyErr || errors.scanErr} + disabled={errors.qtyErr || errors.scanErr || errors.pickErr} > {t("Start Job Order")} - {errors.scanErr && ({t("Please scan the item qr code.")})} - {errors.qtyErr && ({t("Please make sure the qty is enough.")})} + {errors.pickErr && ({t("Please make sure all required items are picked")})} + {errors.scanErr && ({t("Please scan the item qr code")})} + {errors.qtyErr && ({t("Please make sure the qty is enough")})} )} diff --git a/src/components/JoSave/JoSave.tsx b/src/components/JoSave/JoSave.tsx index 000768c..1372bef 100644 --- a/src/components/JoSave/JoSave.tsx +++ b/src/components/JoSave/JoSave.tsx @@ -8,12 +8,13 @@ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState } fro import { Button, Stack, Typography } from "@mui/material"; import StartIcon from "@mui/icons-material/Start"; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; -import { releaseJo } from "@/app/api/jo/actions"; +import { releaseJo, startJo } from "@/app/api/jo/actions"; import InfoCard from "./InfoCard"; import PickTable from "./PickTable"; import ActionButtons from "./ActionButtons"; import { useQrCodeScannerContext } from "../QrCodeScannerProvider/QrCodeScannerProvider"; import { fetchStockInLineInfo } from "@/app/api/po/actions"; +import { submitDialog } from "../Swal/CustomAlerts"; type Props = { id?: number; @@ -93,12 +94,18 @@ const JoSave: React.FC = ({ shouldValidate: true, shouldDirty: true, }); + + // Ask user and confirm to start JO + await submitDialog(() => handleStart(), t, { + title: t("Do you want to start job order"), + confirmButtonText: t("Start Job Order") + }) } } } } finally { - scanner.resetScan() - setIsUploading(false) + scanner.resetScan() + setIsUploading(false) } }, []) @@ -126,7 +133,6 @@ const JoSave: React.FC = ({ formProps.setValue("status", response.entity.status) } } - } catch (e) { // backend error setServerError(t("An error has occurred. Please try again later.")); @@ -137,7 +143,23 @@ const JoSave: React.FC = ({ }, []) const handleStart = useCallback(async () => { - console.log("first") + try { + setIsUploading(true) + if (id) { + const response = await startJo({ id: id }) + if (response) { + formProps.setValue("status", response.entity.status) + + pickLines.map((line) => ({...line, status: "completed"})) + } + } + } catch (e) { + // backend error + setServerError(t("An error has occurred. Please try again later.")); + console.log(e); + } finally { + setIsUploading(false) + } }, []) // --------------------------------------------- Form Submit --------------------------------------------- // diff --git a/src/components/JoSave/PickTable.tsx b/src/components/JoSave/PickTable.tsx index 064b946..c0def2e 100644 --- a/src/components/JoSave/PickTable.tsx +++ b/src/components/JoSave/PickTable.tsx @@ -53,8 +53,8 @@ const PickTable: React.FC = ({ if (params.row.pickedLotNo === null || params.row.pickedLotNo === undefined) { return notPickedStatusColumn } - const scanStatus = params.row.pickedLotNo.map((pln) => Boolean(pln.isScanned)) - return isEmpty(scanStatus) ? notPickedStatusColumn : {scanStatus.map((status) => scanStatusColumn(status))} + const scanStatus = params.row.pickedLotNo.map((pln) => params.row.status === "completed" ? true : Boolean(pln.isScanned)) + return isEmpty(scanStatus) ? notPickedStatusColumn : {scanStatus.map((status) => scanStatusColumn(status))} }, }, { @@ -107,10 +107,11 @@ const PickTable: React.FC = ({ align: "right", headerAlign: "right", renderCell: (params: GridRenderCellParams) => { + const status = Boolean(params.row.pickedLotNo?.every((lotNo) => Boolean(lotNo.isScanned))) || params.row.status === "completed" return ( <> {params.row.pickedLotNo?.every((lotNo) => Boolean(lotNo.isScanned)) ? t("Scanned") : t(upperFirst(params.value))} - {scanStatusColumn(Boolean(params.row.pickedLotNo?.every((lotNo) => Boolean(lotNo.isScanned))))} + {scanStatusColumn(status)} ) }, diff --git a/src/i18n/zh/jo.json b/src/i18n/zh/jo.json index 176ef94..2785d6e 100644 --- a/src/i18n/zh/jo.json +++ b/src/i18n/zh/jo.json @@ -16,6 +16,11 @@ "Pending for pick": "待提料", "Planning": "計劃中", "Scanned": "已掃碼", + "Processing": "已開始工序", + "Storing": "入倉中", + "completed": "已完成", + "Completed": "已完成", + "Cancel": "取消", "Scan Status": "掃碼狀態", "Start Job Order": "開始工單", "Job Order Pickexcution": "工單提料", @@ -30,7 +35,6 @@ "Location": "位置", "Scan Result": "掃碼結果", "Expiry Date": "有效期", - "Pick Order Code": "提料單編號", "Target Date": "需求日期", "Lot Required Pick Qty": "批號需求數量", "Job Order Match": "工單匹配", @@ -64,5 +68,9 @@ "Second Scan Status": "對料狀態", "Job Order Pick Order Details": "工單提料單詳情", "Scanning...": "掃碼中", - "Unassigned Job Orders": "未分配工單" + "Unassigned Job Orders": "未分配工單", + "Please scan the item qr code": "請掃描物料二維碼", + "Please make sure the qty is enough": "請確保物料數量是足夠", + "Please make sure all required items are picked": "請確保所有物料已被提取", + "Do you want to start job order": "是否開始工單" } From c04a70fbff9e37940383fd6d9140cc65797f42c0 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Mon, 29 Sep 2025 19:09:41 +0800 Subject: [PATCH 2/2] quick update --- src/components/JoSave/JoSave.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/JoSave/JoSave.tsx b/src/components/JoSave/JoSave.tsx index 1372bef..1359f86 100644 --- a/src/components/JoSave/JoSave.tsx +++ b/src/components/JoSave/JoSave.tsx @@ -151,6 +151,8 @@ const JoSave: React.FC = ({ formProps.setValue("status", response.entity.status) pickLines.map((line) => ({...line, status: "completed"})) + + handleBack() } } } catch (e) {