Ver a proveniência

update escalation

update po input
master
kelvinsuen há 4 dias
ascendente
cometimento
f1aeb48ec3
15 ficheiros alterados com 277 adições e 120 eliminações
  1. +2
    -0
      src/app/api/escalation/index.ts
  2. +1
    -0
      src/app/api/po/actions.ts
  3. +7
    -1
      src/app/api/user/actions.ts
  4. +1
    -1
      src/app/api/user/index.ts
  5. +9
    -1
      src/app/utils/formatUtil.ts
  6. +1
    -1
      src/components/DashboardPage/DashboardPage.tsx
  7. +95
    -29
      src/components/DashboardPage/escalation/EscalationLogTable.tsx
  8. +89
    -61
      src/components/PoDetail/EscalationComponent.tsx
  9. +10
    -5
      src/components/PoDetail/PoDetail.tsx
  10. +5
    -5
      src/components/PoDetail/PoDetailWrapper.tsx
  11. +13
    -5
      src/components/PoDetail/PoInputGrid.tsx
  12. +25
    -3
      src/components/PoDetail/QcComponent.tsx
  13. +5
    -3
      src/components/PoDetail/QcStockInModalVer2.tsx
  14. +9
    -2
      src/i18n/zh/dashboard.json
  15. +5
    -3
      src/i18n/zh/purchaseOrder.json

+ 2
- 0
src/app/api/escalation/index.ts Ver ficheiro

