@@ -9,6 +9,7 @@ import { PoResult, StockInLine } from "."; | |||
import { serverFetchJson } from "../../utils/fetchUtil"; | |||
import { QcItemResult } from "../settings/qcItem"; | |||
import { RecordsRes } from "../utils"; | |||
import { Uom } from "../settings/uom"; | |||
// import { BASE_API_URL } from "@/config/api"; | |||
export interface PostStockInLiineResponse<T> { | |||
@@ -44,18 +45,23 @@ export interface StockInInput { | |||
itemName: string; | |||
invoiceNo?: string; | |||
receiptDate: string; | |||
supplier: string; | |||
acceptedQty: number; | |||
qty: number; | |||
receivedQty: number; | |||
acceptedWeight?: number; | |||
productionDate?: string; | |||
expiryDate: string; | |||
uom: Uom; | |||
} | |||
export interface PurchaseQCInput { | |||
status: string; | |||
acceptedQty: number; | |||
acceptQty: number; | |||
passingQty: number; | |||
sampleRate: number; | |||
sampleWeight: number; | |||
totalWeight: number; | |||
qcAccept: boolean; | |||
qcResult: PurchaseQcResult[]; | |||
} | |||
export interface EscalationInput { | |||
@@ -28,6 +28,7 @@ export interface PurchaseOrderLine { | |||
itemName: string; | |||
qty: number; | |||
processed: number; | |||
receivedQty: number; | |||
uom: Uom; | |||
price: number; | |||
status: string; | |||
@@ -45,6 +46,8 @@ export interface StockInLine { | |||
itemType: string; | |||
demandQty: number; | |||
acceptedQty: number; | |||
qty: number; | |||
processed: number; | |||
price: number; | |||
priceUnit: string; | |||
shelfLife?: number; | |||
@@ -73,6 +73,7 @@ export interface InputDataGridProps<T, V, E> { | |||
columns: GridColDef[]; | |||
validateRow: (newRow: GridRowModel<TableRow<V, E>>) => E; | |||
needAdd?: boolean; | |||
showRemoveBtn?: boolean; | |||
} | |||
export interface SelectionInputDataGridProps<T, V, E> { | |||
@@ -109,6 +110,7 @@ function InputDataGrid<T, V, E>({ | |||
columns, | |||
validateRow, | |||
needAdd, | |||
showRemoveBtn = true, | |||
}: Props<T, V, E>) { | |||
const { | |||
t, | |||
@@ -303,7 +305,7 @@ function InputDataGrid<T, V, E>({ | |||
新增 | |||
{/* {t("Add Record")} */} | |||
</Button> | |||
<Button | |||
{showRemoveBtn && <Button | |||
disableRipple | |||
variant="outlined" | |||
startIcon={<Add />} | |||
@@ -312,7 +314,7 @@ function InputDataGrid<T, V, E>({ | |||
> | |||
{/* {t("Clean Record")} */} | |||
清除 | |||
</Button> | |||
</Button>} | |||
</Box> | |||
); | |||
// const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => { | |||
@@ -414,9 +414,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||
<TableCell align="right">{decimalFormatter.format(row.price)}</TableCell> | |||
{/* <TableCell align="left">{row.expiryDate}</TableCell> */} | |||
<TableCell align="left">{t(`${currStatus.toLowerCase()}`)}</TableCell> | |||
<TableCell align="right"> | |||
0 | |||
</TableCell> | |||
<TableCell align="right">{integerFormatter.format(row.receivedQty)}</TableCell> | |||
<TableCell align="center"> | |||
<TextField | |||
label="輸入來貨數量" | |||
@@ -284,8 +284,8 @@ const closeNewModal = useCallback(() => { | |||
// Button handler to update the URL and open the modal | |||
const handleNewQC = useCallback( | |||
(id: GridRowId, params: any) => async () => { | |||
console.log(id) | |||
console.log(params) | |||
// console.log(id) | |||
// console.log(params) | |||
setBtnIsLoading(true); | |||
setRowModesModel((prev) => ({ | |||
...prev, | |||
@@ -296,6 +296,7 @@ const closeNewModal = useCallback(() => { | |||
setModalInfo({ | |||
...params.row, | |||
qcResult: qcResult, | |||
receivedQty: itemDetail.receivedQty, | |||
}); | |||
setTimeout(() => { | |||
@@ -499,7 +500,7 @@ const closeNewModal = useCallback(() => { | |||
// }, | |||
{ | |||
field: "status", | |||
headerName: t("status"), | |||
headerName: t("Status"), | |||
width: 70, | |||
// flex: 0.5, | |||
renderCell: (params) => { | |||
@@ -499,6 +499,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||
columns={columns} | |||
validateRow={validation} | |||
needAdd={true} | |||
showRemoveBtn={false} | |||
/> | |||
</Grid> | |||
</Grid> | |||
@@ -6,7 +6,11 @@ import { | |||
Card, | |||
CardContent, | |||
Checkbox, | |||
FormControl, | |||
FormControlLabel, | |||
Grid, | |||
Radio, | |||
RadioGroup, | |||
Stack, | |||
Tab, | |||
Tabs, | |||
@@ -15,7 +19,7 @@ import { | |||
Tooltip, | |||
Typography, | |||
} from "@mui/material"; | |||
import { useFormContext } from "react-hook-form"; | |||
import { useFormContext, Controller } from "react-hook-form"; | |||
import { useTranslation } from "react-i18next"; | |||
import StyledDataGrid from "../StyledDataGrid"; | |||
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react"; | |||
@@ -46,6 +50,7 @@ import QcDataGrid from "./QCDatagrid"; | |||
import StockInFormVer2 from "./StockInFormVer2"; | |||
import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; | |||
import { ModalFormInput } from "@/app/api/dashboard/actions"; | |||
import { escape } from "lodash"; | |||
interface Props { | |||
itemDetail: StockInLine; | |||
@@ -54,6 +59,7 @@ interface Props { | |||
qcItems: QcData[] | |||
setQcItems: Dispatch<SetStateAction<QcData[]>> | |||
} | |||
type EntryError = | |||
| { | |||
[field in keyof QcData]?: string; | |||
@@ -79,8 +85,11 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
} = useFormContext<PurchaseQCInput>(); | |||
const [tabIndex, setTabIndex] = useState(0); | |||
const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>() | |||
const [qcResult, setQcResult] = useState(dummyEscalationHistory) | |||
const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>(); | |||
const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory); | |||
const [qcResult, setQcResult] = useState(); | |||
const qcAccept = watch("qcAccept"); | |||
// const [qcAccept, setQcAccept] = useState(true); | |||
// const [qcItems, setQcItems] = useState(dummyQCData) | |||
const column = useMemo<GridColDef[]>( | |||
@@ -105,25 +114,25 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
); | |||
//// validate form | |||
const accQty = watch("acceptedQty"); | |||
const accQty = watch("acceptQty"); | |||
const validateForm = useCallback(() => { | |||
console.log(accQty); | |||
if (accQty > itemDetail.acceptedQty) { | |||
setError("acceptedQty", { | |||
message: `${t("acceptedQty must not greater than")} ${ | |||
setError("acceptQty", { | |||
message: `${t("acceptQty must not greater than")} ${ | |||
itemDetail.acceptedQty | |||
}`, | |||
type: "required", | |||
}); | |||
} | |||
if (accQty < 1) { | |||
setError("acceptedQty", { | |||
setError("acceptQty", { | |||
message: t("minimal value is 1"), | |||
type: "required", | |||
}); | |||
} | |||
if (isNaN(accQty)) { | |||
setError("acceptedQty", { | |||
setError("acceptQty", { | |||
message: t("value must be a number"), | |||
type: "required", | |||
}); | |||
@@ -137,77 +146,6 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
const columns = useMemo<GridColDef[]>( | |||
() => [ | |||
// { | |||
// field: "qcItemId", | |||
// headerName: t("qc Check"), | |||
// flex: 1, | |||
// editable: !disabled, | |||
// valueFormatter(params) { | |||
// const row = params.id ? params.api.getRow<QcRow>(params.id) : null; | |||
// if (!row) { | |||
// return null; | |||
// } | |||
// const Qc = qc.find((q) => q.id === row.qcItemId); | |||
// return Qc ? `${Qc.code} - ${Qc.name}` : t("Please select QC"); | |||
// }, | |||
// renderCell(params: GridRenderCellParams<QcRow, number>) { | |||
// console.log(params.value); | |||
// return <TwoLineCell>{params.formattedValue}</TwoLineCell>; | |||
// }, | |||
// renderEditCell(params: GridRenderEditCellParams<QcRow, number>) { | |||
// const errorMessage = | |||
// params.row._error?.[params.field as keyof PurchaseQcResult]; | |||
// console.log(errorMessage); | |||
// const content = ( | |||
// <QcSelect | |||
// allQcs={qc} | |||
// value={params.row.qcItemId} | |||
// onQcSelect={async (qcItemId) => { | |||
// await params.api.setEditCellValue({ | |||
// id: params.id, | |||
// field: "qcItemId", | |||
// value: qcItemId, | |||
// }); | |||
// // await params.api.setEditCellValue({ | |||
// // id: params.id, | |||
// // field: "type", | |||
// // value: "determine1", | |||
// // }); | |||
// }} | |||
// /> | |||
// ); | |||
// return errorMessage ? ( | |||
// <Tooltip title={errorMessage}> | |||
// <Box width="100%">{content}</Box> | |||
// </Tooltip> | |||
// ) : ( | |||
// content | |||
// ); | |||
// }, | |||
// }, | |||
// { | |||
// field: "failQty", | |||
// headerName: t("failQty"), | |||
// flex: 1, | |||
// editable: !disabled, | |||
// type: "number", | |||
// renderEditCell(params: GridRenderEditCellParams<QcRow>) { | |||
// // const recordQty = params.row.qty | |||
// // if (recordQty !== undefined) { | |||
// // setUnrecordQty((prev) => prev - recordQty) | |||
// // } | |||
// const errorMessage = | |||
// params.row._error?.[params.field as keyof PurchaseQcResult]; | |||
// const content = <GridEditInputCell {...params} />; | |||
// return errorMessage ? ( | |||
// <Tooltip title={t(errorMessage)}> | |||
// <Box width="100%">{content}</Box> | |||
// </Tooltip> | |||
// ) : ( | |||
// content | |||
// ); | |||
// }, | |||
// }, | |||
{ | |||
field: "escalation", | |||
headerName: t("escalation"), | |||
@@ -247,56 +185,57 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
{ | |||
field: "qcItem", | |||
headerName: t("qcItem"), | |||
flex: 1, | |||
flex: 2, | |||
renderCell: (params) => ( | |||
<Box> | |||
<b>{params.value}</b><br/> | |||
{params.row.qcDescription}<br/> | |||
</Box> | |||
), | |||
}, | |||
{ | |||
field: 'isPassed', | |||
headerName: t("passed"), | |||
flex: 1, | |||
renderCell: (params) => ( | |||
<Checkbox | |||
checked={!!params.value} | |||
onClick={(e) => e.stopPropagation()} // avoid row selection | |||
onMouseDown={(e) => e.stopPropagation()} // extra guard | |||
onChange={(e) => { | |||
const checked = e.target.checked; | |||
setQcItems((prev) => | |||
prev.map((r) => | |||
r.id === params.id | |||
? { ...r, isPassed: checked, isFailed: !checked ? r.isFailed : false } | |||
: r | |||
) | |||
); | |||
}} | |||
size="small" | |||
/> | |||
), | |||
headerName: t("qcResult"), | |||
flex: 1.5, | |||
renderCell: (params) => { | |||
const currentValue = params.value; | |||
return ( | |||
<FormControl> | |||
<RadioGroup | |||
row | |||
aria-labelledby="demo-radio-buttons-group-label" | |||
value={currentValue === undefined ? "" : (currentValue ? "true" : "false")} | |||
onChange={(e) => { | |||
const value = e.target.value; | |||
setQcItems((prev) => | |||
prev.map((r): QcData => (r.id === params.id ? { ...r, isPassed: value === "true" } : r)) | |||
); | |||
}} | |||
name={`isPassed-${params.id}`} | |||
> | |||
<FormControlLabel | |||
value="true" | |||
control={<Radio />} | |||
label="合格" | |||
sx={{ | |||
color: currentValue === true ? "green" : "inherit", | |||
"& .Mui-checked": {color: "green"} | |||
}} | |||
/> | |||
<FormControlLabel | |||
value="false" | |||
control={<Radio />} | |||
label="不合格" | |||
sx={{ | |||
color: currentValue === false ? "red" : "inherit", | |||
"& .Mui-checked": {color: "red"} | |||
}} | |||
/> | |||
</RadioGroup> | |||
</FormControl> | |||
); | |||
}, | |||
}, | |||
{ | |||
field: "isFailed", | |||
headerName: t("failed"), | |||
flex: 1, | |||
editable: true, | |||
type: "boolean", | |||
renderCell: (params) => ( | |||
<Checkbox | |||
checked={!!params.value} | |||
onClick={(e) => e.stopPropagation()} // avoid row selection | |||
onMouseDown={(e) => e.stopPropagation()} // extra guard | |||
onChange={(e) => { | |||
const checked = e.target.checked; | |||
setQcItems((prev) => | |||
prev.map((r) => | |||
r.id === params.id | |||
? { ...r, isFailed: checked, isPassed: !checked ? r.isPassed : false } | |||
: r | |||
) | |||
); | |||
}} | |||
size="small" | |||
/> | |||
), | |||
}, | |||
{ | |||
field: "failedQty", | |||
headerName: t("failedQty"), | |||
@@ -306,7 +245,8 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
<TextField | |||
type="number" | |||
size="small" | |||
value={params.value ?? ''} | |||
value={!params.row.isPassed? (params.value ?? '') : '0'} | |||
disabled={params.row.isPassed} | |||
onChange={(e) => { | |||
const v = e.target.value; | |||
const next = v === '' ? undefined : Number(v); | |||
@@ -326,7 +266,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
{ | |||
field: "remarks", | |||
headerName: t("remarks"), | |||
flex: 1, | |||
flex: 2, | |||
renderCell: (params) => ( | |||
<TextField | |||
size="small" | |||
@@ -354,11 +294,18 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
}, [itemDetail]); | |||
// Set initial value for acceptQty | |||
useEffect(() => { | |||
if (itemDetail?.acceptedQty !== undefined) { | |||
setValue("acceptQty", itemDetail.acceptedQty); | |||
} | |||
}, [itemDetail?.acceptedQty, setValue]); | |||
// const [openCollapse, setOpenCollapse] = useState(false) | |||
const [isCollapsed, setIsCollapsed] = useState<boolean>(false); | |||
const onFailedOpenCollapse = useCallback((qcItems: QcData[]) => { | |||
const isFailed = qcItems.some((qc) => qc.isFailed) | |||
const isFailed = qcItems.some((qc) => !qc.isPassed) | |||
console.log(isFailed) | |||
if (isFailed) { | |||
setIsCollapsed(true) | |||
@@ -367,14 +314,20 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
} | |||
}, []) | |||
// const handleRadioChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { | |||
// const value = event.target.value === 'true'; | |||
// setValue("qcAccept", value); | |||
// }, [setValue]); | |||
useEffect(() => { | |||
console.log(itemDetail); | |||
}, [itemDetail]); | |||
useEffect(() => { | |||
onFailedOpenCollapse(qcItems) | |||
}, [qcItems, onFailedOpenCollapse]); | |||
// onFailedOpenCollapse(qcItems) // This function is no longer needed | |||
}, [qcItems]); // Removed onFailedOpenCollapse from dependency array | |||
return ( | |||
<> | |||
@@ -411,24 +364,15 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
autoHeight | |||
/> | |||
</Grid> | |||
<Grid item xs={4}> | |||
<TextField | |||
type="number" | |||
label={t("acceptedQty")} | |||
fullWidth | |||
defaultValue={watch("passingQty")} | |||
{...register("passingQty", { | |||
required: "passingQty required!", | |||
})} | |||
/> | |||
</Grid> | |||
<Grid item xs={12}> | |||
{/* <Grid item xs={12}> | |||
<EscalationComponent | |||
forSupervisor={false} | |||
isCollapsed={isCollapsed} | |||
setIsCollapsed={setIsCollapsed} | |||
/> | |||
</Grid> | |||
</Grid> */} | |||
</> | |||
)} | |||
{tabIndex == 1 && ( | |||
@@ -446,27 +390,68 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||
</Grid> | |||
<Grid item xs={12}> | |||
<StyledDataGrid | |||
rows={qcResult} | |||
rows={escalationHistory} | |||
columns={columns} | |||
onRowSelectionModelChange={(newRowSelectionModel) => { | |||
setRowSelectionModel(newRowSelectionModel); | |||
}} | |||
/> | |||
</Grid> | |||
<Grid item xs={12}> | |||
<Typography variant="h6" display="block" marginBlockEnd={1}> | |||
{t("Escalation Result")} | |||
</Typography> | |||
</Grid> | |||
<Grid item xs={12}> | |||
<EscalationComponent | |||
forSupervisor={true} | |||
isCollapsed={isCollapsed} | |||
setIsCollapsed={setIsCollapsed} | |||
/> | |||
</Grid> | |||
</> | |||
)} | |||
<Grid item xs={12}> | |||
<FormControl> | |||
<Controller | |||
name="qcAccept" | |||
control={control} | |||
defaultValue={true} | |||
render={({ field }) => ( | |||
<RadioGroup | |||
row | |||
aria-labelledby="demo-radio-buttons-group-label" | |||
{...field} | |||
value={field.value?.toString() || "true"} | |||
onChange={(e) => { | |||
const value = e.target.value === 'true'; | |||
if (!value && Boolean(errors.acceptQty)) { | |||
setValue("acceptQty", itemDetail.acceptedQty); | |||
} | |||
field.onChange(value); | |||
}} | |||
> | |||
<FormControlLabel value="true" control={<Radio />} label="接受" /> | |||
<Box sx={{mr:2}}> | |||
<TextField | |||
type="number" | |||
label={t("acceptQty")} | |||
sx={{ width: '150px' }} | |||
defaultValue={accQty} | |||
disabled={!qcAccept} | |||
{...register("acceptQty", { | |||
required: "acceptQty required!", | |||
})} | |||
error={Boolean(errors.acceptQty)} | |||
helperText={errors.acceptQty?.message} | |||
/> | |||
</Box> | |||
<FormControlLabel value="false" control={<Radio />} label="不接受及上報" /> | |||
</RadioGroup> | |||
)} | |||
/> | |||
</FormControl> | |||
</Grid> | |||
{/* <Grid item xs={12}> | |||
<Typography variant="h6" display="block" marginBlockEnd={1}> | |||
{t("Escalation Result")} | |||
</Typography> | |||
</Grid> | |||
<Grid item xs={12}> | |||
<EscalationComponent | |||
forSupervisor={true} | |||
isCollapsed={isCollapsed} | |||
setIsCollapsed={setIsCollapsed} | |||
/> | |||
</Grid> */} | |||
</Grid> | |||
</Grid> | |||
</> | |||
@@ -21,6 +21,8 @@ import QcFormVer2 from "./QcFormVer2"; | |||
import PutawayForm from "./PutawayForm"; | |||
import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate"; | |||
import { useGridApiRef } from "@mui/x-data-grid"; | |||
import {submitDialogWithWarning} from "../Swal/CustomAlerts"; | |||
const style = { | |||
position: "absolute", | |||
top: "50%", | |||
@@ -120,22 +122,70 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>( | |||
async (data, event) => { | |||
console.log("QC Submission:", event!.nativeEvent); | |||
// Extract only QC related fields | |||
// Get QC data from the shared form context | |||
const qcAccept = data.qcAccept; | |||
const acceptQty = data.acceptQty; | |||
// Validate QC data | |||
const validationErrors : string[] = []; | |||
// Check if all QC items have results | |||
const itemsWithoutResult = qcItems.filter(item => item.isPassed === undefined); | |||
if (itemsWithoutResult.length > 0) { | |||
validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.qcItem).join(', ')}`); | |||
} | |||
// Check if failed items have failed quantity | |||
const failedItemsWithoutQty = qcItems.filter(item => | |||
item.isPassed === false && (!item.failedQty || item.failedQty <= 0) | |||
); | |||
if (failedItemsWithoutQty.length > 0) { | |||
validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`); | |||
} | |||
// Check if QC accept decision is made | |||
// if (qcAccept === undefined) { | |||
// validationErrors.push("QC accept/reject decision is required"); | |||
// } | |||
// Check if accept quantity is valid | |||
if (acceptQty === undefined || acceptQty <= 0) { | |||
validationErrors.push("Accept quantity must be greater than 0"); | |||
} | |||
if (validationErrors.length > 0) { | |||
console.error("QC Validation failed:", validationErrors); | |||
alert(`未完成品檢: ${validationErrors}`); | |||
return; | |||
} | |||
const qcData = { | |||
// qcStatus: data.qcStatus, | |||
// qcComments: data.qcComments, | |||
// qcResult: data.qcResult, | |||
// approvedBy: data.approvedBy, | |||
// qualityGrade: data.qualityGrade, | |||
// defectNotes: data.defectNotes, | |||
data: data, | |||
// Add other QC specific fields from your form | |||
qcAccept: qcAccept, | |||
acceptQty: acceptQty, | |||
qcItems: qcItems.map(item => ({ | |||
id: item.id, | |||
qcItem: item.qcItem, | |||
qcDescription: item.qcDescription, | |||
isPassed: item.isPassed, | |||
failedQty: (item.failedQty && !item.isPassed) || 0, | |||
remarks: item.remarks || '' | |||
})) | |||
}; | |||
console.log(qcItems) | |||
console.log("QC Data:", qcData); | |||
// Handle QC submission logic here | |||
// After QC approval, open putaway form | |||
// onOpenPutaway(); | |||
// const qcData = data; | |||
console.log("QC Data for submission:", qcData); | |||
// await submitQcData(qcData); | |||
if (!qcData.qcItems.every((qc) => qc.isPassed) && qcData.qcAccept) { | |||
submitDialogWithWarning(onOpenPutaway, t, {title:"有不合格檢查項目,確認接受收貨?", confirmButtonText: "Confirm", html: ""}); | |||
return; | |||
} | |||
if (qcData.qcAccept) { | |||
onOpenPutaway(); | |||
} else { | |||
onClose(); | |||
} | |||
}, | |||
[onOpenPutaway, qcItems], | |||
); | |||
@@ -237,7 +287,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
id="printButton" | |||
type="button" | |||
variant="contained" | |||
color="secondary" | |||
color="primary" | |||
sx={{ mt: 1 }} | |||
onClick={onPrint} | |||
> | |||
@@ -247,7 +297,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
id="putawaySubmit" | |||
type="submit" | |||
variant="contained" | |||
color="secondary" | |||
color="primary" | |||
sx={{ mt: 1 }} | |||
> | |||
{t("confirm putaway")} | |||
@@ -299,7 +349,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
id="emailSupplier" | |||
type="button" | |||
variant="contained" | |||
color="secondary" | |||
color="primary" | |||
sx={{ mt: 1 }} | |||
onClick={formProps.handleSubmit(onSubmitEmailSupplier)} | |||
> | |||
@@ -309,7 +359,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||
id="qcSubmit" | |||
type="button" | |||
variant="contained" | |||
color="secondary" | |||
color="primary" | |||
sx={{ mt: 1 }} | |||
onClick={formProps.handleSubmit(onSubmitQc)} | |||
> | |||
@@ -75,7 +75,7 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
setError, | |||
clearErrors, | |||
} = useFormContext<StockInInput>(); | |||
console.log(itemDetail); | |||
// console.log(itemDetail); | |||
useEffect(() => { | |||
console.log("triggered"); | |||
@@ -90,15 +90,17 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
const productionDate = watch("productionDate"); | |||
const expiryDate = watch("expiryDate"); | |||
const uom = watch("uom"); | |||
useEffect(() => { | |||
console.log(uom); | |||
console.log(productionDate); | |||
console.log(expiryDate); | |||
if (expiryDate) clearErrors(); | |||
if (productionDate) clearErrors(); | |||
}, [productionDate, expiryDate, clearErrors]); | |||
console.log(itemDetail) | |||
// console.log(itemDetail) | |||
return ( | |||
<Grid container justifyContent="flex-start" alignItems="flex-start"> | |||
@@ -186,6 +188,28 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
}} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("Supplier")} | |||
fullWidth | |||
{...register("supplier", { | |||
// required: "productLotNo required!", | |||
})} | |||
disabled={true} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("productLotNo")} | |||
fullWidth | |||
{...register("productLotNo", { | |||
// required: "productLotNo required!", | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.productLotNo)} | |||
helperText={errors.productLotNo?.message} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<Controller | |||
control={control} | |||
@@ -227,14 +251,12 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("productLotNo")} | |||
label={t("qty")} | |||
fullWidth | |||
{...register("productLotNo", { | |||
// required: "productLotNo required!", | |||
{...register("qty", { | |||
required: "qty required!", | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.productLotNo)} | |||
helperText={errors.productLotNo?.message} | |||
disabled={true} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
@@ -275,6 +297,27 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
}} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("receivedQty")} | |||
fullWidth | |||
{...register("receivedQty", { | |||
required: "receivedQty required!", | |||
})} | |||
disabled={true} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("uom")} | |||
fullWidth | |||
{...register("uom", { | |||
required: "uom required!", | |||
})} | |||
value={uom.code} | |||
disabled={true} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("acceptedQty")} | |||
@@ -282,9 +325,10 @@ const StockInFormVer2: React.FC<Props> = ({ | |||
{...register("acceptedQty", { | |||
required: "acceptedQty required!", | |||
})} | |||
disabled={disabled} | |||
error={Boolean(errors.acceptedQty)} | |||
helperText={errors.acceptedQty?.message} | |||
disabled={true} | |||
// disabled={disabled} | |||
// error={Boolean(errors.acceptedQty)} | |||
// helperText={errors.acceptedQty?.message} | |||
/> | |||
</Grid> | |||
{/* <Grid item xs={4}> | |||
@@ -3,8 +3,8 @@ import { PutawayLine } from "@/app/api/po/actions" | |||
export interface QcData { | |||
id: number, | |||
qcItem: string, | |||
qcDescription: string, | |||
isPassed: boolean | undefined | |||
isFailed: boolean | undefined | |||
failedQty: number | undefined | |||
remarks: string | undefined | |||
} | |||
@@ -12,25 +12,41 @@ export interface QcData { | |||
export const dummyQCData: QcData[] = [ | |||
{ | |||
id: 1, | |||
qcItem: "目測", | |||
qcItem: "包裝", | |||
qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | |||
isPassed: undefined, | |||
isFailed: undefined, | |||
failedQty: undefined, | |||
remarks: undefined, | |||
}, | |||
{ | |||
id: 2, | |||
qcItem: "目測2", | |||
qcItem: "肉質", | |||
qcDescription: "肉質鬆散,則不合格", | |||
isPassed: undefined, | |||
isFailed: undefined, | |||
failedQty: undefined, | |||
remarks: undefined, | |||
}, | |||
{ | |||
id: 3, | |||
qcItem: "目測3", | |||
qcItem: "顔色", | |||
qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,", | |||
isPassed: undefined, | |||
failedQty: undefined, | |||
remarks: undefined, | |||
}, | |||
{ | |||
id: 4, | |||
qcItem: "狀態", | |||
qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | |||
isPassed: undefined, | |||
failedQty: undefined, | |||
remarks: undefined, | |||
}, | |||
{ | |||
id: 5, | |||
qcItem: "異物", | |||
qcDescription: "有不屬於本食材的雜質,則不合格", | |||
isPassed: undefined, | |||
isFailed: undefined, | |||
failedQty: undefined, | |||
remarks: undefined, | |||
}, | |||
@@ -38,6 +38,10 @@ | |||
"processed": "已處理數量", | |||
"expiryDate": "到期日", | |||
"acceptedQty": "是次來貨數量", | |||
"putawayQty": "上架數量", | |||
"acceptQty": "揀收數量", | |||
"printQty": "列印數量", | |||
"qcResult": "品檢結果", | |||
"weight": "重量", | |||
"start": "開始", | |||
"qc": "質量控制", | |||
@@ -45,7 +49,11 @@ | |||
"stock in": "入庫", | |||
"putaway": "上架", | |||
"delete": "刪除", | |||
"Accept quantity must be greater than 0": "揀收數量不能少於1", | |||
"QC items without result": "請完成品檢結果", | |||
"Failed items must have failed quantity": "請輸入不合格數量", | |||
"qty cannot be greater than remaining qty": "數量不能大於剩餘數量", | |||
"acceptQty must not greater than": "揀收數量不能大於", | |||
"Record pol": "記錄採購訂單", | |||
"Add some entries!": "添加條目!", | |||
"draft": "草稿", | |||
@@ -74,9 +82,10 @@ | |||
"Escalation": "上報", | |||
"to be processed": "待處理", | |||
"supervisor": "管理層", | |||
"Stock In Detail": "入庫詳情", | |||
"productLotNo": "產品批號", | |||
"productLotNo": "貨品批號", | |||
"receiptDate": "收貨日期", | |||
"acceptedWeight": "接受重量", | |||
"productionDate": "生產日期", | |||
@@ -94,7 +103,7 @@ | |||
"receivedQty": "已來貨數量", | |||
"dnQty": "送貨單數量", | |||
"Accept submit": "處理來貨", | |||
"Accept submit": "接受來貨", | |||
"qc processing": "處理來貨及品檢", | |||
"putawayBtn": "上架", | |||
"dnNo": "送貨單編號", | |||
@@ -177,7 +177,7 @@ const components: ThemeOptions["components"] = { | |||
styleOverrides: { | |||
root: { | |||
"& .MuiFilledInput-root": { | |||
paddingTop: 8, | |||
paddingTop: 16, | |||
paddingBottom: 8, | |||
}, | |||
}, | |||
@@ -315,6 +315,7 @@ const components: ThemeOptions["components"] = { | |||
root: { | |||
borderBottomColor: palette.divider, | |||
padding: "1px 6px", | |||
fontSize: defaultFontSize - 2, | |||
// padding: "15px 16px", | |||
// lineHeight: 1.5, | |||
}, | |||