MSI\derek преди 2 седмици
родител
ревизия
80e1b9b8a1
променени са 4 файла, в които са добавени 769 реда и са изтрити 245 реда
  1. +391
    -67
      src/components/PoDetail/QCDatagrid.tsx
  2. +140
    -22
      src/components/PoDetail/QcFormVer2.tsx
  3. +236
    -154
      src/components/PoDetail/QcStockInModalVer2.tsx
  4. +2
    -2
      src/components/PoDetail/StockInForm.tsx

+ 391
- 67
src/components/PoDetail/QCDatagrid.tsx Целия файл

@@ -1,71 +1,395 @@
"use client"

import { MutableRefObject } from "react";
import StyledDataGrid from "../StyledDataGrid"
import { GridApiCommunity } from "@mui/x-data-grid/internals";
import { GridColDef } from "@mui/x-data-grid";
"use client";
import {
Dispatch,
MutableRefObject,
SetStateAction,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import StyledDataGrid from "../StyledDataGrid";
import {
FooterPropsOverrides,
GridActionsCellItem,
GridCellParams,
GridColDef,
GridEventListener,
GridRowEditStopReasons,
GridRowId,
GridRowIdGetter,
GridRowModel,
GridRowModes,
GridRowModesModel,
GridRowSelectionModel,
GridToolbarContainer,
GridValidRowModel,
useGridApiRef,
} from "@mui/x-data-grid";
import { set, useFormContext } from "react-hook-form";
import SaveIcon from "@mui/icons-material/Save";
import DeleteIcon from "@mui/icons-material/Delete";
import CancelIcon from "@mui/icons-material/Cancel";
import { Add } from "@mui/icons-material";
import { Box, Button, Typography } from "@mui/material";
import { useTranslation } from "react-i18next";
import { dummyQCData, QcData } from "./dummyQcTemplate";
import { Checkbox } from "@mui/material";
import {
GridApiCommunity,
GridSlotsComponentsProps,
} from "@mui/x-data-grid/internals";
import { dummyQCData } from "./dummyQcTemplate";
// T == CreatexxxInputs map of the form's fields
// V == target field input inside CreatexxxInputs, e.g. qcChecks: ItemQc[], V = ItemQc
// E == error
interface ResultWithId {
id: string | number;
}
// export type InputGridProps = {
// [key: string]: any
// }
interface DefaultResult<E> {
_isNew: boolean;
_error: E;
}

interface Props {
// apiRef: MutableRefObject<GridApiCommunity>;
};
interface SelectionResult<E> {
active: boolean;
_isNew: boolean;
_error: E;
}
type Result<E> = DefaultResult<E> | SelectionResult<E>;

export type TableRow<V, E> = Partial<
V & {
isActive: boolean | undefined;
_isNew: boolean;
_error: E;
} & ResultWithId
>;

export interface InputDataGridProps<T, V, E> {
apiRef: MutableRefObject<GridApiCommunity>;
// checkboxSelection: false | undefined;
_formKey: keyof T;
columns: GridColDef[];
validateRow: (newRow: GridRowModel<TableRow<V, E>>) => E;
needAdd?: boolean;
}

export interface SelectionInputDataGridProps<T, V, E> {
// thinking how do
apiRef: MutableRefObject<GridApiCommunity>;
// checkboxSelection: true;
_formKey: keyof T;
columns: GridColDef[];
validateRow: (newRow: GridRowModel<TableRow<V, E>>) => E;
}

export type Props<T, V, E> =
| InputDataGridProps<T, V, E>
| SelectionInputDataGridProps<T, V, E>;
export class ProcessRowUpdateError<T, E> extends Error {
public readonly row: T;
public readonly errors: E | undefined;
constructor(row: T, message?: string, errors?: E) {
super(message);
this.row = row;
this.errors = errors;

Object.setPrototypeOf(this, ProcessRowUpdateError.prototype);
}
}
// T == CreatexxxInputs map of the form's fields
// V == target field input inside CreatexxxInputs, e.g. qcChecks: ItemQc[], V = ItemQc
// E == error
function InputDataGrid<T, V, E>({
apiRef,
// checkboxSelection = false,
_formKey,
columns,
validateRow,
}: Props<T, V, E>) {
const {
t,
// i18n: { language },
} = useTranslation("purchaseOrder");
const formKey = _formKey.toString();
const { setValue, getValues } = useFormContext();
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
// const apiRef = useGridApiRef();
const getRowId = useCallback<GridRowIdGetter<TableRow<V, E>>>(
(row) => row.id! as number,
[],
);
const formValue = getValues(formKey)
const list: TableRow<V, E>[] = !formValue || formValue.length == 0 ? dummyQCData : getValues(formKey);
console.log(list)
const [rows, setRows] = useState<TableRow<V, E>[]>(() => {
// const list: TableRow<V, E>[] = getValues(formKey);
console.log(list)
return list && list.length > 0 ? list : [];
});
console.log(rows)
// const originalRows = list && list.length > 0 ? list : [];
const originalRows = useMemo(() => (
list && list.length > 0 ? list : []
), [list])
// const originalRowModel = originalRows.filter((li) => li.isActive).map(i => i.id) as GridRowSelectionModel
const [rowSelectionModel, setRowSelectionModel] =
useState<GridRowSelectionModel>(() => {
// const rowModel = list.filter((li) => li.isActive).map(i => i.id) as GridRowSelectionModel
const rowModel: GridRowSelectionModel = getValues(
`${formKey}_active`,
) as GridRowSelectionModel;
console.log(rowModel);
return rowModel;
});

useEffect(() => {
for (let i = 0; i < rows.length; i++) {
const currRow = rows[i]
setRowModesModel((prevRowModesModel) => ({
...prevRowModesModel,
[currRow.id as number]: { mode: GridRowModes.View },
}));
}
}, [rows])

const handleSave = useCallback(
(id: GridRowId) => () => {
setRowModesModel((prevRowModesModel) => ({
...prevRowModesModel,
[id]: { mode: GridRowModes.View },
}));
},
[],
);
const onProcessRowUpdateError = useCallback(
(updateError: ProcessRowUpdateError<T, E>) => {
const errors = updateError.errors;
const row = updateError.row;
console.log(errors);
apiRef.current.updateRows([{ ...row, _error: errors }]);
},
[apiRef],
);

const processRowUpdate = useCallback(
(
newRow: GridRowModel<TableRow<V, E>>,
originalRow: GridRowModel<TableRow<V, E>>,
) => {
/////////////////
// validation here
const errors = validateRow(newRow);
console.log(newRow);
if (errors) {
throw new ProcessRowUpdateError(
originalRow,
"validation error",
errors,
);
}
/////////////////
const { _isNew, _error, ...updatedRow } = newRow;
const rowToSave = {
...updatedRow,
} as TableRow<V, E>; /// test
console.log(rowToSave);
setRows((rw) =>
rw.map((r) => (getRowId(r) === getRowId(originalRow) ? rowToSave : r)),
);
return rowToSave;
},
[validateRow, getRowId],
);

const addRow = useCallback(() => {
const newEntry = { id: Date.now(), _isNew: true } as TableRow<V, E>;
setRows((prev) => [...prev, newEntry]);
setRowModesModel((model) => ({
...model,
[getRowId(newEntry)]: {
mode: GridRowModes.Edit,
// fieldToFocus: "team", /// test
},
}));
}, [getRowId]);

const reset = useCallback(() => {
setRowModesModel({});
setRows(originalRows);
}, [originalRows]);

const QcDataGrid: React.FC<Props> = ({
// apiRef
}) => {
const { t } = useTranslation("purchaseOrder");

const columns: GridColDef[] = [
{
field: "qcItem",
headerName: t("qcItem"),
flex: 1,
},
{
field: "isPassed",
headerName: t("passed"),
flex: 1,
renderCell: (params) => (
<Checkbox
checked={params.value}
// onChange={() => handleCheckboxChange(params.id)}
/>
),
},
{
field: "isFailed",
headerName: t("failed"),
flex: 1,
renderCell: (params) => (
<Checkbox
checked={params.value}
// onChange={() => handleCheckboxChange(params.id)}
/>
),
},
{
field: "failedQty",
headerName: t("failedQty"),
flex: 1,
editable: true,
},
{
field: "remarks",
headerName: t("remarks"),
flex: 1,
editable: true,
},
]
return (
<StyledDataGrid
// apiRef={apiRef}
autoHeight
editMode="row"
rows={dummyQCData}
columns={columns}
/>
)
const handleCancel = useCallback(
(id: GridRowId) => () => {
setRowModesModel((model) => ({
...model,
[id]: { mode: GridRowModes.View, ignoreModifications: true },
}));
const editedRow = rows.find((row) => getRowId(row) === id);
if (editedRow?._isNew) {
setRows((rw) => rw.filter((r) => getRowId(r) !== id));
} else {
setRows((rw) =>
rw.map((r) => (getRowId(r) === id ? { ...r, _error: undefined } : r)),
);
}
},
[rows, getRowId],
);

const handleDelete = useCallback(
(id: GridRowId) => () => {
setRows((prevRows) => prevRows.filter((row) => getRowId(row) !== id));
},
[getRowId],
);

const _columns = useMemo<GridColDef[]>(
() => [
...columns,
{
field: "actions",
type: "actions",
headerName: "",
flex: 0.5,
cellClassName: "actions",
getActions: ({ id }: { id: GridRowId }) => {
const isInEditMode = rowModesModel[id]?.mode === GridRowModes.Edit;
if (isInEditMode) {
return [
<GridActionsCellItem
icon={<SaveIcon />}
label="Save"
key="edit"
sx={{
color: "primary.main",
}}
onClick={handleSave(id)}
/>,
<GridActionsCellItem
icon={<CancelIcon />}
label="Cancel"
key="edit"
onClick={handleCancel(id)}
/>,
];
}
return [
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
sx={{
color: "error.main",
}}
onClick={handleDelete(id)}
color="inherit"
key="edit"
/>,
];
},
},
],
[columns, rowModesModel, handleSave, handleCancel, handleDelete],
);
// sync useForm
useEffect(() => {
// console.log(formKey)
// console.log(rows)
setValue(formKey, rows);
}, [formKey, rows, setValue]);

const footer = (
<Box display="flex" gap={2} alignItems="center">
<Button
disableRipple
variant="outlined"
startIcon={<Add />}
onClick={addRow}
size="small"
>
新增
{/* {t("Add Record")} */}
</Button>
<Button
disableRipple
variant="outlined"
startIcon={<Add />}
onClick={reset}
size="small"
>
{/* {t("Clean Record")} */}
清除
</Button>
</Box>
);
// const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => {
// if (params.reason === GridRowEditStopReasons.rowFocusOut) {
// event.defaultMuiPrevented = true;
// }
// };

return (
<StyledDataGrid
// {...props}
// getRowId={getRowId as GridRowIdGetter<GridValidRowModel>}
rowSelectionModel={rowSelectionModel}
apiRef={apiRef}
rows={rows}
columns={columns}
editMode="row"
autoHeight
sx={{
"--DataGrid-overlayHeight": "100px",
".MuiDataGrid-row .MuiDataGrid-cell.hasError": {
border: "1px solid",
borderColor: "error.main",
},
".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": {
border: "1px solid",
borderColor: "warning.main",
},
}}
disableColumnMenu
processRowUpdate={processRowUpdate as any}
// onRowEditStop={handleRowEditStop}
rowModesModel={rowModesModel}
onRowModesModelChange={setRowModesModel}
onProcessRowUpdateError={onProcessRowUpdateError}
getCellClassName={(params: GridCellParams<TableRow<T, E>>) => {
let classname = "";
if (params.row._error) {
classname = "hasError";
}
return classname;
}}
slots={{
// footer: FooterToolbar,
noRowsOverlay: NoRowsOverlay,
}}
// slotProps={{
// footer: { child: footer },
// }
// }
/>
);
}
export default QcDataGrid
const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
};
const NoRowsOverlay: React.FC = () => {
const { t } = useTranslation("home");
return (
<Box
display="flex"
justifyContent="center"
alignItems="center"
height="100%"
>
<Typography variant="caption">{t("Add some entries!")}</Typography>
</Box>
);
};
export default InputDataGrid;

+ 140
- 22
src/components/PoDetail/QcFormVer2.tsx Целия файл

@@ -5,6 +5,7 @@ import {
Box,
Card,
CardContent,
Checkbox,
Grid,
Stack,
Tab,
@@ -17,7 +18,7 @@ import {
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import StyledDataGrid from "../StyledDataGrid";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
import {
GridColDef,
GridRowIdGetter,
@@ -43,22 +44,25 @@ import axiosInstance from "@/app/(main)/axios/axiosInstance";
import EscalationComponent from "./EscalationComponent";
import QcDataGrid from "./QCDatagrid";
import StockInFormVer2 from "./StockInFormVer2";
import { dummyEscalationHistory } from "./dummyQcTemplate";
import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate";
import { ModalFormInput } from "@/app/api/dashboard/actions";

interface Props {
itemDetail: StockInLine;
qc: QcItemWithChecks[];
disabled: boolean;
qcItems: QcData[]
setQcItems: Dispatch<SetStateAction<QcData[]>>
}
type EntryError =
| {
[field in keyof PurchaseQcResult]?: string;
[field in keyof QcData]?: string;
}
| undefined;

type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>;
type QcRow = TableRow<Partial<QcData>, EntryError>;
// fetchQcItemCheck
const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcItems }) => {
const { t } = useTranslation("purchaseOrder");
const apiRef = useGridApiRef();
const {
@@ -76,6 +80,8 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
const [tabIndex, setTabIndex] = useState(0);
const [rowSelectionModel, setRowSelectionModel] = useState<GridRowSelectionModel>()
const [qcResult, setQcResult] = useState(dummyEscalationHistory)
// const [qcItems, setQcItems] = useState(dummyQCData)

const column = useMemo<GridColDef[]>(
() => [
@@ -137,18 +143,18 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
// flex: 1,
// editable: !disabled,
// valueFormatter(params) {
// const row = params.id ? params.api.getRow<PoQcRow>(params.id) : null;
// 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<PoQcRow, number>) {
// renderCell(params: GridRenderCellParams<QcRow, number>) {
// console.log(params.value);
// return <TwoLineCell>{params.formattedValue}</TwoLineCell>;
// },
// renderEditCell(params: GridRenderEditCellParams<PoQcRow, number>) {
// renderEditCell(params: GridRenderEditCellParams<QcRow, number>) {
// const errorMessage =
// params.row._error?.[params.field as keyof PurchaseQcResult];
// console.log(errorMessage);
@@ -185,7 +191,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
// flex: 1,
// editable: !disabled,
// type: "number",
// renderEditCell(params: GridRenderEditCellParams<PoQcRow>) {
// renderEditCell(params: GridRenderEditCellParams<QcRow>) {
// // const recordQty = params.row.qty
// // if (recordQty !== undefined) {
// // setUnrecordQty((prev) => prev - recordQty)
@@ -217,23 +223,124 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
);
/// validate datagrid
const validation = useCallback(
(newRow: GridRowModel<PoQcRow>): EntryError => {
(newRow: GridRowModel<QcRow>): EntryError => {
const error: EntryError = {};
const { qcItemId, failQty } = newRow;
if (!qcItemId || qcItemId <= 0) {
error["qcItemId"] = t("select qc");
}
if (!failQty || failQty <= 0) {
error["failQty"] = t("enter a failQty");
}
if (failQty && failQty > itemDetail.acceptedQty) {
error["failQty"] = t("qty too big");
}
// const { qcItemId, failQty } = newRow;
return Object.keys(error).length > 0 ? error : undefined;
},
[],
);

function BooleanEditCell(params: GridRenderEditCellParams) {
const apiRef = useGridApiContext();
const { id, field, value } = params;

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
apiRef.current.setEditCellValue({ id, field, value: e.target.checked });
apiRef.current.stopCellEditMode({ id, field }); // commit immediately
};

return <Checkbox checked={!!value} onChange={handleChange} sx={{ p: 0 }} />;
}

const qcColumns: GridColDef[] = [
{
field: "qcItem",
headerName: t("qcItem"),
flex: 1,
},
{
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 } : r))
);
}}
size="small"
/>
),
},
{
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 } : r))
);
}}
size="small"
/>
),
},
{
field: "failedQty",
headerName: t("failedQty"),
flex: 1,
// editable: true,
renderCell: (params) => (
<TextField
type="number"
size="small"
value={params.value ?? ''}
onChange={(e) => {
const v = e.target.value;
const next = v === '' ? undefined : Number(v);
if (Number.isNaN(next)) return;
setQcItems((prev) =>
prev.map((r) => (r.id === params.id ? { ...r, failedQty: next } : r))
);
}}
onClick={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
inputProps={{ min: 0 }}
sx={{ width: '100%' }}
/>
),
},
{
field: "remarks",
headerName: t("remarks"),
flex: 1,
renderCell: (params) => (
<TextField
size="small"
value={params.value ?? ''}
onChange={(e) => {
const remarks = e.target.value;
// const next = v === '' ? undefined : Number(v);
// if (Number.isNaN(next)) return;
setQcItems((prev) =>
prev.map((r) => (r.id === params.id ? { ...r, remarks: remarks } : r))
);
}}
onClick={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
inputProps={{ min: 0 }}
sx={{ width: '100%' }}
/>
),
},
]

useEffect(() => {
console.log(itemDetail);
const status = "receiving";
@@ -268,10 +375,21 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
{tabIndex == 0 && (
<>
<Grid item xs={12}>
<QcDataGrid/>
{/* <QcDataGrid<ModalFormInput, QcData, EntryError>
apiRef={apiRef}
columns={qcColumns}
_formKey="qcResult"
validateRow={validation}
/> */}
<StyledDataGrid
columns={qcColumns}
rows={qcItems}
autoHeight
/>
</Grid>
<Grid item xs={4}>
<TextField
type="number"
label={t("acceptedQty")}
fullWidth
/>
@@ -296,7 +414,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled }) => {
</Grid>
<Grid item xs={12}>
<StyledDataGrid
rows={dummyEscalationHistory}
rows={qcResult}
columns={columns}
onRowSelectionModelChange={(newRowSelectionModel) => {
setRowSelectionModel(newRowSelectionModel);


+ 236
- 154
src/components/PoDetail/QcStockInModalVer2.tsx Целия файл

@@ -1,9 +1,16 @@
"use client";

import { StockInLine } from "@/app/api/po";
import { ModalFormInput, PurchaseQcResult } from "@/app/api/po/actions";
import { QcItemWithChecks } from "@/app/api/qc";
import { Box, Button, Grid, Modal, ModalProps, Stack, Typography } from "@mui/material";
import {
Box,
Button,
Grid,
Modal,
ModalProps,
Stack,
Typography,
} from "@mui/material";
import { Dispatch, SetStateAction, useCallback, useState } from "react";
import { FormProvider, SubmitHandler, useForm } from "react-hook-form";
import { StockInLineRow } from "./PoInputGrid";
@@ -12,8 +19,8 @@ import StockInForm from "./StockInForm";
import StockInFormVer2 from "./StockInFormVer2";
import QcFormVer2 from "./QcFormVer2";
import PutawayForm from "./PutawayForm";
import { dummyPutawayLine } from "./dummyQcTemplate";
import { dummyPutawayLine, dummyQCData } from "./dummyQcTemplate";
import { useGridApiRef } from "@mui/x-data-grid";
const style = {
position: "absolute",
top: "50%",
@@ -25,9 +32,8 @@ const style = {
pb: 10,
display: "block",
width: { xs: "60%", sm: "60%", md: "60%" },
// height: { xs: "60%", sm: "60%", md: "60%" },
// height: { xs: "60%", sm: "60%", md: "60%" },
};

interface CommonProps extends Omit<ModalProps, "children"> {
// setRows: Dispatch<SetStateAction<PurchaseOrderLine[]>>;
setEntries?: Dispatch<SetStateAction<StockInLineRow[]>>;
@@ -43,12 +49,10 @@ interface CommonProps extends Omit<ModalProps, "children"> {
>;
qc?: QcItemWithChecks[];
warehouse?: any[];
// type: "qc" | "stockIn" | "escalation" | "putaway" | "reject";
// type: "qc" | "stockIn" | "escalation" | "putaway" | "reject";
}

interface Props extends CommonProps{
interface Props extends CommonProps {
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] };

}
const PoQcStockInModalVer2: React.FC<Props> = ({
// type,
@@ -62,165 +66,243 @@ const PoQcStockInModalVer2: React.FC<Props> = ({
qc,
warehouse,
}) => {
console.log(warehouse)
const {
t,
i18n: { language },
} = useTranslation("purchaseOrder");
console.log(warehouse);
const {
t,
i18n: { language },
} = useTranslation("purchaseOrder");
const [qcItems, setQcItems] = useState(dummyQCData)
const formProps = useForm<ModalFormInput>({
defaultValues: {
...itemDetail,
putawayLine: dummyPutawayLine
putawayLine: dummyPutawayLine,
// receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT),
// warehouseId: itemDetail.defaultWarehouseId || 0
},
});
const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>(
(...args) => {
onClose?.(...args);
// reset();
},
[onClose],
);
const [openPutaway, setOpenPutaway] = useState(false)
(...args) => {
onClose?.(...args);
// reset();
},
[onClose],
);
const [openPutaway, setOpenPutaway] = useState(false);
const onOpenPutaway = useCallback(() => {
setOpenPutaway(true);
}, []);

const onClosePutaway = useCallback(() => {
setOpenPutaway(false);
}, []);

const [submissionType, setSubmissionType] = useState<"stockIn" | "qc" | "escalate" | undefined>(undefined)
const onSubmit = useCallback<SubmitHandler<ModalFormInput>>(
// Stock In submission handler
const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>(
async (data, event) => {
console.log(event!.nativeEvent)
// closeHandler({}, "backdropClick");
// for now go to putaway form
onOpenPutaway()

// divide 3 section for this submition
// switch (submissionType) {
// submit stock in data
// submit qc data
// submit putaway
// }
console.log("Stock In Submission:", event!.nativeEvent);
// Extract only stock-in related fields
const stockInData = {
// quantity: data.quantity,
// receiptDate: data.receiptDate,
// batchNumber: data.batchNumber,
// expiryDate: data.expiryDate,
// warehouseId: data.warehouseId,
// location: data.location,
// unitCost: data.unitCost,
data: data,
// Add other stock-in specific fields from your form
};
console.log("Stock In Data:", stockInData);
// Handle stock-in submission logic here
// e.g., call API, update state, etc.
},
[],
);
// QC submission handler
const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>(
async (data, event) => {
console.log("QC Submission:", event!.nativeEvent);
// Extract only QC related fields
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
};
console.log(qcItems)
console.log("QC Data:", qcData);
// Handle QC submission logic here
// After QC approval, open putaway form
// onOpenPutaway();
},
[onOpenPutaway, qcItems],
);
// Email supplier handler
const onSubmitEmailSupplier = useCallback<SubmitHandler<ModalFormInput>>(
async (data, event) => {
console.log("Email Supplier Submission:", event!.nativeEvent);
// Extract only email supplier related fields
const emailData = {
// supplierEmail: data.supplierEmail,
// issueDescription: data.issueDescription,
// qcComments: data.qcComments,
// defectNotes: data.defectNotes,
// attachments: data.attachments,
// escalationReason: data.escalationReason,
data: data,

}, [submissionType])
// Add other email-specific fields
};
console.log("Email Supplier Data:", emailData);
// Handle email supplier logic here
// e.g., send email to supplier, log escalation, etc.
},
[],
);
// Putaway submission handler
const onSubmitPutaway = useCallback<SubmitHandler<ModalFormInput>>(
async (data, event) => {
console.log("Putaway Submission:", event!.nativeEvent);
// Extract only putaway related fields
const putawayData = {
// putawayLine: data.putawayLine,
// putawayLocation: data.putawayLocation,
// binLocation: data.binLocation,
// putawayQuantity: data.putawayQuantity,
// putawayNotes: data.putawayNotes,
data: data,

return (
<>
{/* {itemDetail !== undefined && (
<PutawayForm
itemDetail={itemDetail}
warehouse={warehouse!}
disabled={false}
/>
)} */}
<FormProvider {...formProps}>
<Modal open={open} onClose={closeHandler}>
<Box
sx={{
...style,
padding: 2, // Add padding to the Box
maxHeight: '90vh', // Limit the height of the modal
overflowY: 'auto', // Enable scrolling if content overflows
marginLeft: 3,
marginRight: 3,
}}
component="form"
onSubmit={formProps.handleSubmit(onSubmit)}
>
{openPutaway ? (
<>
<PutawayForm
itemDetail={itemDetail}
warehouse={warehouse!}
disabled={false}
/>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="qc"
type="button"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
>
{t("print")}
</Button>
<Button
id="qc"
type="submit"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
>
{t("confirm putaway")}
</Button>
</Stack>
</>
// Add other putaway specific fields
};
console.log("Putaway Data:", putawayData);
// Handle putaway submission logic here
// Close modal after successful putaway
closeHandler({}, "backdropClick");
},
[closeHandler],
);
// Print handler
const onPrint = useCallback(() => {
console.log("Print putaway documents");
// Handle print logic here
window.print();
}, []);
return (
<>
<FormProvider {...formProps}>
<Modal open={open} onClose={closeHandler}>
<Box
sx={{
...style,
padding: 2,
maxHeight: "90vh",
overflowY: "auto",
marginLeft: 3,
marginRight: 3,
}}
>
{openPutaway ? (
<Box
component="form"
onSubmit={formProps.handleSubmit(onSubmitPutaway)}
>
<PutawayForm
itemDetail={itemDetail}
warehouse={warehouse!}
disabled={false}
/>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="printButton"
type="button"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
onClick={onPrint}
>
{t("print")}
</Button>
<Button
id="putawaySubmit"
type="submit"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
>
{t("confirm putaway")}
</Button>
</Stack>
</Box>
) : (
<>
<Grid container justifyContent="flex-start" alignItems="flex-start">
<Grid item xs={12}>
<Typography variant="h6" display="block" marginBlockEnd={1}>
{t("qc processing")}
</Typography>
</Grid>
<Grid item xs={12}>
<StockInFormVer2
itemDetail={itemDetail}
disabled={false}
/>
</Grid>
</Grid>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="stockIn"
type="button"
variant="contained"
color="primary"
>
{t("submitStockIn")}
</Button>
</Stack>
<Grid container justifyContent="flex-start" alignItems="flex-start">
<QcFormVer2
qc={qc!}
itemDetail={itemDetail}
disabled={false}
/>
</Grid>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="qc"
type="button"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
>
{t("email supplier")}
</Button>
<Button
id="qc"
type="submit"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
>
{t("confirm putaway")}
</Button>
</Stack>
</>
)

}
</Box>
</Modal>
</FormProvider>
</>
)
}
export default PoQcStockInModalVer2
<>
<Grid
container
justifyContent="flex-start"
alignItems="flex-start"
>
<Grid item xs={12}>
<Typography variant="h6" display="block" marginBlockEnd={1}>
{t("qc processing")}
</Typography>
</Grid>
<Grid item xs={12}>
<StockInFormVer2 itemDetail={itemDetail} disabled={false} />
</Grid>
</Grid>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="stockInSubmit"
type="button"
variant="contained"
color="primary"
onClick={formProps.handleSubmit(onSubmitStockIn)}
>
{t("submitStockIn")}
</Button>
</Stack>
<Grid
container
justifyContent="flex-start"
alignItems="flex-start"
>
<QcFormVer2
qc={qc!}
itemDetail={itemDetail}
disabled={false}
qcItems={qcItems}
setQcItems={setQcItems}
/>
</Grid>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
id="emailSupplier"
type="button"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
onClick={formProps.handleSubmit(onSubmitEmailSupplier)}
>
{t("email supplier")}
</Button>
<Button
id="qcSubmit"
type="button"
variant="contained"
color="secondary"
sx={{ mt: 1 }}
onClick={formProps.handleSubmit(onSubmitQc)}
>
{t("confirm putaway")}
</Button>
</Stack>
</>
)}
</Box>
</Modal>
</FormProvider>
</>
);
};
export default PoQcStockInModalVer2;

+ 2
- 2
src/components/PoDetail/StockInForm.tsx Целия файл

@@ -82,7 +82,7 @@ const StockInForm: React.FC<Props> = ({
// receiptDate default tdy
setValue("receiptDate", dayjs().add(0, "month").format(INPUT_DATE_FORMAT));
setValue("status", "received");
}, []);
}, [setValue]);

useEffect(() => {
console.log(errors);
@@ -97,7 +97,7 @@ const StockInForm: React.FC<Props> = ({
if (expiryDate) clearErrors();
if (productionDate) clearErrors();
}, [productionDate, expiryDate, clearErrors]);
return (
<Grid container justifyContent="flex-start" alignItems="flex-start">
<Grid item xs={12}>


Зареждане…
Отказ
Запис