Ver a proveniência

update job order

master
cyril.tsui há 2 meses
ascendente
cometimento
396c00bfe6
5 ficheiros alterados com 71 adições e 21 eliminações
  1. +15
    -5
      src/app/api/jo/actions.ts
  2. +15
    -6
      src/components/JoSave/ActionButtons.tsx
  3. +27
    -5
      src/components/JoSave/JoSave.tsx
  4. +4
    -3
      src/components/JoSave/PickTable.tsx
  5. +10
    -2
      src/i18n/zh/jo.json

+ 15
- 5
src/app/api/jo/actions.ts Ver ficheiro

@@ -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<T> {
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<ReleaseJoResponse>(`${BASE_API_URL}/jo/release`,
export const releaseJo = cache(async (data: CommonActionJoRequest) => {
return serverFetchJson<CommonActionJoResponse>(`${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<CommonActionJoResponse>(`${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<SaveJoResponse>(`${BASE_API_URL}/jo/manualCreate`, {
method: "POST",
body: JSON.stringify(data),


+ 15
- 6
src/components/JoSave/ActionButtons.tsx Ver ficheiro

@@ -14,6 +14,7 @@ type Props = {
interface ErrorEntry {
qtyErr: boolean;
scanErr: boolean;
pickErr: boolean;
}

const ActionButtons: React.FC<Props> = ({
@@ -36,24 +37,31 @@ const ActionButtons: React.FC<Props> = ({
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 (
<Stack direction="row" justifyContent="flex-start" gap={1}>
{status === "planning" && (
@@ -71,12 +79,13 @@ const ActionButtons: React.FC<Props> = ({
variant="outlined"
startIcon={<PlayCircleFilledWhiteIcon />}
onClick={handleStart}
disabled={errors.qtyErr || errors.scanErr}
disabled={errors.qtyErr || errors.scanErr || errors.pickErr}
>
{t("Start Job Order")}
</Button>
{errors.scanErr && (<Typography variant="h3" color="error">{t("Please scan the item qr code.")}</Typography>)}
{errors.qtyErr && (<Typography variant="h3" color="error">{t("Please make sure the qty is enough.")}</Typography>)}
{errors.pickErr && (<Typography variant="h3" color="error">{t("Please make sure all required items are picked")}</Typography>)}
{errors.scanErr && (<Typography variant="h3" color="error">{t("Please scan the item qr code")}</Typography>)}
{errors.qtyErr && (<Typography variant="h3" color="error">{t("Please make sure the qty is enough")}</Typography>)}
</Box>
)}
</Stack>


+ 27
- 5
src/components/JoSave/JoSave.tsx Ver ficheiro

@@ -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<Props> = ({
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<Props> = ({
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<Props> = ({
}, [])

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 --------------------------------------------- //


+ 4
- 3
src/components/JoSave/PickTable.tsx Ver ficheiro

@@ -53,8 +53,8 @@ const PickTable: React.FC<Props> = ({
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 : <Stack direction={"column"}>{scanStatus.map((status) => scanStatusColumn(status))}</Stack>
const scanStatus = params.row.pickedLotNo.map((pln) => params.row.status === "completed" ? true : Boolean(pln.isScanned))
return isEmpty(scanStatus) ? notPickedStatusColumn : <Stack key={`${params.id}-scan`} direction={"column"}>{scanStatus.map((status) => scanStatusColumn(status))}</Stack>
},
},
{
@@ -107,10 +107,11 @@ const PickTable: React.FC<Props> = ({
align: "right",
headerAlign: "right",
renderCell: (params: GridRenderCellParams<JoDetailPickLine>) => {
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)}
</>
)
},


+ 10
- 2
src/i18n/zh/jo.json Ver ficheiro

@@ -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": "是否開始工單"
}

Carregando…
Cancelar
Guardar