@@ -11,7 +11,7 @@ import { QcItemResult } from "../settings/qcItem"; | |||||
import { RecordsRes } from "../utils"; | import { RecordsRes } from "../utils"; | ||||
// import { BASE_API_URL } from "@/config/api"; | // import { BASE_API_URL } from "@/config/api"; | ||||
export interface PostStockInLiineResponse<T> { | |||||
export interface PostStockInLineResponse<T> { | |||||
id: number | null; | id: number | null; | ||||
name: string; | name: string; | ||||
code: string; | code: string; | ||||
@@ -38,6 +38,7 @@ export interface StockInLineEntry { | |||||
export interface PurchaseQcResult { | export interface PurchaseQcResult { | ||||
qcItemId: number; | qcItemId: number; | ||||
failQty: number; | failQty: number; | ||||
isPassed: boolean; | |||||
} | } | ||||
export interface StockInInput { | export interface StockInInput { | ||||
status: string; | status: string; | ||||
@@ -49,11 +50,12 @@ export interface StockInInput { | |||||
expiryDate: string; | expiryDate: string; | ||||
} | } | ||||
export interface PurchaseQCInput { | export interface PurchaseQCInput { | ||||
status: string; | |||||
acceptedQty: number; | |||||
sampleRate: number; | |||||
sampleWeight: number; | |||||
totalWeight: number; | |||||
status?: string; | |||||
qcAccept: boolean; | |||||
acceptQty: number; | |||||
sampleRate?: number; | |||||
sampleWeight?: number; | |||||
totalWeight?: number; | |||||
qcResult: PurchaseQcResult[]; | qcResult: PurchaseQcResult[]; | ||||
} | } | ||||
export interface EscalationInput { | export interface EscalationInput { | ||||
@@ -92,7 +94,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { | |||||
export const createStockInLine = async (data: StockInLineEntry) => { | export const createStockInLine = async (data: StockInLineEntry) => { | ||||
console.log(data) | console.log(data) | ||||
const stockInLine = await serverFetchJson< | const stockInLine = await serverFetchJson< | ||||
PostStockInLiineResponse<StockInLineEntry> | |||||
PostStockInLineResponse<StockInLineEntry> | |||||
>(`${BASE_API_URL}/stockInLine/create`, { | >(`${BASE_API_URL}/stockInLine/create`, { | ||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
@@ -106,7 +108,7 @@ export const updateStockInLine = async ( | |||||
data: StockInLineEntry & ModalFormInput, | data: StockInLineEntry & ModalFormInput, | ||||
) => { | ) => { | ||||
const stockInLine = await serverFetchJson< | const stockInLine = await serverFetchJson< | ||||
PostStockInLiineResponse<StockInLineEntry & ModalFormInput> | |||||
PostStockInLineResponse<StockInLineEntry & ModalFormInput> | |||||
>(`${BASE_API_URL}/stockInLine/update`, { | >(`${BASE_API_URL}/stockInLine/update`, { | ||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
@@ -117,7 +119,7 @@ export const updateStockInLine = async ( | |||||
}; | }; | ||||
export const startPo = async (poId: number) => { | export const startPo = async (poId: number) => { | ||||
const po = await serverFetchJson<PostStockInLiineResponse<PoResult>>( | |||||
const po = await serverFetchJson<PostStockInLineResponse<PoResult>>( | |||||
`${BASE_API_URL}/po/start/${poId}`, | `${BASE_API_URL}/po/start/${poId}`, | ||||
{ | { | ||||
method: "POST", | method: "POST", | ||||
@@ -130,7 +132,7 @@ export const startPo = async (poId: number) => { | |||||
}; | }; | ||||
export const checkPolAndCompletePo = async (poId: number) => { | export const checkPolAndCompletePo = async (poId: number) => { | ||||
const po = await serverFetchJson<PostStockInLiineResponse<PoResult>>( | |||||
const po = await serverFetchJson<PostStockInLineResponse<PoResult>>( | |||||
`${BASE_API_URL}/po/check/${poId}`, | `${BASE_API_URL}/po/check/${poId}`, | ||||
{ | { | ||||
method: "POST", | method: "POST", | ||||
@@ -12,7 +12,7 @@ import { RecordsRes } from "../utils"; | |||||
import { Uom } from "../settings/uom"; | import { Uom } from "../settings/uom"; | ||||
// import { BASE_API_URL } from "@/config/api"; | // import { BASE_API_URL } from "@/config/api"; | ||||
export interface PostStockInLiineResponse<T> { | |||||
export interface PostStockInLineResponse<T> { | |||||
id: number | null; | id: number | null; | ||||
name: string; | name: string; | ||||
code: string; | code: string; | ||||
@@ -35,13 +35,16 @@ export interface StockInLineEntry { | |||||
export interface PurchaseQcResult { | export interface PurchaseQcResult { | ||||
qcItemId: number; | qcItemId: number; | ||||
isPassed: boolean, | |||||
failQty: number; | failQty: number; | ||||
remarks?: string | |||||
} | } | ||||
export interface StockInInput { | export interface StockInInput { | ||||
status: string; | status: string; | ||||
poCode: string; | poCode: string; | ||||
productLotNo?: string; | productLotNo?: string; | ||||
dnNo?: string; | dnNo?: string; | ||||
dnDate?: string; | |||||
itemName: string; | itemName: string; | ||||
invoiceNo?: string; | invoiceNo?: string; | ||||
receiptDate: string; | receiptDate: string; | ||||
@@ -107,7 +110,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { | |||||
export const createStockInLine = async (data: StockInLineEntry) => { | export const createStockInLine = async (data: StockInLineEntry) => { | ||||
const stockInLine = await serverFetchJson< | const stockInLine = await serverFetchJson< | ||||
PostStockInLiineResponse<StockInLineEntry> | |||||
PostStockInLineResponse<StockInLineEntry> | |||||
>(`${BASE_API_URL}/stockInLine/create`, { | >(`${BASE_API_URL}/stockInLine/create`, { | ||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
@@ -121,7 +124,7 @@ export const updateStockInLine = async ( | |||||
data: StockInLineEntry & ModalFormInput, | data: StockInLineEntry & ModalFormInput, | ||||
) => { | ) => { | ||||
const stockInLine = await serverFetchJson< | const stockInLine = await serverFetchJson< | ||||
PostStockInLiineResponse<StockInLineEntry & ModalFormInput> | |||||
PostStockInLineResponse<StockInLineEntry & ModalFormInput> | |||||
>(`${BASE_API_URL}/stockInLine/update`, { | >(`${BASE_API_URL}/stockInLine/update`, { | ||||
method: "POST", | method: "POST", | ||||
body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
@@ -132,7 +135,7 @@ export const updateStockInLine = async ( | |||||
}; | }; | ||||
export const startPo = async (poId: number) => { | export const startPo = async (poId: number) => { | ||||
const po = await serverFetchJson<PostStockInLiineResponse<PoResult>>( | |||||
const po = await serverFetchJson<PostStockInLineResponse<PoResult>>( | |||||
`${BASE_API_URL}/po/start/${poId}`, | `${BASE_API_URL}/po/start/${poId}`, | ||||
{ | { | ||||
method: "POST", | method: "POST", | ||||
@@ -145,7 +148,7 @@ export const startPo = async (poId: number) => { | |||||
}; | }; | ||||
export const checkPolAndCompletePo = async (poId: number) => { | export const checkPolAndCompletePo = async (poId: number) => { | ||||
const po = await serverFetchJson<PostStockInLiineResponse<PoResult>>( | |||||
const po = await serverFetchJson<PostStockInLineResponse<PoResult>>( | |||||
`${BASE_API_URL}/po/check/${poId}`, | `${BASE_API_URL}/po/check/${poId}`, | ||||
{ | { | ||||
method: "POST", | method: "POST", | ||||
@@ -54,6 +54,10 @@ export const arrayToDateString = (arr: ConfigType | (number | undefined)[]) => { | |||||
return arrayToDayjs(arr).format(OUTPUT_DATE_FORMAT); | return arrayToDayjs(arr).format(OUTPUT_DATE_FORMAT); | ||||
}; | }; | ||||
export const arrayToInputDateString = (arr: ConfigType | (number | undefined)[]) => { | |||||
return arrayToDayjs(arr).format(INPUT_DATE_FORMAT); | |||||
}; | |||||
export const dateStringToDayjs = (date: string) => { | export const dateStringToDayjs = (date: string) => { | ||||
// Format: YYYY/MM/DD | // Format: YYYY/MM/DD | ||||
return dayjs(date, OUTPUT_DATE_FORMAT); | return dayjs(date, OUTPUT_DATE_FORMAT); | ||||
@@ -55,10 +55,10 @@ const navigateTo = useCallback( | |||||
<Table aria-label="Two column navigable table" size="small"> | <Table aria-label="Two column navigable table" size="small"> | ||||
<TableHead> | <TableHead> | ||||
<TableRow> | <TableRow> | ||||
<TableCell>{t("purchase order code")}</TableCell> | |||||
<TableCell>{t("item name")}</TableCell> | |||||
<TableCell>{t("escalation level")}</TableCell> | |||||
<TableCell>{t("reason")}</TableCell> | |||||
<TableCell>{t("Purchase Order Code")}</TableCell> | |||||
<TableCell>{t("Item Name")}</TableCell> | |||||
<TableCell>{t("Escalation Level")}</TableCell> | |||||
<TableCell>{t("Reason")}</TableCell> | |||||
</TableRow> | </TableRow> | ||||
</TableHead> | </TableHead> | ||||
<TableBody> | <TableBody> | ||||
@@ -823,6 +823,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => { | |||||
setProcessedQty={setProcessedQty} | setProcessedQty={setProcessedQty} | ||||
itemDetail={selectedRow} | itemDetail={selectedRow} | ||||
warehouse={warehouse} | warehouse={warehouse} | ||||
fetchPoDetail={fetchPoDetail} | |||||
/> | /> | ||||
</Box> | </Box> | ||||
</TableCell> | </TableCell> | ||||
@@ -73,6 +73,7 @@ interface Props { | |||||
itemDetail: PurchaseOrderLine; | itemDetail: PurchaseOrderLine; | ||||
stockInLine: StockInLine[]; | stockInLine: StockInLine[]; | ||||
warehouse: WarehouseResult[]; | warehouse: WarehouseResult[]; | ||||
fetchPoDetail: (poId: string) => void; | |||||
} | } | ||||
export type StockInLineEntryError = { | export type StockInLineEntryError = { | ||||
@@ -111,6 +112,7 @@ function PoInputGrid({ | |||||
itemDetail, | itemDetail, | ||||
stockInLine, | stockInLine, | ||||
warehouse, | warehouse, | ||||
fetchPoDetail | |||||
}: Props) { | }: Props) { | ||||
console.log(itemDetail); | console.log(itemDetail); | ||||
const { t } = useTranslation("purchaseOrder"); | const { t } = useTranslation("purchaseOrder"); | ||||
@@ -272,6 +274,7 @@ const closeNewModal = useCallback(() => { | |||||
const newParams = new URLSearchParams(searchParams.toString()); | const newParams = new URLSearchParams(searchParams.toString()); | ||||
newParams.delete("stockInLineId"); // Remove the parameter | newParams.delete("stockInLineId"); // Remove the parameter | ||||
router.replace(`${pathname}?${newParams.toString()}`); | router.replace(`${pathname}?${newParams.toString()}`); | ||||
fetchPoDetail(itemDetail.purchaseOrderId.toString()); | |||||
setTimeout(() => { | setTimeout(() => { | ||||
setNewOpen(false); // Close the modal first | setNewOpen(false); // Close the modal first | ||||
}, 300); // Add a delay to avoid immediate re-trigger of useEffect | }, 300); // Add a delay to avoid immediate re-trigger of useEffect | ||||
@@ -413,6 +416,17 @@ const closeNewModal = useCallback(() => { | |||||
[], | [], | ||||
); | ); | ||||
const getButtonSx = (status : string) => { | |||||
let btnSx = {label:"", color:""}; | |||||
switch (status) { | |||||
case "received": btnSx = {label: t("putaway processing"), color:"secondary.main"}; break; | |||||
case "rejected": | |||||
case "completed": btnSx = {label: t("view stockin"), color:"info.main"}; break; | |||||
default: btnSx = {label: t("qc processing"), color:"success.main"}; | |||||
} | |||||
return btnSx | |||||
}; | |||||
// const handleQrCode = useCallback( | // const handleQrCode = useCallback( | ||||
// (id: GridRowId, params: any) => () => { | // (id: GridRowId, params: any) => () => { | ||||
// setRowModesModel((prev) => ({ | // setRowModesModel((prev) => ({ | ||||
@@ -532,7 +546,7 @@ const closeNewModal = useCallback(() => { | |||||
{ | { | ||||
field: "status", | field: "status", | ||||
headerName: t("Status"), | headerName: t("Status"), | ||||
width: 70, | |||||
width: 140, | |||||
// flex: 0.5, | // flex: 0.5, | ||||
renderCell: (params) => { | renderCell: (params) => { | ||||
return t(`${params.row.status}`); | return t(`${params.row.status}`); | ||||
@@ -546,20 +560,22 @@ const closeNewModal = useCallback(() => { | |||||
// )} | ${t("putaway")} | ${t("delete")}`, | // )} | ${t("putaway")} | ${t("delete")}`, | ||||
headerName: "動作", | headerName: "動作", | ||||
// headerName: "start | qc | escalation | stock in | putaway | delete", | // headerName: "start | qc | escalation | stock in | putaway | delete", | ||||
width: 300, | |||||
width: 200, | |||||
// flex: 2, | // flex: 2, | ||||
cellClassName: "actions", | cellClassName: "actions", | ||||
getActions: (params) => { | getActions: (params) => { | ||||
// console.log(params.row.status); | // console.log(params.row.status); | ||||
const status = params.row.status.toLowerCase(); | const status = params.row.status.toLowerCase(); | ||||
const btnSx = getButtonSx(status); | |||||
// console.log(stockInLineStatusMap[status]); | // console.log(stockInLineStatusMap[status]); | ||||
// console.log(session?.user?.abilities?.includes("APPROVAL")); | // console.log(session?.user?.abilities?.includes("APPROVAL")); | ||||
return [ | return [ | ||||
<GridActionsCellItem | <GridActionsCellItem | ||||
icon={<Button variant="contained">{t("qc processing")}</Button>} | |||||
icon={<Button variant="contained" sx={{ width: '150px', backgroundColor: btnSx.color }}> | |||||
{btnSx.label}</Button>} | |||||
label="start" | label="start" | ||||
sx={{ | sx={{ | ||||
color: "primary.main", | |||||
// color: "primary.main", | |||||
// marginRight: 1, | // marginRight: 1, | ||||
}} | }} | ||||
// disabled={!(stockInLineStatusMap[status] === 0)} | // disabled={!(stockInLineStatusMap[status] === 0)} | ||||
@@ -569,20 +585,21 @@ const closeNewModal = useCallback(() => { | |||||
color="inherit" | color="inherit" | ||||
key="edit" | key="edit" | ||||
/>, | />, | ||||
<GridActionsCellItem | |||||
icon={<Button variant="contained">{t("putawayBtn")}</Button>} | |||||
label="start" | |||||
sx={{ | |||||
color: "primary.main", | |||||
// marginRight: 1, | |||||
}} | |||||
// disabled={!(stockInLineStatusMap[status] === 0)} | |||||
// set _isNew to false after posting | |||||
// or check status | |||||
onClick={handleStart(params.row.id, params)} | |||||
color="inherit" | |||||
key="edit" | |||||
/>, | |||||
// <GridActionsCellItem | |||||
// icon={<Button variant="contained">{t("putawayBtn")}</Button>} | |||||
// label="start" | |||||
// sx={{ | |||||
// color: "primary.main", | |||||
// // marginRight: 1, | |||||
// }} | |||||
// // disabled={!(stockInLineStatusMap[status] === 0)} | |||||
// // set _isNew to false after posting | |||||
// // or check status | |||||
// onClick={handleStart(params.row.id, params)} | |||||
// color="inherit" | |||||
// key="edit" | |||||
// />, | |||||
// <GridActionsCellItem | // <GridActionsCellItem | ||||
// icon={<Button variant="contained">{t("qc processing")}</Button>} | // icon={<Button variant="contained">{t("qc processing")}</Button>} | ||||
// label="start" | // label="start" | ||||
@@ -121,9 +121,9 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||||
const params = useSearchParams(); | const params = useSearchParams(); | ||||
const [btnIsLoading, setBtnIsLoading] = useState(false); | const [btnIsLoading, setBtnIsLoading] = useState(false); | ||||
console.log(params.get("id")); | |||||
console.log(itemDetail); | |||||
console.log(itemDetail.qcResult); | |||||
// console.log(params.get("id")); | |||||
// console.log(itemDetail); | |||||
// console.log(itemDetail.qcResult); | |||||
const formProps = useForm<ModalFormInput>({ | const formProps = useForm<ModalFormInput>({ | ||||
defaultValues: { | defaultValues: { | ||||
...itemDetail, | ...itemDetail, | ||||
@@ -245,8 +245,9 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => { | |||||
}, [scanner.values]); | }, [scanner.values]); | ||||
useEffect(() => { | useEffect(() => { | ||||
setValue("status", "completed"); | |||||
setValue("warehouseId", options[0].value); | |||||
setValue("status", "received"); | |||||
// setValue("status", "completed"); | |||||
setValue("warehouseId", options[0].value); //TODO: save all warehouse entry? | |||||
}, []); | }, []); | ||||
useEffect(() => { | useEffect(() => { | ||||
@@ -51,6 +51,7 @@ import StockInFormVer2 from "./StockInFormVer2"; | |||||
import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; | import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; | ||||
import { ModalFormInput } from "@/app/api/dashboard/actions"; | import { ModalFormInput } from "@/app/api/dashboard/actions"; | ||||
import { escape } from "lodash"; | import { escape } from "lodash"; | ||||
import { PanoramaSharp } from "@mui/icons-material"; | |||||
interface Props { | interface Props { | ||||
itemDetail: StockInLine; | itemDetail: StockInLine; | ||||
@@ -216,7 +217,8 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
<FormControlLabel | <FormControlLabel | ||||
value="true" | value="true" | ||||
control={<Radio />} | control={<Radio />} | ||||
label="合格" | |||||
label="合格" | |||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
sx={{ | sx={{ | ||||
color: currentValue === true ? "green" : "inherit", | color: currentValue === true ? "green" : "inherit", | ||||
"& .Mui-checked": {color: "green"} | "& .Mui-checked": {color: "green"} | ||||
@@ -226,6 +228,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
value="false" | value="false" | ||||
control={<Radio />} | control={<Radio />} | ||||
label="不合格" | label="不合格" | ||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
sx={{ | sx={{ | ||||
color: currentValue === false ? "red" : "inherit", | color: currentValue === false ? "red" : "inherit", | ||||
"& .Mui-checked": {color: "red"} | "& .Mui-checked": {color: "red"} | ||||
@@ -237,7 +240,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
}, | }, | ||||
}, | }, | ||||
{ | { | ||||
field: "failedQty", | |||||
field: "failQty", | |||||
headerName: t("failedQty"), | headerName: t("failedQty"), | ||||
flex: 1, | flex: 1, | ||||
// editable: true, | // editable: true, | ||||
@@ -246,13 +249,13 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
type="number" | type="number" | ||||
size="small" | size="small" | ||||
value={!params.row.isPassed? (params.value ?? '') : '0'} | value={!params.row.isPassed? (params.value ?? '') : '0'} | ||||
disabled={params.row.isPassed} | |||||
disabled={params.row.isPassed || itemDetail.status.toLowerCase() == "completed"} | |||||
onChange={(e) => { | 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) => | setQcItems((prev) => | ||||
prev.map((r) => (r.id === params.id ? { ...r, failedQty: next } : r)) | |||||
prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r)) | |||||
); | ); | ||||
}} | }} | ||||
onClick={(e) => e.stopPropagation()} | onClick={(e) => e.stopPropagation()} | ||||
@@ -271,6 +274,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
<TextField | <TextField | ||||
size="small" | size="small" | ||||
value={params.value ?? ''} | value={params.value ?? ''} | ||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
onChange={(e) => { | onChange={(e) => { | ||||
const remarks = e.target.value; | const remarks = e.target.value; | ||||
// const next = v === '' ? undefined : Number(v); | // const next = v === '' ? undefined : Number(v); | ||||
@@ -296,10 +300,12 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
// Set initial value for acceptQty | // Set initial value for acceptQty | ||||
useEffect(() => { | useEffect(() => { | ||||
if (itemDetail?.acceptedQty !== undefined) { | |||||
setValue("acceptQty", itemDetail.acceptedQty); | |||||
if (itemDetail?.demandQty > 0) { //!== undefined) { | |||||
setValue("acceptQty", itemDetail.demandQty); // THIS NEED TO UPDATE TO NOT USE DEMAND QTY | |||||
} else { | |||||
setValue("acceptQty", itemDetail?.acceptedQty); | |||||
} | } | ||||
}, [itemDetail?.acceptedQty, setValue]); | |||||
}, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); | |||||
// const [openCollapse, setOpenCollapse] = useState(false) | // const [openCollapse, setOpenCollapse] = useState(false) | ||||
const [isCollapsed, setIsCollapsed] = useState<boolean>(false); | const [isCollapsed, setIsCollapsed] = useState<boolean>(false); | ||||
@@ -365,14 +371,14 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
{/* <Grid item xs={12}> | |||||
{!qcAccept && ( | |||||
<Grid item xs={12}> | |||||
<EscalationComponent | <EscalationComponent | ||||
forSupervisor={false} | forSupervisor={false} | ||||
isCollapsed={isCollapsed} | isCollapsed={isCollapsed} | ||||
setIsCollapsed={setIsCollapsed} | setIsCollapsed={setIsCollapsed} | ||||
/> | /> | ||||
</Grid> */} | |||||
</Grid>)} | |||||
</> | </> | ||||
)} | )} | ||||
{tabIndex == 1 && ( | {tabIndex == 1 && ( | ||||
@@ -419,14 +425,16 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
field.onChange(value); | field.onChange(value); | ||||
}} | }} | ||||
> | > | ||||
<FormControlLabel value="true" control={<Radio />} label="接受" /> | |||||
<FormControlLabel disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
value="true" control={<Radio />} label="接受" /> | |||||
<Box sx={{mr:2}}> | <Box sx={{mr:2}}> | ||||
<TextField | <TextField | ||||
type="number" | type="number" | ||||
label={t("acceptQty")} | label={t("acceptQty")} | ||||
sx={{ width: '150px' }} | sx={{ width: '150px' }} | ||||
value={qcAccept? accQty : 0 } | |||||
defaultValue={accQty} | defaultValue={accQty} | ||||
disabled={!qcAccept} | |||||
disabled={!qcAccept || itemDetail.status.toLowerCase() == "completed"} | |||||
{...register("acceptQty", { | {...register("acceptQty", { | ||||
required: "acceptQty required!", | required: "acceptQty required!", | ||||
})} | })} | ||||
@@ -434,13 +442,16 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
helperText={errors.acceptQty?.message} | helperText={errors.acceptQty?.message} | ||||
/> | /> | ||||
</Box> | </Box> | ||||
<FormControlLabel value="false" control={<Radio />} label="不接受及上報" /> | |||||
<FormControlLabel disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
value="false" control={<Radio />} | |||||
sx={{"& .Mui-checked": {color: "red"}}} | |||||
label="不接受及上報" /> | |||||
</RadioGroup> | </RadioGroup> | ||||
)} | )} | ||||
/> | /> | ||||
</FormControl> | </FormControl> | ||||
</Grid> | </Grid> | ||||
{/* <Grid item xs={12}> | |||||
{/* {qcAccept && <Grid item xs={12}> | |||||
<Typography variant="h6" display="block" marginBlockEnd={1}> | <Typography variant="h6" display="block" marginBlockEnd={1}> | ||||
{t("Escalation Result")} | {t("Escalation Result")} | ||||
</Typography> | </Typography> | ||||
@@ -451,7 +462,7 @@ const QcFormVer2: React.FC<Props> = ({ qc, itemDetail, disabled, qcItems, setQcI | |||||
isCollapsed={isCollapsed} | isCollapsed={isCollapsed} | ||||
setIsCollapsed={setIsCollapsed} | setIsCollapsed={setIsCollapsed} | ||||
/> | /> | ||||
</Grid> */} | |||||
</Grid>} */} | |||||
</Grid> | </Grid> | ||||
</Grid> | </Grid> | ||||
</> | </> | ||||
@@ -1,6 +1,6 @@ | |||||
"use client"; | "use client"; | ||||
import { StockInLine } from "@/app/api/po"; | import { StockInLine } from "@/app/api/po"; | ||||
import { ModalFormInput, PurchaseQcResult } from "@/app/api/po/actions"; | |||||
import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine } from "@/app/api/po/actions"; | |||||
import { QcItemWithChecks } from "@/app/api/qc"; | import { QcItemWithChecks } from "@/app/api/qc"; | ||||
import { | import { | ||||
Box, | Box, | ||||
@@ -22,6 +22,9 @@ import PutawayForm from "./PutawayForm"; | |||||
import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate"; | import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate"; | ||||
import { useGridApiRef } from "@mui/x-data-grid"; | import { useGridApiRef } from "@mui/x-data-grid"; | ||||
import {submitDialogWithWarning} from "../Swal/CustomAlerts"; | import {submitDialogWithWarning} from "../Swal/CustomAlerts"; | ||||
import { PurchaseQCInput, PutawayInput } from "@/app/api/dashboard/actions"; | |||||
import { arrayToDateString, arrayToInputDateString, dayjsToInputDateString } from "@/app/utils/formatUtil"; | |||||
import dayjs from "dayjs"; | |||||
const style = { | const style = { | ||||
position: "absolute", | position: "absolute", | ||||
@@ -73,15 +76,18 @@ const PoQcStockInModalVer2: React.FC<Props> = ({ | |||||
t, | t, | ||||
i18n: { language }, | i18n: { language }, | ||||
} = useTranslation("purchaseOrder"); | } = useTranslation("purchaseOrder"); | ||||
const [qcItems, setQcItems] = useState(dummyQCData) | const [qcItems, setQcItems] = useState(dummyQCData) | ||||
const formProps = useForm<ModalFormInput>({ | const formProps = useForm<ModalFormInput>({ | ||||
defaultValues: { | defaultValues: { | ||||
...itemDetail, | ...itemDetail, | ||||
dnDate: dayjsToInputDateString(dayjs()), | |||||
putawayLine: dummyPutawayLine, | putawayLine: dummyPutawayLine, | ||||
// receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT), | // receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT), | ||||
// warehouseId: itemDetail.defaultWarehouseId || 0 | // warehouseId: itemDetail.defaultWarehouseId || 0 | ||||
}, | }, | ||||
}); | }); | ||||
const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>( | const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>( | ||||
(...args) => { | (...args) => { | ||||
onClose?.(...args); | onClose?.(...args); | ||||
@@ -89,13 +95,34 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
}, | }, | ||||
[onClose], | [onClose], | ||||
); | ); | ||||
const isPutaway = () => { | |||||
if (itemDetail) { | |||||
const status = itemDetail.status; | |||||
return status == "received"; | |||||
} else return false; | |||||
}; | |||||
useEffect(() => { | |||||
formProps.reset({ | |||||
...itemDetail, | |||||
dnDate: dayjsToInputDateString(dayjs()), | |||||
putawayLine: dummyPutawayLine, | |||||
}) | |||||
setOpenPutaway(isPutaway); | |||||
}, [open]) | |||||
const [openPutaway, setOpenPutaway] = useState(false); | const [openPutaway, setOpenPutaway] = useState(false); | ||||
const onOpenPutaway = useCallback(() => { | const onOpenPutaway = useCallback(() => { | ||||
setOpenPutaway(true); | setOpenPutaway(true); | ||||
}, []); | }, []); | ||||
const onClosePutaway = useCallback(() => { | const onClosePutaway = useCallback(() => { | ||||
setOpenPutaway(false); | setOpenPutaway(false); | ||||
}, []); | }, []); | ||||
// Stock In submission handler | // Stock In submission handler | ||||
const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>( | const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>( | ||||
async (data, event) => { | async (data, event) => { | ||||
@@ -118,14 +145,16 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
}, | }, | ||||
[], | [], | ||||
); | ); | ||||
// QC submission handler | // QC submission handler | ||||
const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>( | const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>( | ||||
async (data, event) => { | async (data, event) => { | ||||
console.log("QC Submission:", event!.nativeEvent); | console.log("QC Submission:", event!.nativeEvent); | ||||
// TODO: Move validation into QC page | |||||
// Get QC data from the shared form context | // Get QC data from the shared form context | ||||
const qcAccept = data.qcAccept; | const qcAccept = data.qcAccept; | ||||
const acceptQty = data.acceptQty; | |||||
const acceptQty = data.acceptQty as number; | |||||
// Validate QC data | // Validate QC data | ||||
const validationErrors : string[] = []; | const validationErrors : string[] = []; | ||||
@@ -137,7 +166,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
// Check if failed items have failed quantity | // Check if failed items have failed quantity | ||||
const failedItemsWithoutQty = qcItems.filter(item => | const failedItemsWithoutQty = qcItems.filter(item => | ||||
item.isPassed === false && (!item.failedQty || item.failedQty <= 0) | |||||
item.isPassed === false && (!item.failQty || item.failQty <= 0) | |||||
); | ); | ||||
if (failedItemsWithoutQty.length > 0) { | if (failedItemsWithoutQty.length > 0) { | ||||
validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`); | validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`); | ||||
@@ -153,6 +182,14 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
validationErrors.push("Accept quantity must be greater than 0"); | validationErrors.push("Accept quantity must be greater than 0"); | ||||
} | } | ||||
// Check if dates are input | |||||
if (data.productionDate === undefined || data.productionDate == null) { | |||||
validationErrors.push("Production Date cannot be null!"); | |||||
} | |||||
if (data.expiryDate === undefined || data.expiryDate == null) { | |||||
validationErrors.push("Expiry Date cannot be null!"); | |||||
} | |||||
if (validationErrors.length > 0) { | if (validationErrors.length > 0) { | ||||
console.error("QC Validation failed:", validationErrors); | console.error("QC Validation failed:", validationErrors); | ||||
alert(`未完成品檢: ${validationErrors}`); | alert(`未完成品檢: ${validationErrors}`); | ||||
@@ -160,35 +197,75 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
} | } | ||||
const qcData = { | const qcData = { | ||||
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, | |||||
dnNo : data.dnNo? data.dnNo : "DN00000", | |||||
dnDate : data.dnDate? arrayToInputDateString(data.dnDate) : dayjsToInputDateString(dayjs()), | |||||
productionDate : arrayToInputDateString(data.productionDate), | |||||
expiryDate : arrayToInputDateString(data.expiryDate), | |||||
receiptDate : arrayToInputDateString(data.receiptDate), | |||||
qcAccept: qcAccept? qcAccept : false, | |||||
acceptQty: acceptQty? acceptQty : 0, | |||||
qcResult: qcItems.map(item => ({ | |||||
qcItemId: item.id, | |||||
// qcItem: item.qcItem, | |||||
// qcDescription: item.qcDescription, | |||||
isPassed: item.isPassed? item.isPassed : false, | |||||
failQty: (item.failQty && !item.isPassed) ? item.failQty : 0, | |||||
// failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, | |||||
remarks: item.remarks || '' | remarks: item.remarks || '' | ||||
})) | })) | ||||
}; | }; | ||||
// const qcData = data; | // const qcData = data; | ||||
console.log("QC Data for submission:", qcData); | 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: ""}); | |||||
if (!qcData.qcResult.every((qc) => qc.isPassed) && qcData.qcAccept) { | |||||
submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?", | |||||
confirmButtonText: t("confirm putaway"), html: ""}); | |||||
return; | return; | ||||
} | } | ||||
if (qcData.qcAccept) { | |||||
onOpenPutaway(); | |||||
} else { | |||||
onClose(); | |||||
} | |||||
await postStockInLineWithQc(qcData); | |||||
// return; | |||||
}, | }, | ||||
[onOpenPutaway, qcItems], | [onOpenPutaway, qcItems], | ||||
); | ); | ||||
const postStockInLineWithQc = useCallback(async (qcData: PurchaseQCInput) => { | |||||
const args = { | |||||
...qcData | |||||
// id: itemDetail.id, | |||||
// purchaseOrderId: itemDetail.purchaseOrderId, | |||||
// purchaseOrderLineId: itemDetail.purchaseOrderLineId, | |||||
// itemId: itemDetail.itemId, | |||||
// ...data, | |||||
// productionDate: productionDate, | |||||
// expiryDate: expiryDate, | |||||
// receiptDate: receiptDate, | |||||
} as ModalFormInput; | |||||
await postStockInLine(args); | |||||
if (qcData.qcAccept) { | |||||
// submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", | |||||
// confirmButtonText: t("confirm putaway"), html: ""}); | |||||
onOpenPutaway(); | |||||
} else { | |||||
closeHandler({}, "backdropClick"); | |||||
} | |||||
return ; | |||||
},[onOpenPutaway,closeHandler]); | |||||
const postStockInLine = useCallback(async (args: ModalFormInput) => { | |||||
const submitData = { | |||||
...itemDetail, ...args | |||||
} as StockInLineEntry & ModalFormInput; | |||||
console.log(submitData); | |||||
const res = await updateStockInLine(submitData); | |||||
console.log("result ", res); | |||||
return res; | |||||
},[]) | |||||
// Email supplier handler | // Email supplier handler | ||||
const onSubmitEmailSupplier = useCallback<SubmitHandler<ModalFormInput>>( | const onSubmitEmailSupplier = useCallback<SubmitHandler<ModalFormInput>>( | ||||
async (data, event) => { | async (data, event) => { | ||||
@@ -222,12 +299,22 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
// binLocation: data.binLocation, | // binLocation: data.binLocation, | ||||
// putawayQuantity: data.putawayQuantity, | // putawayQuantity: data.putawayQuantity, | ||||
// putawayNotes: data.putawayNotes, | // putawayNotes: data.putawayNotes, | ||||
data: data, | |||||
acceptQty: itemDetail.demandQty? itemDetail.demandQty : itemDetail.acceptedQty, | |||||
...data, | |||||
dnDate : data.dnDate? arrayToInputDateString(data.dnDate) : dayjsToInputDateString(dayjs()), | |||||
productionDate : arrayToInputDateString(data.productionDate), | |||||
expiryDate : arrayToInputDateString(data.expiryDate), | |||||
receiptDate : arrayToInputDateString(data.receiptDate), | |||||
// Add other putaway specific fields | // Add other putaway specific fields | ||||
}; | |||||
} as ModalFormInput; | |||||
console.log("Putaway Data:", putawayData); | console.log("Putaway Data:", putawayData); | ||||
// Handle putaway submission logic here | // Handle putaway submission logic here | ||||
const res = await postStockInLine(putawayData); | |||||
console.log("result ", res); | |||||
// Close modal after successful putaway | // Close modal after successful putaway | ||||
closeHandler({}, "backdropClick"); | closeHandler({}, "backdropClick"); | ||||
}, | }, | ||||
@@ -239,6 +326,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
// Handle print logic here | // Handle print logic here | ||||
window.print(); | window.print(); | ||||
}, []); | }, []); | ||||
const acceptQty = formProps.watch("acceptedQty") | const acceptQty = formProps.watch("acceptedQty") | ||||
const checkQcIsPassed = useCallback((qcItems: QcData[]) => { | const checkQcIsPassed = useCallback((qcItems: QcData[]) => { | ||||
@@ -272,7 +360,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
marginRight: 3, | marginRight: 3, | ||||
}} | }} | ||||
> | > | ||||
{openPutaway ? ( | |||||
{openPutaway ? ( | |||||
<Box | <Box | ||||
component="form" | component="form" | ||||
onSubmit={formProps.handleSubmit(onSubmitPutaway)} | onSubmit={formProps.handleSubmit(onSubmitPutaway)} | ||||
@@ -299,6 +387,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
variant="contained" | variant="contained" | ||||
color="primary" | color="primary" | ||||
sx={{ mt: 1 }} | sx={{ mt: 1 }} | ||||
onClick={formProps.handleSubmit(onSubmitPutaway)} | |||||
> | > | ||||
{t("confirm putaway")} | {t("confirm putaway")} | ||||
</Button> | </Button> | ||||
@@ -320,7 +409,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
<StockInFormVer2 itemDetail={itemDetail} disabled={false} /> | <StockInFormVer2 itemDetail={itemDetail} disabled={false} /> | ||||
</Grid> | </Grid> | ||||
</Grid> | </Grid> | ||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
{/* <Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
<Button | <Button | ||||
id="stockInSubmit" | id="stockInSubmit" | ||||
type="button" | type="button" | ||||
@@ -330,7 +419,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
> | > | ||||
{t("submitStockIn")} | {t("submitStockIn")} | ||||
</Button> | </Button> | ||||
</Stack> | |||||
</Stack> */} | |||||
<Grid | <Grid | ||||
container | container | ||||
justifyContent="flex-start" | justifyContent="flex-start" | ||||
@@ -345,7 +434,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | <Stack direction="row" justifyContent="flex-end" gap={1}> | ||||
<Button | |||||
{itemDetail.status.toLowerCase() == "rejected" && (<Button | |||||
id="emailSupplier" | id="emailSupplier" | ||||
type="button" | type="button" | ||||
variant="contained" | variant="contained" | ||||
@@ -354,8 +443,8 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
onClick={formProps.handleSubmit(onSubmitEmailSupplier)} | onClick={formProps.handleSubmit(onSubmitEmailSupplier)} | ||||
> | > | ||||
{t("email supplier")} | {t("email supplier")} | ||||
</Button> | |||||
<Button | |||||
</Button>)} | |||||
{itemDetail.status.toLowerCase() != "completed" && (<Button | |||||
id="qcSubmit" | id="qcSubmit" | ||||
type="button" | type="button" | ||||
variant="contained" | variant="contained" | ||||
@@ -363,8 +452,8 @@ const [qcItems, setQcItems] = useState(dummyQCData) | |||||
sx={{ mt: 1 }} | sx={{ mt: 1 }} | ||||
onClick={formProps.handleSubmit(onSubmitQc)} | onClick={formProps.handleSubmit(onSubmitQc)} | ||||
> | > | ||||
{t("confirm putaway")} | |||||
</Button> | |||||
{t("confirm qc result")} | |||||
</Button>)} | |||||
</Stack> | </Stack> | ||||
</> | </> | ||||
)} | )} | ||||
@@ -123,7 +123,7 @@ const StockInFormVer2: React.FC<Props> = ({ | |||||
{...register("dnNo", { | {...register("dnNo", { | ||||
// required: "productLotNo required!", | // required: "productLotNo required!", | ||||
})} | })} | ||||
disabled={true} | |||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
// error={Boolean(errors.productLotNo)} | // error={Boolean(errors.productLotNo)} | ||||
// helperText={errors.productLotNo?.message} | // helperText={errors.productLotNo?.message} | ||||
/> | /> | ||||
@@ -205,7 +205,7 @@ const StockInFormVer2: React.FC<Props> = ({ | |||||
{...register("productLotNo", { | {...register("productLotNo", { | ||||
// required: "productLotNo required!", | // required: "productLotNo required!", | ||||
})} | })} | ||||
disabled={disabled} | |||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
error={Boolean(errors.productLotNo)} | error={Boolean(errors.productLotNo)} | ||||
helperText={errors.productLotNo?.message} | helperText={errors.productLotNo?.message} | ||||
/> | /> | ||||
@@ -226,7 +226,7 @@ const StockInFormVer2: React.FC<Props> = ({ | |||||
sx={{ width: "100%" }} | sx={{ width: "100%" }} | ||||
label={t("productionDate")} | label={t("productionDate")} | ||||
value={productionDate ? dayjs(productionDate) : undefined} | value={productionDate ? dayjs(productionDate) : undefined} | ||||
disabled={disabled} | |||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
onChange={(date) => { | onChange={(date) => { | ||||
if (!date) return; | if (!date) return; | ||||
setValue( | setValue( | ||||
@@ -275,7 +275,7 @@ const StockInFormVer2: React.FC<Props> = ({ | |||||
sx={{ width: "100%" }} | sx={{ width: "100%" }} | ||||
label={t("expiryDate")} | label={t("expiryDate")} | ||||
value={expiryDate ? dayjs(expiryDate) : undefined} | value={expiryDate ? dayjs(expiryDate) : undefined} | ||||
disabled={disabled} | |||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
onChange={(date) => { | onChange={(date) => { | ||||
console.log(date); | console.log(date); | ||||
if (!date) return; | if (!date) return; | ||||
@@ -322,10 +322,11 @@ const StockInFormVer2: React.FC<Props> = ({ | |||||
<TextField | <TextField | ||||
label={t("acceptedQty")} | label={t("acceptedQty")} | ||||
fullWidth | fullWidth | ||||
disabled={itemDetail.status.toLowerCase() == "completed"} | |||||
{...register("acceptedQty", { | {...register("acceptedQty", { | ||||
required: "acceptedQty required!", | required: "acceptedQty required!", | ||||
})} | })} | ||||
disabled={true} | |||||
// disabled={true} | |||||
// disabled={disabled} | // disabled={disabled} | ||||
// error={Boolean(errors.acceptedQty)} | // error={Boolean(errors.acceptedQty)} | ||||
// helperText={errors.acceptedQty?.message} | // helperText={errors.acceptedQty?.message} | ||||
@@ -5,7 +5,7 @@ export interface QcData { | |||||
qcItem: string, | qcItem: string, | ||||
qcDescription: string, | qcDescription: string, | ||||
isPassed: boolean | undefined | isPassed: boolean | undefined | ||||
failedQty: number | undefined | |||||
failQty: number | undefined | |||||
remarks: string | undefined | remarks: string | undefined | ||||
} | } | ||||
@@ -15,7 +15,7 @@ export const dummyQCData: QcData[] = [ | |||||
qcItem: "包裝", | qcItem: "包裝", | ||||
qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | qcDescription: "有破爛、污糟、脹袋、積水、與實物不符等任何一種情況,則不合格", | ||||
isPassed: undefined, | isPassed: undefined, | ||||
failedQty: undefined, | |||||
failQty: undefined, | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
@@ -23,7 +23,7 @@ export const dummyQCData: QcData[] = [ | |||||
qcItem: "肉質", | qcItem: "肉質", | ||||
qcDescription: "肉質鬆散,則不合格", | qcDescription: "肉質鬆散,則不合格", | ||||
isPassed: undefined, | isPassed: undefined, | ||||
failedQty: undefined, | |||||
failQty: undefined, | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
@@ -31,7 +31,7 @@ export const dummyQCData: QcData[] = [ | |||||
qcItem: "顔色", | qcItem: "顔色", | ||||
qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,", | qcDescription: "不是食材應有的顔色、顔色不均匀、出現其他顔色、腌料/醬顔色不均匀,油脂部分變綠色、黃色,", | ||||
isPassed: undefined, | isPassed: undefined, | ||||
failedQty: undefined, | |||||
failQty: undefined, | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
@@ -39,7 +39,7 @@ export const dummyQCData: QcData[] = [ | |||||
qcItem: "狀態", | qcItem: "狀態", | ||||
qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | qcDescription: "有結晶、結霜、解凍跡象、發霉、散發異味等任何一種情況,則不合格", | ||||
isPassed: undefined, | isPassed: undefined, | ||||
failedQty: undefined, | |||||
failQty: undefined, | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
{ | { | ||||
@@ -47,7 +47,7 @@ export const dummyQCData: QcData[] = [ | |||||
qcItem: "異物", | qcItem: "異物", | ||||
qcDescription: "有不屬於本食材的雜質,則不合格", | qcDescription: "有不屬於本食材的雜質,則不合格", | ||||
isPassed: undefined, | isPassed: undefined, | ||||
failedQty: undefined, | |||||
failQty: undefined, | |||||
remarks: undefined, | remarks: undefined, | ||||
}, | }, | ||||
] | ] | ||||
@@ -126,6 +126,7 @@ export const submitDialogWithWarning = async ( | |||||
title: t("Do you want to submit?") as SweetAlertTitle, | title: t("Do you want to submit?") as SweetAlertTitle, | ||||
html: t("Warning!") as SweetAlertHtml, | html: t("Warning!") as SweetAlertHtml, | ||||
confirmButtonText: t("Submit") as SweetAlertConfirmButtonText, | confirmButtonText: t("Submit") as SweetAlertConfirmButtonText, | ||||
// cancelButtonText: t("Cancel") as SweetAlertConfirmButtonText, | |||||
}, | }, | ||||
) => { | ) => { | ||||
// console.log(props) | // console.log(props) | ||||
@@ -6,8 +6,8 @@ import { authOptions } from "@/config/authConfig"; | |||||
import I18nClientProvider from "./I18nClientProvider"; | import I18nClientProvider from "./I18nClientProvider"; | ||||
import universalLanguageDetect from "@unly/universal-language-detector"; | import universalLanguageDetect from "@unly/universal-language-detector"; | ||||
const FALLBACK_LANG = "en"; | |||||
const SUPPORTED_LANGUAGES = ["en", "zh"]; | |||||
const FALLBACK_LANG = "zh"; | |||||
const SUPPORTED_LANGUAGES = ["zh"]; | |||||
export const detectLanguage = async (): Promise<string> => { | export const detectLanguage = async (): Promise<string> => { | ||||
// Logic to get language preference from cookies/headers/session | // Logic to get language preference from cookies/headers/session | ||||
@@ -14,6 +14,10 @@ | |||||
"Humidity status": "濕度狀態", | "Humidity status": "濕度狀態", | ||||
"Warehouse status": "倉庫狀態", | "Warehouse status": "倉庫狀態", | ||||
"Progress chart": "進度圖表", | "Progress chart": "進度圖表", | ||||
"Purchase Order Code": "採購單號", | |||||
"Item Name": "貨品名稱", | |||||
"Escalation Level": "上報等級", | |||||
"Reason": "原因", | |||||
"Order completion": "訂單完成度", | "Order completion": "訂單完成度", | ||||
"Raw material": "原料", | "Raw material": "原料", | ||||
"Consumable": "消耗品", | "Consumable": "消耗品", | ||||
@@ -19,6 +19,7 @@ | |||||
"Start Fail": "開始失敗", | "Start Fail": "開始失敗", | ||||
"Start PO": "開始採購訂單", | "Start PO": "開始採購訂單", | ||||
"Do you want to complete?": "確定完成嗎?", | "Do you want to complete?": "確定完成嗎?", | ||||
"Cancel": "取消", | |||||
"Complete": "完成", | "Complete": "完成", | ||||
"Complete Success": "完成成功", | "Complete Success": "完成成功", | ||||
"Complete Fail": "完成失敗", | "Complete Fail": "完成失敗", | ||||
@@ -64,9 +65,9 @@ | |||||
"determine2": "上報2", | "determine2": "上報2", | ||||
"determine3": "上報3", | "determine3": "上報3", | ||||
"receiving": "收貨中", | "receiving": "收貨中", | ||||
"received": "已收貨", | |||||
"completed": "已完成", | |||||
"rejected": "已拒絕", | |||||
"received": "已檢收", | |||||
"completed": "已上架", | |||||
"rejected": "已拒絕及上報", | |||||
"status": "狀態", | "status": "狀態", | ||||
"acceptedQty must not greater than": "接受數量不得大於", | "acceptedQty must not greater than": "接受數量不得大於", | ||||
@@ -107,6 +108,9 @@ | |||||
"Accept submit": "接受來貨", | "Accept submit": "接受來貨", | ||||
"qc processing": "處理來貨及品檢", | "qc processing": "處理來貨及品檢", | ||||
"putaway processing": "處理來貨及上架", | |||||
"view stockin": "查看收貨及品檢", | |||||
"putaway processing": "處理來貨及上架", | |||||
"putawayBtn": "上架", | "putawayBtn": "上架", | ||||
"dnNo": "送貨單編號", | "dnNo": "送貨單編號", | ||||
"dnDate": "送貨單日期", | "dnDate": "送貨單日期", | ||||
@@ -120,9 +124,10 @@ | |||||
"update qc info": "更新品檢資料", | "update qc info": "更新品檢資料", | ||||
"email supplier": "電郵供應商", | "email supplier": "電郵供應商", | ||||
"confirm putaway": "確定及上架", | "confirm putaway": "確定及上架", | ||||
"confirm qc result": "確定品檢結果", | |||||
"warehouse": "倉庫", | "warehouse": "倉庫", | ||||
"qcItem": "檢查項目", | |||||
"qcItem": "品檢項目", | |||||
"passed": "接受", | "passed": "接受", | ||||
"failed": "不接受", | "failed": "不接受", | ||||
"failedQty": "不合格數", | "failedQty": "不合格數", | ||||