@@ -15,6 +15,8 @@ export interface EscalationResult {
poId?: number;
reason?: string;
handlerId?: number;
status: string;
recordDate: string;
itemName?: string;
demandQty?: number;
acceptedQty?: number;


+ 1
- 0
src/app/api/po/actions.ts Ver ficheiro

@@ -42,6 +42,7 @@ export interface PurchaseQcResult{
qcPassed?: boolean;
failQty?: number;
remarks?: string;
escalationLogId?: number;
}
export interface StockInInput {
status: string;


+ 7
- 1
src/app/api/user/actions.ts Ver ficheiro

@@ -8,7 +8,7 @@ import {
} from "../../utils/fetchUtil";
import { BASE_API_URL } from "../../../config/api";
import { revalidateTag } from "next/cache";
import { UserDetail, UserResult } from ".";
import { EscalationCombo, UserDetail, UserResult } from ".";
import { cache } from "react";

export interface UserInputs {
@@ -102,3 +102,9 @@ export const adminChangePassword = async (data: any) => {
},
);
};

export const fetchEscalationCombo = async () => {
return serverFetchJson<EscalationCombo>(`${BASE_API_URL}/user/escalation-combo`, {
next: { tags: ["escalationCombo"]}
})
};

+ 1
- 1
src/app/api/user/index.ts Ver ficheiro

@@ -67,7 +67,7 @@ export const fetchPwRules = cache(async () => {
});

export const fetchEscalationCombo = cache(async () => {
return serverFetchJson<EscalationCombo>(`${BASE_API_URL}/user/escalation-combo`, {
return serverFetchJson<EscalationCombo[]>(`${BASE_API_URL}/user/escalation-combo`, {
next: { tags: ["escalationCombo"]}
})
})

+ 9
- 1
src/app/utils/formatUtil.ts Ver ficheiro

@@ -36,7 +36,7 @@ export const INPUT_TIME_FORMAT = "HH:mm:ss";

export const OUTPUT_TIME_FORMAT = "HH:mm:ss";

export const arrayToDayjs = (arr: ConfigType | (number | undefined)[]) => {
export const arrayToDayjs = (arr: ConfigType | (number | undefined)[], showTime: boolean = false) => {
const isValidNumber = (
item: ListIterateeCustom<number | undefined, boolean>,
): boolean => typeof item === "number" && !isNaN(item) && isFinite(item);
@@ -47,6 +47,10 @@ export const arrayToDayjs = (arr: ConfigType | (number | undefined)[]) => {
// [year, month, day]
// tempArr = take(arr, 3);
tempArr = `${arr[0]?.toString().padStart(4, "0")}-${arr[1]?.toString().padStart(2, "0")}-${arr[2]?.toString().padStart(2, "0")}`;
if (showTime) {
// [year, month, day, hour, minute, second]
tempArr += ` ${arr[3]?.toString().padStart(2, "0")}-${arr[4]?.toString().padStart(2, "0")}-${arr[5]?.toString().padStart(2, "0")}`;
}
}

return dayjs(tempArr as ConfigType);
@@ -56,6 +60,10 @@ export const arrayToDateString = (arr: ConfigType | (number | undefined)[]) => {
return arrayToDayjs(arr).format(OUTPUT_DATE_FORMAT);
};

export const arrayToDateTimeString = (arr: ConfigType | (number | undefined)[]) => {
return arrayToDayjs(arr, true).format(`${OUTPUT_DATE_FORMAT} ${OUTPUT_TIME_FORMAT}`);
};

export const arrayToInputDateString = (arr: ConfigType | (number | undefined)[]) => {
return arrayToDayjs(arr).format(INPUT_DATE_FORMAT);
};


+ 1
- 1
src/components/DashboardPage/DashboardPage.tsx Ver ficheiro

@@ -33,7 +33,7 @@ const DashboardPage: React.FC<Props> = ({
<ThemeProvider theme={theme}>
<Grid container spacing={2}>
<Grid item xs={12}>
<CollapsibleCard title={t("Escalation List")}>
<CollapsibleCard title={t("My Escalation List")}>
<CardContent>
<EscalationLogTable items={escalationLogs || []}/>
</CardContent>


+ 95
- 29
src/components/DashboardPage/escalation/EscalationLogTable.tsx Ver ficheiro

@@ -8,7 +8,7 @@ import { useTranslation } from "react-i18next";
import { EscalationResult } from "@/app/api/escalation";
import { Column } from "@/components/SearchResults";
import SearchResults from "@/components/SearchResults/SearchResults";
import { arrayToDateString } from "@/app/utils/formatUtil";
import { arrayToDateString, arrayToDateTimeString } from "@/app/utils/formatUtil";

export type IQCItems = {
id: number;
@@ -22,11 +22,12 @@ export type IQCItems = {
};

type Props = {
type?: "dashboard" | "qc";
items: EscalationResult[];
};

const EscalationLogTable: React.FC<Props> = ({
items
type = "dashboard", items
}) => {
const { t } = useTranslation("dashboard");
const CARD_HEADER = t("stock in escalation list")
@@ -58,19 +59,66 @@ const EscalationLogTable: React.FC<Props> = ({
// [navigateTo]
// );

const columns = useMemo<Column<EscalationResult>[]>(
const base_col = useMemo<Column<EscalationResult>[]>(
() => [
{
name: "handler",
label: t("Responsible for handling colleagues"),
sx: { width: "20%", minWidth: 200, maxWidth: 500 },
name: "qcFailCount",
label: t("QC Fail Count"),
align: "right",
headerAlign: "right",
sx: { width: "10%", minWidth: 120 },
renderCell: (params) => {
return `${params.qcFailCount} / ${params.qcTotalCount}`
}
},
{
name: "reason",
label: t("Reason"),
sx: { width: "30%", minWidth: 150 },
},
{
name: "status",
label: t("escalationStatus"),
sx: { width: "10%", minWidth: 150 },
renderCell: (params) => {
return t(params.status);
// return t(`${params.status}`);
}
},
], [])

const columns_dashboard = useMemo<Column<EscalationResult>[]>(
() => [
{
name: "poCode",
label: t("Po Code"),
align: "left",
headerAlign: "left",
sx: { width: "15%", minWidth: 100 },
},
{
name: "recordDate",
label: t("escalated date"),
align: "right",
headerAlign: "right",
sx: { width: "10%", minWidth: 100 },
renderCell: (params) => {
return arrayToDateString(params.recordDate);
}
},
{
name: "itemName",
label: t("Item Name"),
align: "left",
headerAlign: "left",
sx: { width: "15%", minWidth: 100 },
},
{
name: "acceptedQty",
label: t("Received Qty"),
align: "right",
headerAlign: "right",
sx: { width: "10%", minWidth: 100 },
sx: { width: "5%", minWidth: 100 },
},
{
name: "purchaseUomDesc",
@@ -85,37 +133,55 @@ const EscalationLogTable: React.FC<Props> = ({
return params.dnDate ? arrayToDateString(params.dnDate) : "N/A"
}
},
...base_col
], [])
const columns_qc = useMemo<Column<EscalationResult>[]>(
() => [
{
name: "qcFailCount",
label: t("QC Fail Count"),
name: "handler",
label: t("Responsible for handling colleagues"),
sx: { width: "20%", minWidth: 200, maxWidth: 500 },
renderCell: (params) => {
const department = params.handlerDepartment;
const name = params.handlerName;
const title = params.handlerTitle;
return (
(department ? `${department} - ` : "") + name + (title ? ` (${title})` : "")
);
}
},
{
name: "recordDate",
label: t("escalated date"),
align: "right",
headerAlign: "right",
sx: { width: "15%", minWidth: 120 },
sx: { width: "10%", minWidth: 100 },
renderCell: (params) => {
return `${params.qcFailCount} / ${params.qcTotalCount}`
return arrayToDateString(params.recordDate);
}
},
// {
// name: "qcTotalCount",
// label: t("QC Completed Count"),
// align: "right",
// headerAlign: "right"
// flex: 1,
// },
// {
// name: "qcFailCount",
// label: t("QC Fail Count"),
// align: "right",
// headerAlign: "right"
// flex: 1,
// },
{
name: "reason",
label: t("Reason"),
sx: { width: "30%", minWidth: 150 },
name: "acceptedQty",
label: t("Received Qty"),
align: "right",
headerAlign: "right",
sx: { width: "5%", minWidth: 100 },
},
{
name: "purchaseUomDesc",
label: t("Purchase UoM"),
sx: { width: "15%", minWidth: 120 },
},
...base_col
], [])

const getColumnByType = (type : Props['type']) => {
switch (type) {
case "qc": return columns_qc;
default: return columns_dashboard;
}
}
{/* return (
<TableContainer component={Paper}>
<Table aria-label="Two column navigable table" size="small">
@@ -158,7 +224,7 @@ const EscalationLogTable: React.FC<Props> = ({
<SearchResults
onRowClick={onRowClick}
items={items}
columns={columns}
columns={getColumnByType(type)}
isAutoPaging={false}
/>
)


+ 89
- 61
src/components/PoDetail/EscalationComponent.tsx Ver ficheiro

@@ -1,4 +1,4 @@
import React, { useState, ChangeEvent, FormEvent, Dispatch } from 'react';
import React, { useState, ChangeEvent, FormEvent, Dispatch, useEffect } from 'react';
import {
Box,
Button,
@@ -21,8 +21,10 @@ import { SelectChangeEvent } from '@mui/material/Select';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import { useTranslation } from 'react-i18next';
import { useFormContext } from 'react-hook-form';
import { Controller, useFormContext } from 'react-hook-form';
import { EscalationInput, ModalFormInput } from '@/app/api/po/actions';
import { EscalationCombo } from "@/app/api/user";
import { FireExtinguisher } from '@mui/icons-material';

interface NameOption {
value: string;
@@ -39,15 +41,17 @@ interface Props {
forSupervisor: boolean
isCollapsed: boolean
setIsCollapsed: Dispatch<React.SetStateAction<boolean>>
escalationCombo: EscalationCombo[]
}

const EscalationComponent: React.FC<Props> = ({
const EscalationComponent: React.FC<Props> = ({
forSupervisor,
isCollapsed,
setIsCollapsed
}) => {
setIsCollapsed,
escalationCombo
}) => {
const { t } = useTranslation("purchaseOrder");
const [formData, setFormData] = useState<FormData>({
name: '',
quantity: '',
@@ -74,7 +78,7 @@ const EscalationComponent: React.FC<Props> = ({
resetField,
setError,
clearErrors,
} = useFormContext<ModalFormInput>();
} = useFormContext<ModalFormInput>();

const handleInputChange = (
event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement> | SelectChangeEvent<string>
@@ -86,7 +90,8 @@ const EscalationComponent: React.FC<Props> = ({
}));
};

const handleSubmit = (e: FormEvent<HTMLFormElement>): void => {console.log("called this?");
const handleSubmit = (e: FormEvent<HTMLFormElement>): void => {
console.log("Handled Submit?");
e.preventDefault();
console.log('表單已提交:', formData);
// 處理表單提交
@@ -99,9 +104,9 @@ const EscalationComponent: React.FC<Props> = ({
return (
// <Paper elevation={3} sx={{ maxWidth: 400, mx: 'auto', p: 3 }}>
<>
<Paper sx={{padding: 2}}>
{/* <Paper elevation={3} sx={{ mx: 'auto', p: 3 }}> */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
<Paper sx={{ padding: 2 }}>
{/* <Paper elevation={3} sx={{ mx: 'auto', p: 3 }}> */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Typography variant="body1">上報結果</Typography>
{/* {isCollapsed ? (
@@ -110,7 +115,7 @@ const EscalationComponent: React.FC<Props> = ({
<ExpandMoreIcon sx={{ ml: 1 }} />
)} */}
</Box>
{/* <FormControlLabel
{/* <FormControlLabel
control={
<Checkbox
checked={isCollapsed}
@@ -129,11 +134,34 @@ const EscalationComponent: React.FC<Props> = ({
</Box>
}
/> */}
</Box>
<Collapse in={isCollapsed}>
<Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<FormControl fullWidth>
<select
</Box>
<Collapse in={isCollapsed}>
<Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<FormControl fullWidth>
<Controller
control={control}
name="escalationLog.handlerId"
render={({field, fieldState, formState}) => {
return (<Autocomplete
noOptionsText={t("No Option")}
disableClearable
fullWidth
// value={}
// {...register("escalationLog.handlerId", {
// required: "handler required!",
// })}
// onChange={() => handleInputChange}
onChange={(event, value) => {
field.onChange(value.id);
}}
// getOptionLabel={(option) => option.label}
options={escalationCombo}
renderInput={(params) => <TextField {...params} error={false} label={"負責處理同事"}/>}
/>)
}}

/>
{/* <select
id="handlerId"
// name="name"
// value={formData.name}
@@ -148,33 +176,33 @@ const EscalationComponent: React.FC<Props> = ({
{option.label}
</option>
))}
</select>
</FormControl>
{forSupervisor ? (
<FormControl>
<RadioGroup
row
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="pass"
name="radio-buttons-group"
>
<FormControlLabel value="pass" control={<Radio />} label="合格" />
<FormControlLabel value="fail" control={<Radio />} label="不合格" />
</RadioGroup>
</select> */}
</FormControl>
): undefined}
{forSupervisor && (<TextField
fullWidth
id="decision"
name="decision"
label="上報結果"
type="radio"
// value={formData.decision}
onChange={handleInputChange}
InputProps={{ inputProps: { min: 1 } }}
placeholder="請決定上報結果"
/>)}
{/* <TextField
{forSupervisor ? (
<FormControl>
<RadioGroup
row
aria-labelledby="demo-radio-buttons-group-label"
defaultValue="pass"
name="radio-buttons-group"
>
<FormControlLabel value="pass" control={<Radio />} label="合格" />
<FormControlLabel value="fail" control={<Radio />} label="不合格" />
</RadioGroup>
</FormControl>
) : undefined}
{forSupervisor && (<TextField
fullWidth
id="decision"
name="decision"
label="上報結果"
type="radio"
// value={formData.decision}
onChange={handleInputChange}
InputProps={{ inputProps: { min: 1 } }}
placeholder="請決定上報結果"
/>)}
{/* <TextField
fullWidth
id="quantity"
name="quantity"
@@ -186,22 +214,22 @@ const EscalationComponent: React.FC<Props> = ({
placeholder="請輸入數量"
/> */}

<TextField
fullWidth
id="reason"
// name="reason"
{...register("escalationLog.reason", {
required: "reason required!",
})}
label="上報原因"
multiline
rows={4}
// value={formData.reason}
onChange={handleInputChange}
placeholder="請輸入上報原因"
/>
<TextField
fullWidth
id="reason"
// name="reason"
{...register("escalationLog.reason", {
required: "reason required!",
})}
label="上報原因"
multiline
rows={4}
// value={formData.reason}
onChange={handleInputChange}
placeholder="請輸入上報原因"
/>

{/* <Stack direction="row" justifyContent="flex-end" gap={1}>
{/* <Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
type="submit"
variant="contained"
@@ -210,9 +238,9 @@ const EscalationComponent: React.FC<Props> = ({
{t("update qc info")}
</Button>
</Stack> */}
</Box>
</Collapse>
</Paper>
</Box>
</Collapse>
</Paper>
</>
);
}


+ 10
- 5
src/components/PoDetail/PoDetail.tsx Ver ficheiro

@@ -80,6 +80,7 @@ import { debounce } from "lodash";
import LoadingComponent from "../General/LoadingComponent";
import { getMailTemplateForStockInLine } from "@/app/api/mailTemplate/actions";
import { PrinterCombo } from "@/app/api/settings/printer";
import { EscalationCombo } from "@/app/api/user";
//import { useRouter } from "next/navigation";


@@ -88,6 +89,7 @@ type Props = {
qc: QcItemWithChecks[];
warehouse: WarehouseResult[];
printerCombo: PrinterCombo[];
escalationCombo: EscalationCombo[];
};

type EntryError =
@@ -190,7 +192,7 @@ interface PolInputResult {
dnQty: number,
}

const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo, escalationCombo }) => {
const cameras = useContext(CameraContext);
// console.log(cameras);
const { t } = useTranslation("purchaseOrder");
@@ -217,6 +219,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
useEffect(() => {
if (defaultPolId) {
setSelectedRow(rows.find((r) => r.id.toString() === defaultPolId) ?? null)
console.log("%c StockIn:", "color:green", selectedRow);
}
}, [])

@@ -263,6 +266,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
const result = await fetchPoInClient(parseInt(poId));
console.log(result)
if (result) {
console.log("%c Fetched PO:", "color:orange", result);
setPurchaseOrder(result);
setRows(result.pol || []);
if (result.pol && result.pol.length > 0) {
@@ -506,7 +510,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
<TableCell align="left">{row.itemNo}</TableCell>
<TableCell align="left">{row.itemName}</TableCell>
<TableCell align="right">{integerFormatter.format(row.qty)}</TableCell>
<TableCell align="right">{integerFormatter.format(processedQty)}</TableCell>
<TableCell align="right">{integerFormatter.format(row.processed)}</TableCell>
<TableCell align="left">{row.uom?.code}</TableCell>
{/* <TableCell align="right">{decimalFormatter.format(row.stockUom.stockQty)}</TableCell> */}
<TableCell align="right">{decimalFormatter.format(row.stockInLine.filter((sil) => sil.purchaseOrderLineId === row.id).reduce((acc, cur) => acc + (cur.acceptedQty ?? 0),0) * purchaseToStockRatio)}</TableCell>
@@ -814,7 +818,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
<TableCell align="right">{t("qty")}</TableCell>
<TableCell align="right">{t("processed")}</TableCell>
<TableCell align="left">{t("uom")}</TableCell>
<TableCell align="right">{t("Stock In Qty")}</TableCell>
<TableCell align="right">{t("receivedTotal")}</TableCell>
<TableCell align="left">{t("Stock UoM")}</TableCell>
{/* <TableCell align="right">{t("total weight")}</TableCell> */}
{/* <TableCell align="right">{`${t("price")} (HKD)`}</TableCell> */}
@@ -861,6 +865,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
fetchPoDetail={fetchPoDetail}
handleMailTemplateForStockInLine={handleMailTemplateForStockInLine}
printerCombo={printerCombo}
escalationCombo={escalationCombo}
/>
</Box>
</TableCell>
@@ -878,7 +883,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
/> */}
</Grid>
</Stack>
{itemInfo !== undefined && (
{/* {itemInfo !== undefined && (
<>
<PoQcStockInModal
type={"putaway"}
@@ -889,7 +894,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => {
itemDetail={itemInfo}
/>
</>
)}
)} */}
</>
);
};

+ 5
- 5
src/components/PoDetail/PoDetailWrapper.tsx Ver ficheiro

@@ -26,18 +26,18 @@ const PoDetailWrapper: React.FC<Props> & SubComponents = async ({ id }) => {
poWithStockInLine,
warehouse,
qc,
escalationCombo,
printerCombo,
escalationCombo,
] = await Promise.all([
fetchPoWithStockInLines(id),
fetchWarehouseList(),
fetchQcItemCheck(),
fetchEscalationCombo(),
fetchPrinterCombo()
fetchPrinterCombo(),
fetchEscalationCombo()
]);
// const poWithStockInLine = await fetchPoWithStockInLines(id)
return <PoDetail po={poWithStockInLine} qc={qc} warehouse={warehouse} printerCombo={printerCombo} />;
console.log("%c pol:", "color:green", poWithStockInLine);
return <PoDetail po={poWithStockInLine} qc={qc} warehouse={warehouse} printerCombo={printerCombo} escalationCombo={escalationCombo}/>;
};

PoDetailWrapper.Loading = PoDetailLoading;


+ 13
- 5
src/components/PoDetail/PoInputGrid.tsx Ver ficheiro

@@ -66,6 +66,7 @@ import { PrinterCombo } from "@/app/api/settings/printer";
import { EscalationResult } from "@/app/api/escalation";
import { fetchEscalationLogsByStockInLines } from "@/app/api/escalation/actions";
import { SessionWithTokens } from "@/config/authConfig";
import { EscalationCombo } from "@/app/api/user";

interface ResultWithId {
id: number;
@@ -82,6 +83,7 @@ interface Props {
fetchPoDetail: (poId: string) => void;
handleMailTemplateForStockInLine: (stockInLineId: number) => void;
printerCombo: PrinterCombo[];
escalationCombo: EscalationCombo[];
}

export type StockInLineEntryError = {
@@ -122,7 +124,8 @@ function PoInputGrid({
warehouse,
fetchPoDetail,
handleMailTemplateForStockInLine,
printerCombo
printerCombo,
escalationCombo
}: Props) {

const { t } = useTranslation("purchaseOrder");
@@ -263,8 +266,8 @@ function PoInputGrid({
}));
const qcResult = await fetchQcDefaultValue(id);
const escResult = await fetchEscalationLogsByStockInLines([Number(id)]);
console.log(params.row);
console.log(qcResult);
// console.log(params.row);
console.log("Fetched QC Result:", qcResult);
setModalInfo({
...params.row,
@@ -580,8 +583,11 @@ const closeNewModal = useCallback(() => {
const handlerId = params.row.handlerId
const status = params.row.status
return (<span style={{
color: (status == "escalated")? "red":"inherit"}}>
{t(`${params.row.status}`)}
color:
(status == "escalated")? "red":
(status == "rejected" || status == "partially_completed") ? "orange" : "inherit"}}
>
{t(`${params.row.status}`)}
</span>);
},
},
@@ -622,6 +628,7 @@ const closeNewModal = useCallback(() => {
variant="contained"
color="primary"
sx={{ width: '150px' }}
disabled={params.row.status != "rejected" && params.row.status != "partially_completed"}
onClick={() => handleMailTemplateForStockInLine(params.row.id as number)}
>
{t("email supplier")}
@@ -944,6 +951,7 @@ const closeNewModal = useCallback(() => {
itemDetail={modalInfo}
handleMailTemplateForStockInLine={handleMailTemplateForStockInLine}
printerCombo={printerCombo}
escalationCombo={escalationCombo}
/>
</>
)


+ 25
- 3
src/components/PoDetail/QcComponent.tsx Ver ficheiro

@@ -6,6 +6,7 @@ import {
Card,
CardContent,
Checkbox,
Collapse,
FormControl,
FormControlLabel,
Grid,
@@ -54,11 +55,13 @@ import { escape } from "lodash";
import { PanoramaSharp } from "@mui/icons-material";
import EscalationLogTable from "../DashboardPage/escalation/EscalationLogTable";
import { EscalationResult } from "@/app/api/escalation";
import { EscalationCombo } from "@/app/api/user";

interface Props {
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] };
qc: QcItemWithChecks[];
disabled: boolean;
escalationCombo: EscalationCombo[];
// qcItems: QcData[]
// setQcItems: Dispatch<SetStateAction<QcData[]>>
}
@@ -71,7 +74,7 @@ type EntryError =

type QcRow = TableRow<Partial<QcData>, EntryError>;
// fetchQcItemCheck
const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escalationCombo }) => {
const { t } = useTranslation("purchaseOrder");
const apiRef = useGridApiRef();
const {
@@ -95,6 +98,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
const qcDecision = watch("qcDecision"); //WIP
// const qcResult = useMemo(() => [...watch("qcResult")], [watch("qcResult")]);
const qcResult = [...watch("qcResult")];
const [qcHistory, setQcHistory] = useState<PurchaseQcResult[]>([]);

// const [qcAccept, setQcAccept] = useState(true);
// const [qcItems, setQcItems] = useState(dummyQCData)
@@ -407,6 +411,12 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
}
}

useEffect(() => {
if (qcHistory.length < 1) {
setQcHistory(qcResult.filter((qc) => {qc.escalationLogId != null}));
console.log("QC History updated:", qcHistory);
}
}, [watch("qcResult")]);
// useEffect(() => {
// // onFailedOpenCollapse(qcItems)
// }, [qcItems]);
@@ -428,7 +438,8 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
variant="scrollable"
>
<Tab label={t("QC Info")} iconPosition="end" />
<Tab label={t("Escalation History")} iconPosition="end" />
{(itemDetail.escResult && itemDetail.escResult?.length > 0) &&
(<Tab label={t("Escalation History")} iconPosition="end" />)}
</Tabs>
</Grid>
{tabIndex == 0 && (
@@ -478,7 +489,17 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
</Typography>
</Grid> */}
<Grid item xs={12}>
<EscalationLogTable items={itemDetail.escResult || []}/>
<EscalationLogTable type="qc" items={itemDetail.escResult || []}/>
{/* <Collapse in={true}> */}
<StyledDataGrid
columns={qcColumns}
rows={qcResult}
// rows={qcResult && qcResult.length > 0 ? qcResult : qcItems}
// rows={disabled? qcResult:qcItems}
autoHeight
sortModel={[]}
/>
{/* </Collapse> */}
{/* <StyledDataGrid
rows={escalationHistory}
columns={columns}
@@ -569,6 +590,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false }) => {
forSupervisor={false}
isCollapsed={isCollapsed}
setIsCollapsed={setIsCollapsed}
escalationCombo={escalationCombo}
/>
</Grid>)}
{/* {qcAccept && <Grid item xs={12}>


+ 5
- 3
src/components/PoDetail/QcStockInModalVer2.tsx Ver ficheiro

@@ -21,7 +21,6 @@ import StockInForm from "./StockInForm";
import StockInFormVer2 from "./StockInFormVer2";
import QcComponent from "./QcComponent";
import { dummyPutAwayLine, dummyQCData } from "./dummyQcTemplate";
// import QcFormVer2 from "./QcFormVer2";
import PutAwayForm from "./PutAwayForm";
import { GridRowModes, useGridApiRef } from "@mui/x-data-grid";
import {submitDialogWithWarning} from "../Swal/CustomAlerts";
@@ -34,6 +33,7 @@ import { EscalationResult } from "@/app/api/escalation";
import { SessionWithTokens } from "@/config/authConfig";
import { GridRowModesModel } from "@mui/x-data-grid";
import { isEmpty } from "lodash";
import { EscalationCombo } from "@/app/api/user";


const style = {
@@ -68,6 +68,7 @@ interface CommonProps extends Omit<ModalProps, "children"> {
// type: "qc" | "stockIn" | "escalation" | "putaway" | "reject";
handleMailTemplateForStockInLine: (stockInLineId: number) => void;
printerCombo: PrinterCombo[];
escalationCombo: EscalationCombo[];
onClose: () => void;
}
interface Props extends CommonProps {
@@ -86,7 +87,8 @@ const PoQcStockInModalVer2: React.FC<Props> = ({
qc,
warehouse,
handleMailTemplateForStockInLine,
printerCombo
printerCombo,
escalationCombo
}) => {
const {
t,
@@ -486,7 +488,6 @@ const [qcItems, setQcItems] = useState(dummyQCData)
onSubmit={formProps.handleSubmit(onSubmitPutaway)}
>
<PutAwayForm
printerCombo={printerCombo}
itemDetail={itemDetail}
warehouse={warehouse!}
disabled={viewOnly}
@@ -569,6 +570,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)
qc={qc!}
itemDetail={itemDetail}
disabled={viewOnly}
escalationCombo={escalationCombo}
// qcItems={qcItems}
// setQcItems={setQcItems}
/>


+ 9
- 2
src/i18n/zh/dashboard.json Ver ficheiro

@@ -17,7 +17,8 @@
"Purchase Order Code": "採購單號",
"Item Name": "貨品名稱",
"Escalation Level": "上報等級",
"Reason": "原因",
"Reason": "上報原因",
"escalated date": "上報日期",
"Order completion": "訂單完成度",
"Raw material": "原料",
"Consumable": "消耗品",
@@ -32,6 +33,9 @@
"Processed application": "已處理提料申請",
"Pending application": "待處理提料申請",
"pending inspection material": "待品檢物料",
"pending": "待處理",
"rejected": "已拒絕",
"escalated": "已上報",
"inspected material": "已品檢物料",
"total material": "物料總數",
"stock in escalation list": "收貨已上報列表",
@@ -40,8 +44,11 @@
"QC Fail Count": "品檢不合格數量",
"DN Date": "送貨日期",
"Received Qty": "收貨數量",
"Po Code": "採購訂單編號",
"My Escalation List": "我的上報列表",
"Escalation List": "上報列表",
"Purchase UoM": "計量單位",
"QC Completed Count": "品檢完成數量",
"QC Fail-Total Count": "品檢不合格/總數"
"QC Fail-Total Count": "品檢不合格/總數",
"escalationStatus": "上報狀態"
}

+ 5
- 3
src/i18n/zh/purchaseOrder.json Ver ficheiro

@@ -39,7 +39,7 @@
"qty": "訂單數量",
"uom": "計量單位",
"Stock UoM": "庫存單位",
"Stock In Qty": "收貨數量",
"Stock In Qty": "換算庫存數量",
"total weight": "總重量",
"weight unit": "重量單位",
"price": "訂單貨值",
@@ -105,7 +105,7 @@
"No Warehouse": "沒有倉庫",
"Please scan warehouse qr code.": "請掃描倉庫 QR 碼。",
"receivedQty": "已來貨數量",
"dnQty": "送貨單數量",
"dnQty": "本批來貨數量",
"Accept submit": "接受來貨",
"qc processing": "處理來貨及品檢",
"putaway processing": "處理來貨及上架",
@@ -138,5 +138,7 @@
"Printer": "列印機",
"Printing": "列印中",
"rejectQty": "拒絕數量",
"QC decision is required": "請決定品檢結果"
"QC decision is required": "請決定品檢結果",
"No Option": "沒有選項",
"receivedTotal": "已來貨總數"
}

Carregando…
Cancelar
Guardar