@@ -7,6 +7,7 @@ import { cache } from "react"; | |||||
export interface EscalationResult { | export interface EscalationResult { | ||||
id: number; | id: number; | ||||
submitter?: string; | |||||
handler?: string; | handler?: string; | ||||
handlerDepartment?: string; | handlerDepartment?: string; | ||||
handlerName?: string; | handlerName?: string; | ||||
@@ -38,7 +38,8 @@ export interface StockInLineEntry { | |||||
} | } | ||||
export interface PurchaseQcResult{ | export interface PurchaseQcResult{ | ||||
id: number; | |||||
id?: number; | |||||
qcItemId: number; | |||||
qcPassed?: boolean; | qcPassed?: boolean; | ||||
failQty?: number; | failQty?: number; | ||||
remarks?: string; | remarks?: string; | ||||
@@ -16,7 +16,8 @@ export interface QcItemWithChecks { | |||||
} | } | ||||
export interface QcData { | export interface QcData { | ||||
id: number, | |||||
id?: number, | |||||
qcItemId: number, | |||||
code: string, | code: string, | ||||
name: string, | name: string, | ||||
qcDescription: string, | qcDescription: string, | ||||
@@ -104,7 +104,7 @@ export const adminChangePassword = async (data: any) => { | |||||
}; | }; | ||||
export const fetchEscalationCombo = async () => { | export const fetchEscalationCombo = async () => { | ||||
return serverFetchJson<EscalationCombo>(`${BASE_API_URL}/user/escalation-combo`, { | |||||
return serverFetchJson<EscalationCombo[]>(`${BASE_API_URL}/user/escalation-combo`, { | |||||
next: { tags: ["escalationCombo"]} | next: { tags: ["escalationCombo"]} | ||||
}) | }) | ||||
}; | }; |
@@ -89,6 +89,13 @@ const EscalationLogTable: React.FC<Props> = ({ | |||||
const columns_dashboard = useMemo<Column<EscalationResult>[]>( | const columns_dashboard = useMemo<Column<EscalationResult>[]>( | ||||
() => [ | () => [ | ||||
{ | |||||
name: "submitter", | |||||
label: t("escalateFrom"), | |||||
align: "left", | |||||
headerAlign: "left", | |||||
sx: { width: "15%", minWidth: 100 }, | |||||
}, | |||||
{ | { | ||||
name: "poCode", | name: "poCode", | ||||
label: t("Po Code"), | label: t("Po Code"), | ||||
@@ -138,6 +145,13 @@ const EscalationLogTable: React.FC<Props> = ({ | |||||
const columns_qc = useMemo<Column<EscalationResult>[]>( | const columns_qc = useMemo<Column<EscalationResult>[]>( | ||||
() => [ | () => [ | ||||
{ | |||||
name: "submitter", | |||||
label: t("escalateFrom"), | |||||
align: "left", | |||||
headerAlign: "left", | |||||
sx: { width: "15%", minWidth: 100 }, | |||||
}, | |||||
{ | { | ||||
name: "handler", | name: "handler", | ||||
label: t("Responsible for handling colleagues"), | label: t("Responsible for handling colleagues"), | ||||
@@ -153,12 +167,12 @@ const EscalationLogTable: React.FC<Props> = ({ | |||||
}, | }, | ||||
{ | { | ||||
name: "recordDate", | name: "recordDate", | ||||
label: t("escalated date"), | |||||
label: t("escalated datetime"), | |||||
align: "right", | align: "right", | ||||
headerAlign: "right", | headerAlign: "right", | ||||
sx: { width: "10%", minWidth: 100 }, | sx: { width: "10%", minWidth: 100 }, | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
return arrayToDateString(params.recordDate); | |||||
return arrayToDateTimeString(params.recordDate); | |||||
} | } | ||||
}, | }, | ||||
{ | { | ||||
@@ -24,6 +24,7 @@ import { useTranslation } from 'react-i18next'; | |||||
import { Controller, useFormContext } from 'react-hook-form'; | import { Controller, useFormContext } from 'react-hook-form'; | ||||
import { EscalationInput, ModalFormInput } from '@/app/api/po/actions'; | import { EscalationInput, ModalFormInput } from '@/app/api/po/actions'; | ||||
import { EscalationCombo } from "@/app/api/user"; | import { EscalationCombo } from "@/app/api/user"; | ||||
import { fetchEscalationCombo } from "@/app/api/user/actions"; | |||||
import { FireExtinguisher } from '@mui/icons-material'; | import { FireExtinguisher } from '@mui/icons-material'; | ||||
interface NameOption { | interface NameOption { | ||||
@@ -41,14 +42,14 @@ interface Props { | |||||
forSupervisor: boolean | forSupervisor: boolean | ||||
isCollapsed: boolean | isCollapsed: boolean | ||||
setIsCollapsed: Dispatch<React.SetStateAction<boolean>> | setIsCollapsed: Dispatch<React.SetStateAction<boolean>> | ||||
escalationCombo: EscalationCombo[] | |||||
// escalationCombo: EscalationCombo[] | |||||
} | } | ||||
const EscalationComponent: React.FC<Props> = ({ | const EscalationComponent: React.FC<Props> = ({ | ||||
forSupervisor, | forSupervisor, | ||||
isCollapsed, | isCollapsed, | ||||
setIsCollapsed, | setIsCollapsed, | ||||
escalationCombo | |||||
// escalationCombo | |||||
}) => { | }) => { | ||||
const { t } = useTranslation("purchaseOrder"); | const { t } = useTranslation("purchaseOrder"); | ||||
@@ -58,6 +59,18 @@ const EscalationComponent: React.FC<Props> = ({ | |||||
message: '', | message: '', | ||||
}); | }); | ||||
const [escalationCombo, setEscalationCombo] = useState<EscalationCombo[]>([]); | |||||
useEffect(() => { | |||||
async function fetchData() { | |||||
if (escalationCombo.length < 1) { | |||||
const escCombo = await fetchEscalationCombo(); | |||||
setEscalationCombo(escCombo); | |||||
} | |||||
} | |||||
fetchData(); | |||||
}, []) | |||||
const nameOptions: NameOption[] = [ | const nameOptions: NameOption[] = [ | ||||
{ value: '', label: '請選擇姓名...' }, | { value: '', label: '請選擇姓名...' }, | ||||
{ value: 'john', label: '張大明' }, | { value: 'john', label: '張大明' }, | ||||
@@ -89,7 +89,6 @@ type Props = { | |||||
qc: QcItemWithChecks[]; | qc: QcItemWithChecks[]; | ||||
warehouse: WarehouseResult[]; | warehouse: WarehouseResult[]; | ||||
printerCombo: PrinterCombo[]; | printerCombo: PrinterCombo[]; | ||||
escalationCombo: EscalationCombo[]; | |||||
}; | }; | ||||
type EntryError = | type EntryError = | ||||
@@ -192,7 +191,7 @@ interface PolInputResult { | |||||
dnQty: number, | dnQty: number, | ||||
} | } | ||||
const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo, escalationCombo }) => { | |||||
const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo }) => { | |||||
const cameras = useContext(CameraContext); | const cameras = useContext(CameraContext); | ||||
// console.log(cameras); | // console.log(cameras); | ||||
const { t } = useTranslation("purchaseOrder"); | const { t } = useTranslation("purchaseOrder"); | ||||
@@ -865,7 +864,6 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse, printerCombo, escalation | |||||
fetchPoDetail={fetchPoDetail} | fetchPoDetail={fetchPoDetail} | ||||
handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} | handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} | ||||
printerCombo={printerCombo} | printerCombo={printerCombo} | ||||
escalationCombo={escalationCombo} | |||||
/> | /> | ||||
</Box> | </Box> | ||||
</TableCell> | </TableCell> | ||||
@@ -27,17 +27,15 @@ const PoDetailWrapper: React.FC<Props> & SubComponents = async ({ id }) => { | |||||
warehouse, | warehouse, | ||||
qc, | qc, | ||||
printerCombo, | printerCombo, | ||||
escalationCombo, | |||||
] = await Promise.all([ | ] = await Promise.all([ | ||||
fetchPoWithStockInLines(id), | fetchPoWithStockInLines(id), | ||||
fetchWarehouseList(), | fetchWarehouseList(), | ||||
fetchQcItemCheck(), | fetchQcItemCheck(), | ||||
fetchPrinterCombo(), | fetchPrinterCombo(), | ||||
fetchEscalationCombo() | |||||
]); | ]); | ||||
// const poWithStockInLine = await fetchPoWithStockInLines(id) | // const poWithStockInLine = await fetchPoWithStockInLines(id) | ||||
console.log("%c pol:", "color:green", poWithStockInLine); | console.log("%c pol:", "color:green", poWithStockInLine); | ||||
return <PoDetail po={poWithStockInLine} qc={qc} warehouse={warehouse} printerCombo={printerCombo} escalationCombo={escalationCombo}/>; | |||||
return <PoDetail po={poWithStockInLine} qc={qc} warehouse={warehouse} printerCombo={printerCombo} />; | |||||
}; | }; | ||||
PoDetailWrapper.Loading = PoDetailLoading; | PoDetailWrapper.Loading = PoDetailLoading; | ||||
@@ -83,7 +83,6 @@ interface Props { | |||||
fetchPoDetail: (poId: string) => void; | fetchPoDetail: (poId: string) => void; | ||||
handleMailTemplateForStockInLine: (stockInLineId: number) => void; | handleMailTemplateForStockInLine: (stockInLineId: number) => void; | ||||
printerCombo: PrinterCombo[]; | printerCombo: PrinterCombo[]; | ||||
escalationCombo: EscalationCombo[]; | |||||
} | } | ||||
export type StockInLineEntryError = { | export type StockInLineEntryError = { | ||||
@@ -125,7 +124,6 @@ function PoInputGrid({ | |||||
fetchPoDetail, | fetchPoDetail, | ||||
handleMailTemplateForStockInLine, | handleMailTemplateForStockInLine, | ||||
printerCombo, | printerCombo, | ||||
escalationCombo | |||||
}: Props) { | }: Props) { | ||||
const { t } = useTranslation("purchaseOrder"); | const { t } = useTranslation("purchaseOrder"); | ||||
@@ -307,7 +305,6 @@ const closeNewModal = useCallback(() => { | |||||
const handleNewQC = useCallback( | const handleNewQC = useCallback( | ||||
(id: GridRowId, params: any) => async() => { | (id: GridRowId, params: any) => async() => { | ||||
// console.log(id) | // console.log(id) | ||||
console.log("params", params.row) | |||||
// setBtnIsLoading(true); | // setBtnIsLoading(true); | ||||
setRowModesModel((prev) => ({ | setRowModesModel((prev) => ({ | ||||
...prev, | ...prev, | ||||
@@ -955,7 +952,6 @@ const closeNewModal = useCallback(() => { | |||||
itemDetail={modalInfo} | itemDetail={modalInfo} | ||||
handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} | handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} | ||||
printerCombo={printerCombo} | printerCombo={printerCombo} | ||||
escalationCombo={escalationCombo} | |||||
/> | /> | ||||
</> | </> | ||||
) | ) | ||||
@@ -60,9 +60,8 @@ import CollapsibleCard from "../CollapsibleCard/CollapsibleCard"; | |||||
interface Props { | interface Props { | ||||
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; | itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; | ||||
qc: QcItemWithChecks[]; | |||||
// qc: QcItemWithChecks[]; | |||||
disabled: boolean; | disabled: boolean; | ||||
escalationCombo: EscalationCombo[]; | |||||
// qcItems: QcData[] | // qcItems: QcData[] | ||||
// setQcItems: Dispatch<SetStateAction<QcData[]>> | // setQcItems: Dispatch<SetStateAction<QcData[]>> | ||||
} | } | ||||
@@ -75,7 +74,7 @@ type EntryError = | |||||
type QcRow = TableRow<Partial<QcData>, EntryError>; | type QcRow = TableRow<Partial<QcData>, EntryError>; | ||||
// fetchQcItemCheck | // fetchQcItemCheck | ||||
const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escalationCombo }) => { | |||||
const QcComponent: React.FC<Props> = ({ itemDetail, disabled = false }) => { | |||||
const { t } = useTranslation("purchaseOrder"); | const { t } = useTranslation("purchaseOrder"); | ||||
const apiRef = useGridApiRef(); | const apiRef = useGridApiRef(); | ||||
const { | const { | ||||
@@ -94,12 +93,16 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
const [tabIndex, setTabIndex] = useState(0); | const [tabIndex, setTabIndex] = useState(0); | ||||
const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>(); | const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>(); | ||||
const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory); | const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory); | ||||
// const [qcResult, setQcResult] = useState(); | |||||
const qcAccept = watch("qcAccept"); | const qcAccept = watch("qcAccept"); | ||||
const qcDecision = watch("qcDecision"); //WIP | const qcDecision = watch("qcDecision"); //WIP | ||||
// const qcResult = useMemo(() => [...watch("qcResult")], [watch("qcResult")]); | // const qcResult = useMemo(() => [...watch("qcResult")], [watch("qcResult")]); | ||||
const qcResult = [...watch("qcResult")]; | |||||
const qcRecord = useMemo(() => { // Need testing | |||||
const value = watch('qcResult'); console.log("%c QC update!", "color:green", value); | |||||
return Array.isArray(value) ? [...value] : []; | |||||
}, [watch('qcResult')]); | |||||
const [qcHistory, setQcHistory] = useState<PurchaseQcResult[]>([]); | const [qcHistory, setQcHistory] = useState<PurchaseQcResult[]>([]); | ||||
const [qcResult, setQcResult] = useState<PurchaseQcResult[]>([]); | |||||
// const [qcAccept, setQcAccept] = useState(true); | // const [qcAccept, setQcAccept] = useState(true); | ||||
// const [qcItems, setQcItems] = useState(dummyQCData) | // const [qcItems, setQcItems] = useState(dummyQCData) | ||||
@@ -118,12 +121,16 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
}, | }, | ||||
], [] | ], [] | ||||
) | ) | ||||
const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||||
(_e, newValue) => { | |||||
setTabIndex(newValue); | |||||
}, | |||||
[], | |||||
); | |||||
const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||||
(_e, newValue) => { | |||||
setTabIndex(newValue); | |||||
}, | |||||
[], | |||||
); | |||||
const isExist = (data : string | number | undefined) => { | |||||
return (data !== null && data !== undefined); | |||||
} | |||||
// W I P // | // W I P // | ||||
const validateFieldFail = (field : FieldPath<PurchaseQCInput>, condition: boolean, message: string) : boolean => { | const validateFieldFail = (field : FieldPath<PurchaseQCInput>, condition: boolean, message: string) : boolean => { | ||||
@@ -225,6 +232,10 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
return <Checkbox checked={!!value} onChange={handleChange} sx={{ p: 0 }} />; | return <Checkbox checked={!!value} onChange={handleChange} sx={{ p: 0 }} />; | ||||
} | } | ||||
const qcDisabled = (row : PurchaseQcResult) => { | |||||
return disabled || isExist(row.escalationLogId); | |||||
}; | |||||
const qcColumns: GridColDef[] = useMemo(() => [ | const qcColumns: GridColDef[] = useMemo(() => [ | ||||
{ | { | ||||
field: "code", | field: "code", | ||||
@@ -245,7 +256,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
flex: 1.5, | flex: 1.5, | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
const rowValue = params.row; | const rowValue = params.row; | ||||
const index = params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
// console.log(rowValue.row); | // console.log(rowValue.row); | ||||
return ( | return ( | ||||
<FormControl> | <FormControl> | ||||
@@ -267,7 +278,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
value="true" | value="true" | ||||
control={<Radio />} | control={<Radio />} | ||||
label="合格" | label="合格" | ||||
disabled={disabled || itemDetail.status == "escalated"} | |||||
disabled={qcDisabled(rowValue)} | |||||
sx={{ | sx={{ | ||||
color: rowValue.qcPassed === true ? "green" : "inherit", | color: rowValue.qcPassed === true ? "green" : "inherit", | ||||
"& .Mui-checked": {color: "green"} | "& .Mui-checked": {color: "green"} | ||||
@@ -277,7 +288,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
value="false" | value="false" | ||||
control={<Radio />} | control={<Radio />} | ||||
label="不合格" | label="不合格" | ||||
disabled={disabled || itemDetail.status == "escalated"} | |||||
disabled={qcDisabled(rowValue)} | |||||
sx={{ | sx={{ | ||||
color: rowValue.qcPassed === false ? "red" : "inherit", | color: rowValue.qcPassed === false ? "red" : "inherit", | ||||
"& .Mui-checked": {color: "red"} | "& .Mui-checked": {color: "red"} | ||||
@@ -294,22 +305,27 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
flex: 1, | flex: 1, | ||||
// editable: true, | // editable: true, | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
const index = params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
return ( | return ( | ||||
<TextField | <TextField | ||||
type="number" | type="number" | ||||
size="small" | size="small" | ||||
value={!params.row.qcPassed? params.value : '0'} | value={!params.row.qcPassed? params.value : '0'} | ||||
disabled={params.row.qcPassed || disabled || itemDetail.status == "escalated"} | |||||
onBlur={(e) => { | |||||
disabled={params.row.qcPassed || qcDisabled(params.row)} | |||||
/* TODO improve */ | |||||
/* Reference: https://grok.com/share/c2hhcmQtNA%3D%3D_10787069-3eec-40af-a7cc-bacbdb86bf05 */ | |||||
onChange={(e) => { | |||||
const v = e.target.value; | const v = e.target.value; | ||||
const next = v === '' ? undefined : Number(v); | const next = v === '' ? undefined : Number(v); | ||||
if (Number.isNaN(next)) return; | if (Number.isNaN(next)) return; | ||||
// setQcItems((prev) => | |||||
// prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r)) | |||||
// ); | |||||
setValue(`qcResult.${index}.failQty`, next); | setValue(`qcResult.${index}.failQty`, next); | ||||
}} | }} | ||||
// onBlur={(e) => { | |||||
// const v = e.target.value; | |||||
// const next = v === '' ? undefined : Number(v); | |||||
// if (Number.isNaN(next)) return; | |||||
// setValue(`qcResult.${index}.failQty`, next); | |||||
// }} | |||||
onClick={(e) => e.stopPropagation()} | onClick={(e) => e.stopPropagation()} | ||||
onMouseDown={(e) => e.stopPropagation()} | onMouseDown={(e) => e.stopPropagation()} | ||||
onKeyDown={(e) => e.stopPropagation()} | onKeyDown={(e) => e.stopPropagation()} | ||||
@@ -324,12 +340,12 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
headerName: t("remarks"), | headerName: t("remarks"), | ||||
flex: 2, | flex: 2, | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
const index = params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
const index = Number(params.id);//params.api.getRowIndexRelativeToVisibleRows(params.id); | |||||
return ( | return ( | ||||
<TextField | <TextField | ||||
size="small" | size="small" | ||||
defaultValue={params.value} | defaultValue={params.value} | ||||
disabled={disabled || itemDetail.status == "escalated"} | |||||
disabled={qcDisabled(params.row)} | |||||
onBlur={(e) => { | onBlur={(e) => { | ||||
const value = e.target.value; | const value = e.target.value; | ||||
setValue(`qcResult.${index}.remarks`, value); | setValue(`qcResult.${index}.remarks`, value); | ||||
@@ -365,15 +381,31 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
}, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); | }, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); | ||||
useEffect(() => { | useEffect(() => { | ||||
// console.log("Qc Result updated:", qcResult); | |||||
if (qcResult.length < 1) { // New QC | |||||
const mutableQcData = dummyQCData; | |||||
// const mutableQcData = JSON.parse(JSON.stringify(dummyQCData)); | |||||
// replace([mutableQcData]); | |||||
setValue("qcResult", mutableQcData); | |||||
// setValue("qcResult.0.qcPassed", false); | |||||
console.log("%c Qc Record updated:", "color:red", qcRecord); | |||||
if (qcRecord.length < 1) { // New QC | |||||
const fetchedQcData = dummyQCData; //TODO fetch from DB | |||||
setValue("qcResult", fetchedQcData); | |||||
} else { | |||||
if (itemDetail.status == "escalated") { // Copy the previous QC data for editing | |||||
if (qcRecord.find((qc) => !isExist(qc.escalationLogId)) === undefined) { | |||||
const copiedQcData = qcRecord.map(qc => ({ ...qc, escalationLogId: undefined })); | |||||
const mutableQcData = [...qcRecord, ...copiedQcData]; | |||||
setValue("qcResult", mutableQcData); | |||||
} | |||||
} | |||||
if (qcRecord.length > 0) { | |||||
if (qcResult.length < 1) { // Set QC Result | |||||
const filteredQcResult = qcRecord.filter((qc) => !isExist(qc.escalationLogId)); | |||||
setQcResult(filteredQcResult); | |||||
} | |||||
if (qcHistory.length < 1) { // Set QC History | |||||
const filteredQcHistory = qcRecord.filter((qc) => isExist(qc.escalationLogId)); | |||||
setQcHistory(filteredQcHistory); | |||||
} | |||||
} | |||||
} | } | ||||
}, [qcResult, setValue]) | |||||
}, [qcRecord, setValue]) | |||||
// const [openCollapse, setOpenCollapse] = useState(false) | // const [openCollapse, setOpenCollapse] = useState(false) | ||||
const [isCollapsed, setIsCollapsed] = useState<boolean>(true); | const [isCollapsed, setIsCollapsed] = useState<boolean>(true); | ||||
@@ -415,16 +447,16 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
} | } | ||||
} | } | ||||
useEffect(() => { | |||||
if (qcHistory.length < 1) { | |||||
setQcHistory(qcResult.filter((qc) => {qc.escalationLogId != null})); | |||||
console.log("QC History updated:", qcHistory); | |||||
} | |||||
}, [watch("qcResult")]); | |||||
// }, [watch("qcResult")]); | |||||
// useEffect(() => { | // useEffect(() => { | ||||
// // onFailedOpenCollapse(qcItems) | // // onFailedOpenCollapse(qcItems) | ||||
// }, [qcItems]); | // }, [qcItems]); | ||||
const getRowId = (row :any) => { | |||||
return qcRecord.findIndex(qc => qc == row); | |||||
// return row.id || `${row.name}-${Math.random().toString(36).substr(2, 9)}`; | |||||
}; | |||||
return ( | return ( | ||||
<> | <> | ||||
<Grid container justifyContent="flex-start" alignItems="flex-start"> | <Grid container justifyContent="flex-start" alignItems="flex-start"> | ||||
@@ -475,6 +507,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
// rows={disabled? qcResult:qcItems} | // rows={disabled? qcResult:qcItems} | ||||
autoHeight | autoHeight | ||||
sortModel={[]} | sortModel={[]} | ||||
getRowId={getRowId} | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
</> | </> | ||||
@@ -497,7 +530,7 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
<CollapsibleCard title={t("QC Record")}> | <CollapsibleCard title={t("QC Record")}> | ||||
<StyledDataGrid | <StyledDataGrid | ||||
columns={qcColumns} | columns={qcColumns} | ||||
rows={qcResult} | |||||
rows={qcHistory} | |||||
// rows={qcResult && qcResult.length > 0 ? qcResult : qcItems} | // rows={qcResult && qcResult.length > 0 ? qcResult : qcItems} | ||||
// rows={disabled? qcResult:qcItems} | // rows={disabled? qcResult:qcItems} | ||||
autoHeight | autoHeight | ||||
@@ -536,8 +569,8 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
onChange={(e) => { | onChange={(e) => { | ||||
const value = e.target.value.toString();// === 'true'; | const value = e.target.value.toString();// === 'true'; | ||||
const input = document.getElementById('accQty') as HTMLInputElement; | |||||
console.log("%c Error", "color:pink", errors.acceptQty); | |||||
const input = document.getElementById('accQty') as HTMLInputElement; //TODO improve | |||||
console.log("%c AccQty Error", "color:pink", errors.acceptQty); | |||||
if (input) { // Selected Reject in new flow with Error | if (input) { // Selected Reject in new flow with Error | ||||
if (value == "1") { // Selected Accept | if (value == "1") { // Selected Accept | ||||
input.value = Number(accQty).toString(); | input.value = Number(accQty).toString(); | ||||
@@ -641,7 +674,6 @@ const QcComponent: React.FC<Props> = ({ qc, itemDetail, disabled = false, escala | |||||
forSupervisor={false} | forSupervisor={false} | ||||
isCollapsed={isCollapsed} | isCollapsed={isCollapsed} | ||||
setIsCollapsed={setIsCollapsed} | setIsCollapsed={setIsCollapsed} | ||||
escalationCombo={escalationCombo} | |||||
/> | /> | ||||
</Grid>)} | </Grid>)} | ||||
{/* {qcAccept && <Grid item xs={12}> | {/* {qcAccept && <Grid item xs={12}> | ||||
@@ -67,7 +67,6 @@ interface CommonProps extends Omit<ModalProps, "children"> { | |||||
// type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; | // type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; | ||||
handleMailTemplateForStockInLine: (stockInLineId: number) => void; | handleMailTemplateForStockInLine: (stockInLineId: number) => void; | ||||
printerCombo: PrinterCombo[]; | printerCombo: PrinterCombo[]; | ||||
escalationCombo: EscalationCombo[]; | |||||
onClose: () => void; | onClose: () => void; | ||||
} | } | ||||
interface Props extends CommonProps { | interface Props extends CommonProps { | ||||
@@ -87,7 +86,6 @@ const PoQcStockInModalVer2: React.FC<Props> = ({ | |||||
warehouse, | warehouse, | ||||
handleMailTemplateForStockInLine, | handleMailTemplateForStockInLine, | ||||
printerCombo, | printerCombo, | ||||
escalationCombo | |||||
}) => { | }) => { | ||||
const { | const { | ||||
t, | t, | ||||
@@ -110,9 +108,10 @@ const defaultNewValue = useMemo(() => { | |||||
escResult: (itemDetail.escResult && itemDetail.escResult?.length > 0) ? itemDetail.escResult : [], | escResult: (itemDetail.escResult && itemDetail.escResult?.length > 0) ? itemDetail.escResult : [], | ||||
productionDate: itemDetail.productionDate ? arrayToDateString(itemDetail.productionDate, "input") : undefined, | productionDate: itemDetail.productionDate ? arrayToDateString(itemDetail.productionDate, "input") : undefined, | ||||
expiryDate: itemDetail.expiryDate ? arrayToDateString(itemDetail.expiryDate, "input") : undefined, | expiryDate: itemDetail.expiryDate ? arrayToDateString(itemDetail.expiryDate, "input") : undefined, | ||||
receiptDate: itemDetail.receiptDate ?? dayjs().add(0, "month").format(INPUT_DATE_FORMAT), | |||||
receiptDate: itemDetail.receiptDate ? arrayToDateString(itemDetail.receiptDate, "input") | |||||
: dayjs().add(0, "month").format(INPUT_DATE_FORMAT), | |||||
acceptQty: itemDetail.demandQty?? itemDetail.acceptedQty, | acceptQty: itemDetail.demandQty?? itemDetail.acceptedQty, | ||||
warehouseId: itemDetail.defaultWarehouseId ?? 1 | |||||
warehouseId: itemDetail.defaultWarehouseId ?? 1, | |||||
} | } | ||||
) | ) | ||||
},[itemDetail]) | },[itemDetail]) | ||||
@@ -153,10 +152,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
}, [itemDetail]); | }, [itemDetail]); | ||||
useEffect(() => { | useEffect(() => { | ||||
const qcRes = itemDetail?.qcResult; | |||||
// if (!qcRes || qcRes?.length <= 0) { | |||||
// itemDetail.qcResult = dummyQCData; | |||||
// } | |||||
formProps.reset({ | formProps.reset({ | ||||
...defaultNewValue | ...defaultNewValue | ||||
}) | }) | ||||
@@ -220,7 +215,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
const qcAccept = data.qcDecision == 1; | const qcAccept = data.qcDecision == 1; | ||||
// const qcAccept = data.qcAccept; | // const qcAccept = data.qcAccept; | ||||
let acceptQty = Number(data.acceptQty); | let acceptQty = Number(data.acceptQty); | ||||
const qcResults = data.qcResult || dummyQCData; // qcItems; | |||||
const qcResults = data.qcResult?.filter((qc) => qc.escalationLogId === undefined) || []; // Remove old QC data | |||||
// const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems; | // const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems; | ||||
// const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems; | // const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems; | ||||
@@ -290,16 +285,17 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
qcAccept: qcAccept? qcAccept : false, | qcAccept: qcAccept? qcAccept : false, | ||||
acceptQty: acceptQty? acceptQty : 0, | acceptQty: acceptQty? acceptQty : 0, | ||||
qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({ | |||||
id: item.id, | |||||
qcItemId: item.id, | |||||
// qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({ | |||||
qcResult: qcResults.map(item => ({ | |||||
// id: item.id, | |||||
qcItemId: item.qcItemId, | |||||
// code: item.code, | // code: item.code, | ||||
// qcDescription: item.qcDescription, | // qcDescription: item.qcDescription, | ||||
qcPassed: item.qcPassed? item.qcPassed : false, | qcPassed: item.qcPassed? item.qcPassed : false, | ||||
failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0, | failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0, | ||||
// failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, | // failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, | ||||
remarks: item.remarks || '' | |||||
})) : [], | |||||
remarks: item.remarks || '', | |||||
})), | |||||
}; | }; | ||||
// const qcData = data; | // const qcData = data; | ||||
@@ -389,7 +385,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
status: data.status, //TODO Fix it! | status: data.status, //TODO Fix it! | ||||
// ...data, | // ...data, | ||||
dnDate : data.dnDate? arrayToDateString(data.dnDate) : dayjsToInputDateString(dayjs()), | |||||
dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()), | |||||
productionDate : arrayToDateString(data.productionDate, "input"), | productionDate : arrayToDateString(data.productionDate, "input"), | ||||
expiryDate : arrayToDateString(data.expiryDate, "input"), | expiryDate : arrayToDateString(data.expiryDate, "input"), | ||||
receiptDate : arrayToDateString(data.receiptDate, "input"), | receiptDate : arrayToDateString(data.receiptDate, "input"), | ||||
@@ -406,8 +402,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
alert("請新增上架資料!"); | alert("請新增上架資料!"); | ||||
return; | return; | ||||
} | } | ||||
console.log(typeof data.putAwayLines!![0].qty + " = 'number'"); | |||||
console.log(typeof data.putAwayLines!![0].qty !== "number"); | |||||
if (data.putAwayLines!!.filter((line) => /[^0-9]/.test(String(line.qty))).length > 0) { //TODO Improve | if (data.putAwayLines!!.filter((line) => /[^0-9]/.test(String(line.qty))).length > 0) { //TODO Improve | ||||
alert("上架數量不正確!"); | alert("上架數量不正確!"); | ||||
return; | return; | ||||
@@ -471,11 +465,11 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
return isPassed | return isPassed | ||||
}, [acceptQty, formProps]) | }, [acceptQty, formProps]) | ||||
useEffect(() => { | |||||
// maybe check if submitted before | |||||
console.log("Modal QC Items updated:", qcItems); | |||||
// checkQcIsPassed(qcItems) | |||||
}, [qcItems, checkQcIsPassed]) | |||||
// useEffect(() => { | |||||
// // maybe check if submitted before | |||||
// console.log("Modal QC Items updated:", qcItems); | |||||
// // checkQcIsPassed(qcItems) | |||||
// }, [qcItems, checkQcIsPassed]) | |||||
return ( | return ( | ||||
<> | <> | ||||
@@ -576,10 +570,9 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
alignItems="flex-start" | alignItems="flex-start" | ||||
> | > | ||||
<QcComponent | <QcComponent | ||||
qc={qc!} | |||||
// qc={qc!} | |||||
itemDetail={itemDetail} | itemDetail={itemDetail} | ||||
disabled={viewOnly} | disabled={viewOnly} | ||||
escalationCombo={escalationCombo} | |||||
// qcItems={qcItems} | // qcItems={qcItems} | ||||
// setQcItems={setQcItems} | // setQcItems={setQcItems} | ||||
/> | /> | ||||
@@ -12,7 +12,8 @@ import { QcData } from "@/app/api/qc" | |||||
export const dummyQCData: QcData[] = [ | export const dummyQCData: QcData[] = [ | ||||
{ | { | ||||
id: 4, | |||||
id: 1, | |||||
qcItemId: 4, | |||||
code: "包裝", | code: "包裝", | ||||
qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | ||||
name: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | name: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | ||||
@@ -21,7 +22,8 @@ export const dummyQCData: QcData[] = [ | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
id: 5, | |||||
id: 2, | |||||
qcItemId: 5, | |||||
code: "肉質", | code: "肉質", | ||||
qcDescription: "肉質鬆散,則不合格", | qcDescription: "肉質鬆散,則不合格", | ||||
name: "肉質鬆散,則不合格", | name: "肉質鬆散,則不合格", | ||||
@@ -30,7 +32,8 @@ export const dummyQCData: QcData[] = [ | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
id: 6, | |||||
id: 3, | |||||
qcItemId: 6, | |||||
code: "顔色", | code: "顔色", | ||||
qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | ||||
name: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | name: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,則不合格", | ||||
@@ -39,7 +42,8 @@ export const dummyQCData: QcData[] = [ | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
id: 7, | |||||
id: 4, | |||||
qcItemId: 7, | |||||
code: "狀態", | code: "狀態", | ||||
qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | ||||
name: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | name: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | ||||
@@ -48,7 +52,8 @@ export const dummyQCData: QcData[] = [ | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
id: 8, | |||||
id: 5, | |||||
qcItemId: 8, | |||||
code: "異物", | code: "異物", | ||||
qcDescription: "有不屬於本食材的雜質,則不合格", | qcDescription: "有不屬於本食材的雜質,則不合格", | ||||
name: "有不屬於本食材的雜質,則不合格", | name: "有不屬於本食材的雜質,則不合格", | ||||
@@ -34,6 +34,7 @@ | |||||
"Pending application": "待處理提料申請", | "Pending application": "待處理提料申請", | ||||
"pending inspection material": "待品檢物料", | "pending inspection material": "待品檢物料", | ||||
"rejected": "已拒絕", | "rejected": "已拒絕", | ||||
"accepted": "已收貨", | |||||
"escalated": "已上報", | "escalated": "已上報", | ||||
"inspected material": "已品檢物料", | "inspected material": "已品檢物料", | ||||
"total material": "物料總數", | "total material": "物料總數", | ||||
@@ -50,5 +51,6 @@ | |||||
"QC Completed Count": "品檢完成數量", | "QC Completed Count": "品檢完成數量", | ||||
"QC Fail-Total Count": "品檢不合格/總數", | "QC Fail-Total Count": "品檢不合格/總數", | ||||
"escalationStatus": "上報狀態", | "escalationStatus": "上報狀態", | ||||
"escalated datetime": "上報時間" | |||||
"escalated datetime": "上報時間", | |||||
"escalateFrom": "上報同事" | |||||
} | } |