瀏覽代碼

Merge branch 'master' of https://git.2fi-solutions.com/derek/FPSMS-frontend

# Conflicts:
#	src/components/PoDetail/PoDetail.tsx
master
CANCERYS\kw093 1 周之前
父節點
當前提交
16f7cf37f0
共有 12 個檔案被更改,包括 323 行新增206 行删除
  1. +7
    -1
      src/app/api/po/actions.ts
  2. +3
    -0
      src/app/api/po/index.ts
  3. +4
    -2
      src/components/InputDataGrid/InputDataGrid.tsx
  4. +4
    -5
      src/components/PoDetail/PoDetail.tsx
  5. +4
    -3
      src/components/PoDetail/PoInputGrid.tsx
  6. +1
    -0
      src/components/PoDetail/PutawayForm.tsx
  7. +141
    -156
      src/components/PoDetail/QcFormVer2.tsx
  8. +68
    -18
      src/components/PoDetail/QcStockInModalVer2.tsx
  9. +55
    -11
      src/components/PoDetail/StockInFormVer2.tsx
  10. +23
    -7
      src/components/PoDetail/dummyQcTemplate.tsx
  11. +11
    -2
      src/i18n/zh/purchaseOrder.json
  12. +2
    -1
      src/theme/devias-material-kit/components.ts

+ 7
- 1
src/app/api/po/actions.ts 查看文件

@@ -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 {


+ 3
- 0
src/app/api/po/index.ts 查看文件

@@ -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;


+ 4
- 2
src/components/InputDataGrid/InputDataGrid.tsx 查看文件

@@ -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) => {


+ 4
- 5
src/components/PoDetail/PoDetail.tsx 查看文件

@@ -182,8 +182,9 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
const searchParams = useSearchParams();
const [row, setRow] = useState(rows[0]);
const [stockInLine, setStockInLine] = useState<StockInLine[]>(rows[0].stockInLine);
const [processedQty, setProcessedQty] = useState(rows[0].processed);

const [stockInLine, setStockInLine] = useState<StockInLine[]>([]);
const [processedQty, setProcessedQty] = useState(0);

const router = useRouter();
const [poList, setPoList] = useState<PoResult[]>([]);
@@ -427,9 +428,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="輸入來貨數量"


+ 4
- 3
src/components/PoDetail/PoInputGrid.tsx 查看文件

@@ -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) => {


+ 1
- 0
src/components/PoDetail/PutawayForm.tsx 查看文件

@@ -499,6 +499,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
columns={columns}
validateRow={validation}
needAdd={true}
showRemoveBtn={false}
/>
</Grid>
</Grid>


+ 141
- 156
src/components/PoDetail/QcFormVer2.tsx 查看文件

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


+ 68
- 18
src/components/PoDetail/QcStockInModalVer2.tsx 查看文件

@@ -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)}
>


+ 55
- 11
src/components/PoDetail/StockInFormVer2.tsx 查看文件

@@ -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}>


+ 23
- 7
src/components/PoDetail/dummyQcTemplate.tsx 查看文件

@@ -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,
},


+ 11
- 2
src/i18n/zh/purchaseOrder.json 查看文件

@@ -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": "送貨單編號",


+ 2
- 1
src/theme/devias-material-kit/components.ts 查看文件

@@ -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,
},


Loading…
取消
儲存