@@ -0,0 +1,17 @@ | |||
import { getServerI18n } from "@/i18n"; | |||
import { Stack, Typography, Link } from "@mui/material"; | |||
import NextLink from "next/link"; | |||
export default async function NotFound() { | |||
const { t } = await getServerI18n("qcItem", "common"); | |||
return ( | |||
<Stack spacing={2}> | |||
<Typography variant="h4">{t("Not Found")}</Typography> | |||
<Typography variant="body1">{t("The edit detail scheduling page was not found!")}</Typography> | |||
<Link href="/scheduling/detail" component={NextLink} variant="body2"> | |||
{t("Return to all detail scheduling")} | |||
</Link> | |||
</Stack> | |||
); | |||
} |
@@ -0,0 +1,47 @@ | |||
import { Metadata } from "next"; | |||
import { getServerI18n, I18nProvider } from "@/i18n"; | |||
import Typography from "@mui/material/Typography"; | |||
import { fetchQcItemDetails, preloadQcItem } from "@/app/api/settings/qcItem"; | |||
import QcItemSave from "@/components/QcItemSave"; | |||
import { isArray } from "lodash"; | |||
import { notFound } from "next/navigation"; | |||
import { ServerFetchError } from "@/app/utils/fetchUtil"; | |||
import DetailScheduleDetail from "@/components/DetailScheduleDetail"; | |||
export const metadata: Metadata = { | |||
title: "Qc Item", | |||
}; | |||
interface Props { | |||
searchParams: { [key: string]: string | string[] | undefined }; | |||
} | |||
const DetailScheduling: React.FC<Props> = async ({ searchParams }) => { | |||
const { t } = await getServerI18n("schedule") | |||
const id = searchParams["id"] | |||
if (!id || isArray(id)) { | |||
notFound() | |||
} | |||
// try { | |||
// await fetchQcItemDetails(id) | |||
// } catch (e) { | |||
// if (e instanceof ServerFetchError && (e.response?.status === 404 || e.response?.status === 400)) { | |||
// console.log(e) | |||
// notFound(); | |||
// } | |||
// } | |||
return <> | |||
<Typography variant="h4" marginInlineEnd={2}> | |||
{t("FG Production Schedule")} | |||
</Typography> | |||
<I18nProvider namespaces={["schedule"]}> | |||
<DetailScheduleDetail id={id}/> | |||
</I18nProvider> | |||
</>; | |||
}; | |||
export default DetailScheduling; |
@@ -9,7 +9,7 @@ export default async function NotFound() { | |||
<Stack spacing={2}> | |||
<Typography variant="h4">{t("Not Found")}</Typography> | |||
<Typography variant="body1">{t("The edit qc item page was not found!")}</Typography> | |||
<Link href="/qcItems" component={NextLink} variant="body2"> | |||
<Link href="/settings/qcItems" component={NextLink} variant="body2"> | |||
{t("Return to all qc items")} | |||
</Link> | |||
</Stack> | |||
@@ -17,6 +17,7 @@ const pathToLabelMap: { [path: string]: string } = { | |||
"/scheduling/rough": "Demand Forecast", | |||
"/scheduling/rough/edit": "FG & Material Demand Forecast Detail", | |||
"/scheduling/detail": "Detail Scheduling", | |||
"/scheduling/detail/edit": "FG Production Schedule", | |||
}; | |||
const Breadcrumb = () => { | |||
@@ -0,0 +1,40 @@ | |||
import Card from "@mui/material/Card"; | |||
import CardContent from "@mui/material/CardContent"; | |||
import Skeleton from "@mui/material/Skeleton"; | |||
import Stack from "@mui/material/Stack"; | |||
import React from "react"; | |||
// Can make this nicer | |||
export const DetailScheduleLoading: React.FC = () => { | |||
return ( | |||
<> | |||
<Card> | |||
<CardContent> | |||
<Stack spacing={2}> | |||
<Skeleton variant="rounded" height={60} /> | |||
<Skeleton variant="rounded" height={60} /> | |||
<Skeleton variant="rounded" height={60} /> | |||
<Skeleton | |||
variant="rounded" | |||
height={50} | |||
width={100} | |||
sx={{ alignSelf: "flex-end" }} | |||
/> | |||
</Stack> | |||
</CardContent> | |||
</Card> | |||
<Card> | |||
<CardContent> | |||
<Stack spacing={2}> | |||
<Skeleton variant="rounded" height={40} /> | |||
<Skeleton variant="rounded" height={40} /> | |||
<Skeleton variant="rounded" height={40} /> | |||
<Skeleton variant="rounded" height={40} /> | |||
</Stack> | |||
</CardContent> | |||
</Card> | |||
</> | |||
); | |||
}; | |||
export default DetailScheduleLoading; |
@@ -0,0 +1,202 @@ | |||
"use client"; | |||
import React, {useCallback, useEffect, useMemo, useState} from "react"; | |||
import SearchBox, { Criterion } from "../SearchBox"; | |||
import { ItemsResult} from "@/app/api/settings/item"; | |||
import SearchResults, { Column } from "../SearchResults"; | |||
import { EditNote } from "@mui/icons-material"; | |||
import { useRouter, useSearchParams } from "next/navigation"; | |||
import { GridDeleteIcon } from "@mui/x-data-grid"; | |||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||
import axios from "axios"; | |||
import {BASE_API_URL, NEXT_PUBLIC_API_URL} from "@/config/api"; | |||
import { useTranslation } from "react-i18next"; | |||
import axiosInstance from "@/app/(main)/axios/axiosInstance"; | |||
import Qs from 'qs'; | |||
import EditableSearchResults from "@/components/SearchResults/EditableSearchResults"; // Make sure to import Qs | |||
// may need move to "index" or "actions" | |||
type RecordStructure = { | |||
id: number, | |||
scheduledPeriod: string, | |||
scheduledAt: string, | |||
productCount: number, | |||
}; | |||
type Props = { | |||
records: RecordStructure[]; | |||
}; | |||
type SearchQuery = Partial<Omit<RecordStructure, "id">>; | |||
type SearchParamNames = keyof SearchQuery; | |||
const DSOverview: React.FC<Props> = ({ records }) => { | |||
const [filteredItems, setFilteredItems] = useState<RecordStructure[]>(records ?? []); | |||
const { t } = useTranslation("items"); | |||
const router = useRouter(); | |||
const [filterObj, setFilterObj] = useState({}); | |||
const [tempSelectedValue, setTempSelectedValue] = useState({}); | |||
const [pagingController, setPagingController] = useState({ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}) | |||
const [mode, redirPath] = useMemo(() => { | |||
// var typeId = TypeEnum.CONSUMABLE_ID | |||
let title = ""; | |||
const mode = "Search"; | |||
let redirPath = ""; | |||
title = "Product"; | |||
redirPath = "/scheduling/detail"; | |||
return [mode, redirPath]; | |||
}, []); | |||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | |||
() => | |||
[ | |||
{ label: t("Schedule Period"), paramName: "scheduledPeriod", type: "dateRange" }, | |||
{ label: t("Scheduled At"), paramName: "scheduledAt", type: "dateRange" }, | |||
{ label: t("Product Count"), paramName: "productCount", type: "text" }, | |||
] | |||
, | |||
[t, records] | |||
); | |||
// const onDetailClick = useCallback( | |||
// (item: ItemsResult) => { | |||
// router.push(`/settings/items/edit?id=${item.id}`); | |||
// }, | |||
// [router] | |||
// ); | |||
const onDeleteClick = useCallback( | |||
(item: ItemsResult) => {}, | |||
[router] | |||
); | |||
const onDetailClick = (record: any) => { | |||
console.log("[debug] record", record); | |||
router.push(`/scheduling/detail/edit?id=${record.id}`); | |||
} | |||
const columns = useMemo<Column<RecordStructure>[]>( | |||
() => [ | |||
{ | |||
name: "id", | |||
label: t("Details"), | |||
onClick: (record)=>onDetailClick(record), | |||
buttonIcon: <EditNote />, | |||
}, | |||
{ | |||
name: "scheduledPeriod", | |||
label: "Demand Forecast Period", | |||
}, | |||
{ | |||
name: "scheduledAt", | |||
label: t("Scheduled At"), | |||
}, | |||
{ | |||
name: "productCount", | |||
label: t("Product Count(s)"), | |||
}, | |||
// { | |||
// name: "action", | |||
// label: t(""), | |||
// buttonIcon: <GridDeleteIcon />, | |||
// onClick: onDeleteClick, | |||
// }, | |||
], | |||
[filteredItems] | |||
); | |||
useEffect(() => { | |||
refetchData(filterObj); | |||
}, [filterObj, pagingController.pageNum, pagingController.pageSize]); | |||
const refetchData = async (filterObj: SearchQuery | null) => { | |||
const authHeader = axiosInstance.defaults.headers['Authorization']; | |||
if (!authHeader) { | |||
return; // Exit the function if the token is not set | |||
} | |||
const params ={ | |||
pageNum: pagingController.pageNum, | |||
pageSize: pagingController.pageSize, | |||
...filterObj, | |||
...tempSelectedValue, | |||
} | |||
try { | |||
const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, { | |||
params, | |||
paramsSerializer: (params) => { | |||
return Qs.stringify(params, { arrayFormat: 'repeat' }); | |||
}, | |||
}); | |||
//setFilteredItems(response.data.records); | |||
setFilteredItems([ | |||
{ | |||
id: 1, | |||
scheduledPeriod: "2025-05-11 to 2025-05-17", | |||
scheduledAt: "2025-05-07", | |||
productCount: 13, | |||
}, | |||
{ | |||
id: 2, | |||
scheduledPeriod: "2025-05-18 to 2025-05-24", | |||
scheduledAt: "2025-05-14", | |||
productCount: 15, | |||
}, | |||
{ | |||
id: 3, | |||
scheduledPeriod: "2025-05-25 to 2025-05-31", | |||
scheduledAt: "2025-05-21", | |||
productCount: 13, | |||
}, | |||
]) | |||
setPagingController({ | |||
...pagingController, | |||
totalCount: response.data.total | |||
}) | |||
return response; // Return the data from the response | |||
} catch (error) { | |||
console.error('Error fetching items:', error); | |||
throw error; // Rethrow the error for further handling | |||
} | |||
}; | |||
const onReset = useCallback(() => { | |||
//setFilteredItems(items ?? []); | |||
setFilterObj({}); | |||
setTempSelectedValue({}); | |||
refetchData(null); | |||
}, [records]); | |||
return ( | |||
<> | |||
<SearchBox | |||
criteria={searchCriteria} | |||
onSearch={(query) => { | |||
setFilterObj({ | |||
...query | |||
}) | |||
}} | |||
onReset={onReset} | |||
/> | |||
<SearchResults<RecordStructure> | |||
items={filteredItems} | |||
columns={columns} | |||
setPagingController={setPagingController} | |||
pagingController={pagingController} | |||
isAutoPaging={false} | |||
// hasCollapse={false} | |||
/> | |||
</> | |||
); | |||
}; | |||
export default DSOverview; |
@@ -0,0 +1,16 @@ | |||
import React from "react"; | |||
import {DetailScheduleLoading} from "./DetailScheduleLoading"; | |||
import DSOverview from "./DetailScheduleSearchView"; | |||
interface SubComponents { | |||
Loading: typeof DetailScheduleLoading; | |||
} | |||
const DetailScheduleWrapper: React.FC & SubComponents = async () => { | |||
return <DSOverview records={[]} />; | |||
}; | |||
DetailScheduleWrapper.Loading = DetailScheduleLoading; | |||
export default DetailScheduleWrapper; |
@@ -0,0 +1 @@ | |||
export { default } from "./DetailScheduleWrapper"; |
@@ -0,0 +1,112 @@ | |||
"use client"; | |||
import { | |||
Box, | |||
Card, | |||
CardContent, | |||
Grid, | |||
Stack, | |||
TextField, | |||
Typography, | |||
} from "@mui/material"; | |||
import { Controller, useFormContext } from "react-hook-form"; | |||
import { useTranslation } from "react-i18next"; | |||
import InputDataGrid from "../InputDataGrid"; | |||
import { useCallback, useEffect, useMemo, useState } from "react"; | |||
import { GridColDef, GridRowModel } from "@mui/x-data-grid"; | |||
import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; | |||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||
import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
import { NumberInputProps } from "@/components/CreateItem/NumberInputProps"; | |||
import { integerFormatter } from "@/app/utils/formatUtil"; | |||
import { SaveDetailSchedule } from "./DetailScheudleDetailView"; | |||
// temp interface input | |||
type Props = { | |||
recordDetails: SaveDetailSchedule; | |||
isEditing: boolean; | |||
}; | |||
const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing }) => { | |||
const { | |||
t, | |||
i18n: { language }, | |||
} = useTranslation(); | |||
const { | |||
control, | |||
register, | |||
formState: { errors, defaultValues, touchedFields }, | |||
} = useFormContext<SaveDetailSchedule>(); | |||
const [details, setDetails] = useState<SaveDetailSchedule|null>(null); | |||
useEffect(() => { | |||
console.log("[debug] record details", recordDetails) | |||
setDetails(recordDetails); | |||
}, [recordDetails]) | |||
useEffect(() => { | |||
console.log("[debug] isEdit", isEditing) | |||
}, [isEditing]) | |||
return ( | |||
<Card sx={{ display: "block" }}> | |||
<CardContent component={Stack} spacing={4}> | |||
<Box> | |||
{/* <Typography variant="overline" display="block" marginBlockEnd={1}> | |||
{t("Schedule Detail")} | |||
</Typography> */} | |||
<Grid container spacing={2} columns={{ xs: 6, sm: 12 }}> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("Production Date")} | |||
fullWidth | |||
{...register("productionDate", { | |||
required: "name required!", | |||
})} | |||
// defaultValue={details?.scheduledPeriod} | |||
disabled={!isEditing} | |||
// error={Boolean(errors.name)} | |||
// helperText={errors.name?.message} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("Total Job Orders")} | |||
fullWidth | |||
{...register("totalJobOrders", { | |||
required: "code required!", | |||
})} | |||
// defaultValue={details?.productCount} | |||
disabled={!isEditing} | |||
// error={Boolean(errors.code)} | |||
// helperText={errors.code?.message} | |||
/> | |||
</Grid> | |||
<Grid item xs={6}> | |||
<Controller | |||
name="totalProductionQty" | |||
control={control} | |||
render={({ field }) => ( | |||
<TextField | |||
{...field} | |||
label={t("Total Production Qty")} | |||
fullWidth | |||
disabled={!isEditing} | |||
value={typeof (field.value) == "number" ? integerFormatter.format(field.value) : field.value} | |||
// defaultValue={typeof (details?.productionCount) == "number" ? integerFormatter.format(details?.productionCount) : details?.productionCount} | |||
// error={Boolean(errors.type)} | |||
// helperText={errors.type?.message} | |||
required | |||
/> | |||
)} | |||
/> | |||
</Grid> | |||
</Grid> | |||
</Box> | |||
</CardContent> | |||
</Card> | |||
); | |||
}; | |||
export default DetailInfoCard; |
@@ -0,0 +1,38 @@ | |||
import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
import { fetchItem } from "@/app/api/settings/item"; | |||
import GeneralLoading from "@/components/General/GeneralLoading"; | |||
import DetailScheduleDetailView from "@/components/DetailScheduleDetail/DetailScheudleDetailView"; | |||
interface SubComponents { | |||
Loading: typeof GeneralLoading; | |||
} | |||
type EditDetailScheduleDetailProps = { | |||
id?: string | number | |||
} | |||
type Props = EditDetailScheduleDetailProps | |||
const DetailScheduleDetailWrapper: React.FC<Props> & SubComponents = async ({ | |||
id | |||
}) => { | |||
const defaultValues = { | |||
id: 1, | |||
productionDate: "2025-05-07", | |||
totalJobOrders: 13, | |||
totalProductionQty: 21000, | |||
} | |||
return ( | |||
<DetailScheduleDetailView | |||
isEditMode={Boolean(id)} | |||
defaultValues={defaultValues} | |||
// qcChecks={qcChecks || []} | |||
/> | |||
); | |||
}; | |||
DetailScheduleDetailWrapper.Loading = GeneralLoading; | |||
export default DetailScheduleDetailWrapper; |
@@ -0,0 +1,216 @@ | |||
"use client"; | |||
import { useCallback, useEffect, useMemo, useState } from "react"; | |||
import { useRouter, useSearchParams } from "next/navigation"; | |||
import { useTranslation } from "react-i18next"; | |||
import { | |||
SaveDetailSchedule, | |||
saveItem, | |||
} from "@/app/api/settings/item/actions"; | |||
import { | |||
FormProvider, | |||
SubmitErrorHandler, | |||
SubmitHandler, | |||
useForm, | |||
} from "react-hook-form"; | |||
import { deleteDialog } from "../Swal/CustomAlerts"; | |||
import { Box, Button, Grid, Link, Stack, Tab, Tabs, TabsProps, Typography } from "@mui/material"; | |||
import { Add, Check, Close, EditNote } from "@mui/icons-material"; | |||
import { ItemQc, ItemsResult } from "@/app/api/settings/item"; | |||
import { useGridApiRef } from "@mui/x-data-grid"; | |||
import ProductDetails from "@/components/CreateItem/ProductDetails"; | |||
import DetailInfoCard from "@/components/DetailScheduleDetail/DetailInfoCard"; | |||
import ViewByFGDetails, { FGRecord } from "@/components/DetailScheduleDetail/ViewByFGDetails"; | |||
import ViewByBomDetails from "@/components/DetailScheduleDetail/ViewByBomDetails"; | |||
import EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults"; | |||
// temp interface input | |||
export interface SaveDetailSchedule { | |||
id: number, | |||
productionDate: string, | |||
totalJobOrders: number, | |||
totalProductionQty: number | |||
} | |||
type Props = { | |||
isEditMode: boolean; | |||
// type: TypeEnum; | |||
defaultValues: Partial<SaveDetailSchedule> | undefined; | |||
qcChecks: ItemQc[] | |||
}; | |||
const DetailScheduleDetailView: React.FC<Props> = ({ | |||
isEditMode, | |||
// type, | |||
defaultValues, | |||
// qcChecks | |||
}) => { | |||
// console.log(type) | |||
const apiRef = useGridApiRef(); | |||
const params = useSearchParams() | |||
console.log(params.get("id")) | |||
const [serverError, setServerError] = useState(""); | |||
const [tabIndex, setTabIndex] = useState(0); | |||
const { t } = useTranslation("schedule") | |||
const router = useRouter(); | |||
const [isEdit, setIsEdit] = useState(false); | |||
//const title = "Demand Forecast Detail" | |||
const [mode, redirPath] = useMemo(() => { | |||
// var typeId = TypeEnum.CONSUMABLE_ID | |||
let title = ""; | |||
let mode = ""; | |||
let redirPath = ""; | |||
// if (type === TypeEnum.MATERIAL) { | |||
// typeId = TypeEnum.MATERIAL_ID | |||
// title = "Material"; | |||
// redirPath = "/settings/material"; | |||
// } | |||
// if (type === TypeEnum.PRODUCT) { | |||
// typeId = TypeEnum.PRODUCT_ID | |||
title = "Product"; | |||
redirPath = "scheduling/detail/edit"; | |||
// } | |||
// if (type === TypeEnum.BYPRODUCT) { | |||
// typeId = TypeEnum.BYPRODUCT_ID | |||
// title = "By-Product"; | |||
// redirPath = "/settings/byProduct"; | |||
// } | |||
if (isEditMode) { | |||
mode = "Edit"; | |||
} else { | |||
mode = "Create"; | |||
} | |||
return [mode, redirPath]; | |||
}, [isEditMode]); | |||
// console.log(typeId) | |||
const formProps = useForm<SaveDetailSchedule>({ | |||
defaultValues: defaultValues ? defaultValues : { | |||
id: 1, | |||
productionDate: "2025-05-07", | |||
totalJobOrders: 13, | |||
totalProductionQty: 21000, | |||
}, | |||
}); | |||
const errors = formProps.formState.errors; | |||
const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>( | |||
(_e, newValue) => { | |||
setTabIndex(newValue); | |||
}, | |||
[], | |||
); | |||
const [pagingController, setPagingController] = useState({ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}) | |||
const handleCancel = () => { | |||
router.replace(`/scheduling/Detail`); | |||
}; | |||
const onSubmit = useCallback<SubmitHandler<SaveDetailSchedule>>( | |||
async (data, event) => { | |||
const hasErrors = false; | |||
console.log(errors) | |||
// console.log(apiRef.current.getCellValue(2, "lowerLimit")) | |||
// apiRef.current. | |||
try { | |||
if (hasErrors) { | |||
setServerError(t("An error has occurred. Please try again later.")); | |||
return false; | |||
} | |||
} catch (e) { | |||
// backend error | |||
setServerError(t("An error has occurred. Please try again later.")); | |||
console.log(e); | |||
} | |||
}, | |||
[apiRef, router, t] | |||
); | |||
// multiple tabs | |||
const onSubmitError = useCallback<SubmitErrorHandler<SaveDetailSchedule>>( | |||
(errors) => { }, | |||
[] | |||
); | |||
const onClickEdit = () => { | |||
setIsEdit(!isEdit) | |||
} | |||
return ( | |||
<> | |||
<FormProvider {...formProps}> | |||
<Stack | |||
spacing={2} | |||
component="form" | |||
onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} | |||
> | |||
{/*<Grid>*/} | |||
{/* <Typography mb={2} variant="h4">*/} | |||
{/* {t(`${mode} ${title}`)}*/} | |||
{/* </Typography>*/} | |||
{/*</Grid>*/} | |||
<DetailInfoCard | |||
recordDetails={formProps.formState.defaultValues} | |||
isEditing={isEdit} | |||
/> | |||
<Stack | |||
direction="row" | |||
justifyContent="space-between" | |||
flexWrap="wrap" | |||
rowGap={2} | |||
> | |||
<Button | |||
variant="contained" | |||
onClick={onClickEdit} | |||
// startIcon={<Add />} | |||
//LinkComponent={Link} | |||
//href="qcCategory/create" | |||
> | |||
{isEdit ? t("Save") : t("Edit")} | |||
</Button> | |||
</Stack> | |||
{/* <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> | |||
<Tab label={t("View By FG") + (tabIndex === 0 ? " (Selected)" : "")} iconPosition="end" /> | |||
<Tab label={t("View By Material") + (tabIndex === 1 ? " (Selected)" : "")} iconPosition="end" /> | |||
</Tabs> */} | |||
{serverError && ( | |||
<Typography variant="body2" color="error" alignSelf="flex-end"> | |||
{serverError} | |||
</Typography> | |||
)} | |||
{/* {tabIndex === 0 && <ViewByFGDetails isEdit={isEdit} apiRef={apiRef} />} */} | |||
<ViewByFGDetails isEdit={isEdit} apiRef={apiRef} /> | |||
{/* {tabIndex === 1 && <ViewByBomDetails isEdit={isEdit} apiRef={apiRef} isHideButton={true} />} */} | |||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||
<Button | |||
name="submit" | |||
variant="contained" | |||
startIcon={<Check />} | |||
type="submit" | |||
// disabled={submitDisabled} | |||
> | |||
{isEditMode ? t("Save") : t("Confirm")} | |||
</Button> | |||
<Button | |||
variant="outlined" | |||
startIcon={<Close />} | |||
onClick={handleCancel} | |||
> | |||
{t("Cancel")} | |||
</Button> | |||
</Stack> | |||
</Stack> | |||
</FormProvider> | |||
</> | |||
); | |||
}; | |||
export default DetailScheduleDetailView; |
@@ -0,0 +1,556 @@ | |||
"use client"; | |||
import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
import { | |||
GridColDef, | |||
GridRowModel, | |||
GridRenderEditCellParams, | |||
GridEditInputCell, | |||
GridRowSelectionModel, | |||
useGridApiRef, | |||
} from "@mui/x-data-grid"; | |||
import {MutableRefObject, useCallback, useEffect, useMemo, useState} from "react"; | |||
import { useFormContext } from "react-hook-form"; | |||
import { useTranslation } from "react-i18next"; | |||
import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid"; | |||
import {Box, Grid, Tooltip, Typography} from "@mui/material"; | |||
import { ItemQc } from "@/app/api/settings/item"; | |||
import { QcChecksInputs } from "@/app/api/settings/qcCheck/actions"; | |||
import { GridApiCommunity } from "@mui/x-data-grid/internals"; | |||
import { RiceBowl } from "@mui/icons-material"; | |||
import EditableSearchResults, {Column} from "@/components/SearchResults/EditableSearchResults"; | |||
import { decimalFormatter } from "@/app/utils/formatUtil"; | |||
import { GridRenderCellParams } from "@mui/x-data-grid"; | |||
type Props = { | |||
apiRef: MutableRefObject<GridApiCommunity> | |||
}; | |||
type EntryError = | |||
| { | |||
[field in keyof QcChecksInputs]?: string; | |||
} | |||
| undefined; | |||
export type FGRecord = { | |||
id: string | number | |||
code: string; | |||
name: string; | |||
inStockQty: number; | |||
purchaseQty: number; | |||
} | |||
export type FGOverallRecord = { | |||
id: string | number | |||
code: string; | |||
name: string; | |||
type: string; | |||
inStockQty: number; | |||
purchaseQty: number; | |||
purchaseQty1: number; | |||
purchaseQty2: number; | |||
purchaseQty3: number; | |||
purchaseQty4: number; | |||
purchaseQty5: number; | |||
purchaseQty6: number; | |||
purchaseQty7: number; | |||
overallPurchaseQty: number; | |||
} | |||
const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
const { | |||
t, | |||
i18n: { language }, | |||
} = useTranslation("schedule"); | |||
const { | |||
formState: { errors, defaultValues, touchedFields }, | |||
} = useFormContext<CreateItemInputs>(); | |||
// const apiRef = useGridApiRef(); | |||
const dayPeriod = [ | |||
'2025-05-11', | |||
'2025-05-12', | |||
'2025-05-13', | |||
'2025-05-14', | |||
'2025-05-15', | |||
'2025-05-16', | |||
'2025-05-17', | |||
]; | |||
const fakeRecords = useMemo<FGRecord[][]>( | |||
() => [ | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , purchaseQty: 972.12 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , purchaseQty: 3175.2 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , purchaseQty: 90 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , purchaseQty: 60.4 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , purchaseQty: 66.45 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , purchaseQty: 78.55 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
], | |||
[] | |||
); | |||
const fakeOverallRecords = useMemo<FGOverallRecord[]>( | |||
() => [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44 , | |||
purchaseQty1: 972.12, purchaseQty2: 972.12, purchaseQty3: 972.12, | |||
purchaseQty4: 972.12, purchaseQty5: 972.12, purchaseQty6: 972.12, | |||
purchaseQty7: 972.12, overallPurchaseQty: 6804.84 | |||
}, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52 , | |||
purchaseQty1: 3175.2, purchaseQty2: 3175.2, purchaseQty3: 3175.2, | |||
purchaseQty4: 3175.2, purchaseQty5: 3175.2, purchaseQty6: 3175.2, | |||
purchaseQty7: 3175.2, overallPurchaseQty: 22226.4 | |||
}, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00 , | |||
purchaseQty1: 90, purchaseQty2: 90, purchaseQty3: 90, | |||
purchaseQty4: 90, purchaseQty5: 90, purchaseQty6: 90, | |||
purchaseQty7: 90, overallPurchaseQty: 630 | |||
}, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04 , | |||
purchaseQty1: 60.4, purchaseQty2: 60.4, purchaseQty3: 60.4, | |||
purchaseQty4: 60.4, purchaseQty5: 60.4, purchaseQty6: 60.4, | |||
purchaseQty7: 60.4, overallPurchaseQty: 422.8 | |||
}, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04 , | |||
purchaseQty1: 66.45, purchaseQty2: 66.45, purchaseQty3: 66.45, | |||
purchaseQty4: 66.45, purchaseQty5: 66.45, purchaseQty6: 66.45, | |||
purchaseQty7: 66.45, overallPurchaseQty: 465.15 | |||
}, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04 , | |||
purchaseQty1: 78.55, purchaseQty2: 78.55, purchaseQty3: 78.55, | |||
purchaseQty4: 78.55, purchaseQty5: 78.55, purchaseQty6: 78.55, | |||
purchaseQty7: 78.55, overallPurchaseQty: 549.85 | |||
}, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98 , purchaseQty: 2419.8 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00 , purchaseQty: 0 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42 , purchaseQty: 774.2 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00 , purchaseQty: 0 }, | |||
{ id: 11, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00 , purchaseQty: 6000 }, | |||
{ id: 12, code: "MH0040",type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 972.12 }, | |||
{ id: 13, code: "FA0161",type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 28.15 }, | |||
{ id: 14, code: "MG1288", type: "Material",name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 15, code: "MG0066", type: "Material",name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
{ id: 16, code: "MH0040", type: "Material",name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
], | |||
[] | |||
); | |||
const [pagingController, setPagingController] = useState([ | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
]) | |||
const updatePagingController = (updatedObj) => { | |||
setPagingController((prevState) => { | |||
return prevState.map((item, index) => { | |||
if (index === updatedObj?.index){ | |||
return { | |||
...item, | |||
pageNum: item.pageNum, | |||
pageSize: item.pageSize, | |||
totalCount: item.totalCount, | |||
}; | |||
} | |||
else | |||
return item | |||
}); | |||
}); | |||
}; | |||
const overallColumns = useMemo<Column<any>[]>( | |||
() => [ | |||
{ | |||
field: "code", | |||
label: "code", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "name", | |||
label: t("name"), | |||
type: 'read-only', | |||
}, | |||
{ | |||
field: "type", | |||
label: "type", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "inStockQty", | |||
label: t("Available Qty"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "overallPurchaseQty", | |||
label: t("Total Demand Qty"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.overallPurchaseQty) == "number") { | |||
return decimalFormatter.format(row.overallPurchaseQty) | |||
} | |||
return row.overallPurchaseQty | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty1", | |||
label: t("Demand Qty (Day1)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty1) == "number") { | |||
return decimalFormatter.format(row.purchaseQty1) | |||
} | |||
return row.purchaseQty1 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty2", | |||
label: t("Demand Qty (Day2)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty2) == "number") { | |||
return decimalFormatter.format(row.purchaseQty2) | |||
} | |||
return row.purchaseQty2 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty3", | |||
label: t("Demand Qty (Day3)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty3) == "number") { | |||
return decimalFormatter.format(row.purchaseQty3) | |||
} | |||
return row.purchaseQty3 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty4", | |||
label: t("Demand Qty (Day4)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty4) == "number") { | |||
return decimalFormatter.format(row.purchaseQty4) | |||
} | |||
return row.purchaseQty4 | |||
} | |||
},{ | |||
field: "purchaseQty5", | |||
label: t("Demand Qty (Day5)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty5) == "number") { | |||
return decimalFormatter.format(row.purchaseQty5) | |||
} | |||
return row.purchaseQty5 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty6", | |||
label: t("Demand Qty (Day6)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty6) == "number") { | |||
return decimalFormatter.format(row.purchaseQty6) | |||
} | |||
return row.purchaseQty6 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty7", | |||
label: t("Demand Qty (Day7)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty7) == "number") { | |||
return decimalFormatter.format(row.purchaseQty7) | |||
} | |||
return row.purchaseQty7 | |||
} | |||
}, | |||
], | |||
[] | |||
); | |||
const columns = useMemo<Column<any>[]>( | |||
() => [ | |||
{ | |||
field: "code", | |||
label: "code", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "name", | |||
label: "name", | |||
type: 'read-only', | |||
}, | |||
{ | |||
field: "type", | |||
label: "type", | |||
type: 'read-only', | |||
}, | |||
{ | |||
field: "inStockQty", | |||
label: "Available Qty", | |||
type: 'read-only', | |||
// editable: true, | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty", | |||
label: "Demand Qty", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.purchaseQty) == "number") { | |||
return decimalFormatter.format(row.purchaseQty) | |||
} | |||
return row.purchaseQty | |||
} | |||
}, | |||
], | |||
[] | |||
); | |||
return ( | |||
<Grid container spacing={2}> | |||
<Grid item xs={12} key={"all"}> | |||
<Typography variant="overline" display="block" marginBlockEnd={1}> | |||
{t("Material Demand List (7 Days)")} | |||
</Typography> | |||
<EditableSearchResults<FGRecord> | |||
index={7} | |||
items={fakeOverallRecords} | |||
isMockUp={true} | |||
columns={overallColumns} | |||
setPagingController={updatePagingController} | |||
pagingController={pagingController[7]} | |||
isAutoPaging={true} | |||
isEditable={false} | |||
isEdit={false} | |||
/> | |||
</Grid> | |||
{dayPeriod.map((date, index) => ( | |||
<Grid item xs={12} key={index}> | |||
<Typography variant="overline" display="block" marginBlockEnd={1}> | |||
{`${t("Material Demand Date")}: ${date}`} | |||
</Typography> | |||
<EditableSearchResults<FGRecord> | |||
index={index} | |||
items={fakeRecords[index]} // Use the corresponding records for the day | |||
columns={columns} | |||
setPagingController={updatePagingController} | |||
pagingController={pagingController[index]} | |||
isAutoPaging={true} | |||
isEditable={false} | |||
isEdit={isEdit} | |||
/> | |||
</Grid> | |||
))} | |||
</Grid> | |||
); | |||
}; | |||
export default ViewByBomDetails; |
@@ -0,0 +1,709 @@ | |||
"use client"; | |||
import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
import { | |||
GridColDef, | |||
GridRowModel, | |||
GridRenderEditCellParams, | |||
GridEditInputCell, | |||
GridRowSelectionModel, | |||
useGridApiRef, | |||
} from "@mui/x-data-grid"; | |||
import { MutableRefObject, useCallback, useMemo, useState } from "react"; | |||
import { useFormContext } from "react-hook-form"; | |||
import { useTranslation } from "react-i18next"; | |||
import InputDataGrid, { TableRow } from "../InputDataGrid/InputDataGrid"; | |||
import { Box, Grid, Tooltip, Typography } from "@mui/material"; | |||
import { ItemQc } from "@/app/api/settings/item"; | |||
import { QcChecksInputs } from "@/app/api/settings/qcCheck/actions"; | |||
import { GridApiCommunity } from "@mui/x-data-grid/internals"; | |||
import { RiceBowl } from "@mui/icons-material"; | |||
import EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults"; | |||
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | |||
type Props = { | |||
apiRef: MutableRefObject<GridApiCommunity> | |||
isEdit: Boolean | |||
}; | |||
type EntryError = | |||
| { | |||
[field in keyof QcChecksInputs]?: string; | |||
} | |||
| undefined; | |||
export type FGRecord = { | |||
id: string | number | |||
code: string; | |||
name: string; | |||
inStockQty: number; | |||
productionQty?: number; | |||
purchaseQty?: number | |||
} | |||
const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
const { | |||
t, | |||
i18n: { language }, | |||
} = useTranslation(); | |||
const { | |||
formState: { errors, defaultValues, touchedFields }, | |||
} = useFormContext<CreateItemInputs>(); | |||
// const apiRef = useGridApiRef(); | |||
const dayPeriod = [ | |||
'2025-05-07', | |||
// '2025-05-12', | |||
// '2025-05-13', | |||
// '2025-05-14', | |||
// '2025-05-15', | |||
// '2025-05-16', | |||
// '2025-05-17', | |||
]; | |||
const fakeRecordLine = useMemo<FGRecord[][]>( | |||
() => [ | |||
[ | |||
{ id: 1, code: "mt1", name: "material 1", inStockQty: 10, purchaseQty: 1 }, | |||
{ id: 2, code: "mt2", name: "material 2", inStockQty: 20, purchaseQty: 199 }, | |||
], | |||
[ | |||
{ id: 3, code: "mt3", name: "material 3", inStockQty: 30, purchaseQty: 3 }, | |||
{ id: 4, code: "mt4", name: "material 4", inStockQty: 40, purchaseQty: 499 }, | |||
], | |||
[ | |||
{ id: 5, code: "mt5", name: "material 5", inStockQty: 50, purchaseQty: 5 }, | |||
{ id: 6, code: "mt6", name: "material 6", inStockQty: 60, purchaseQty: 699 }, | |||
], | |||
[ | |||
{ id: 7, code: "mt7", name: "material 7", inStockQty: 70, purchaseQty: 7 }, | |||
{ id: 8, code: "mt8", name: "material 8", inStockQty: 80, purchaseQty: 899 }, | |||
], | |||
[ | |||
{ id: 9, code: "mt9", name: "material 9", inStockQty: 90, purchaseQty: 9 }, | |||
{ id: 10, code: "mt10", name: "material 10", inStockQty: 100, purchaseQty: 999 }, | |||
], | |||
[ | |||
{ id: 11, code: "mt11", name: "material 11", inStockQty: 110, purchaseQty: 11 }, | |||
{ id: 12, code: "mt12", name: "material 12", inStockQty: 120, purchaseQty: 1299 }, | |||
], | |||
[ | |||
{ id: 13, code: "mt13", name: "material 13", inStockQty: 130, purchaseQty: 13 }, | |||
{ id: 14, code: "mt14", name: "material 14", inStockQty: 140, purchaseQty: 1499 }, | |||
], | |||
], | |||
[] | |||
); | |||
const fakeRecords = useMemo<FGRecord[][]>( | |||
() => [ | |||
[ | |||
{ | |||
id: 1, jobNo: "JO20250507001", priority: 85, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 100, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 80, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 2, jobNo: "JO20250507002", priority: 80, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 1000, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 1000, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
{ | |||
id: 3, jobNo: "JO20250507003", priority: 35, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 4, jobNo: "JO20250507004", priority: 20, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.00 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
[ | |||
{ | |||
id: 1, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 18.00 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 12.08 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 12.08 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 483.96 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 72.00 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 154.84 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 120.00 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 200.0 }, | |||
] | |||
}, | |||
{ | |||
id: 2, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 } | |||
] | |||
}, | |||
{ | |||
id: 3, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 }, | |||
] | |||
}, | |||
{ | |||
id: 4, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
], | |||
], | |||
[] | |||
); | |||
const [pagingController, setPagingController] = useState([ | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
{ | |||
pageNum: 1, | |||
pageSize: 10, | |||
totalCount: 0, | |||
}, | |||
]) | |||
const updatePagingController = (updatedObj) => { | |||
setPagingController((prevState) => { | |||
return prevState.map((item, index) => { | |||
if (index === updatedObj?.index) { | |||
return { | |||
...item, | |||
pageNum: item.pageNum, | |||
pageSize: item.pageSize, | |||
totalCount: item.totalCount, | |||
}; | |||
} | |||
else | |||
return item | |||
}); | |||
}); | |||
}; | |||
const columns = useMemo<Column<any>[]>( | |||
() => [ | |||
{ | |||
field: "jobNo", | |||
label: "Job No.", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "code", | |||
label: "code", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "name", | |||
label: "name", | |||
type: 'read-only', | |||
}, | |||
{ | |||
field: "type", | |||
label: "type", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
// { | |||
// field: "inStockQty", | |||
// label: "Available Qty", | |||
// type: 'read-only', | |||
// style: { | |||
// textAlign: "right", | |||
// }, | |||
// // editable: true, | |||
// renderCell: (row: FGRecord) => { | |||
// if (typeof (row.inStockQty) == "number") { | |||
// return decimalFormatter.format(row.inStockQty) | |||
// } | |||
// return row.inStockQty | |||
// } | |||
// }, | |||
{ | |||
field: "productionQty", | |||
label: "Demand Qty", | |||
type: 'input', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof (row.productionQty) == "number") { | |||
return decimalFormatter.format(row.productionQty ?? 0) | |||
} | |||
return row.productionQty | |||
} | |||
}, | |||
{ | |||
field: "priority", | |||
label: "Production Priority", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
// editable: true, | |||
}, | |||
], | |||
[] | |||
); | |||
const overallColumns = useMemo<Column<any>[]>( | |||
() => [ | |||
{ | |||
field: "code", | |||
label: "code", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "name", | |||
label: "name", | |||
type: 'read-only', | |||
}, | |||
{ | |||
field: "type", | |||
label: "type", | |||
type: 'read-only', | |||
// editable: true, | |||
}, | |||
{ | |||
field: "lastMonthAvgStock", | |||
label: "Last Month Average Stock", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof (row.lastMonthAvgStock) == "number") { | |||
return decimalFormatter.format(row.lastMonthAvgStock) | |||
} | |||
return row.lastMonthAvgStock | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "safetyStock", | |||
label: "Safety Stock", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof (row.safetyStock) == "number") { | |||
return decimalFormatter.format(row.safetyStock) | |||
} | |||
return row.safetyStock | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "inStockQty", | |||
label: "Available Qty", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof (row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "productionQty", | |||
label: "Demand Qty (7 Days)", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof (row.productionQty) == "number") { | |||
return decimalFormatter.format(row.productionQty) | |||
} | |||
return row.productionQty | |||
} | |||
}, | |||
], | |||
[] | |||
); | |||
const fakeOverallRecords = useMemo<FGRecord[]>( | |||
() => [ | |||
{ | |||
id: 1, jobNo: "JO20250507001", priority: 20, code: "PP1193", type: "FG", name: "蔥油(1磅) ", lastMonthAvgStock: 1320, safetyStock: 1322, inStockQty: 1322, productionQty: 4627, | |||
lines: [ | |||
{ id: 2, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 20 * 7 }, | |||
{ id: 3, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 10 * 7 } | |||
] | |||
}, | |||
{ | |||
id: 2, jobNo: "JO20250507002", priority: 25, code: " PP1096", type: "FG", name: "白麵撈", lastMonthAvgStock: 1040, safetyStock: 1040, inStockQty: 1040, productionQty: 3640, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 190.00 * 7 }, | |||
{ id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 0, purchaseQty: 250.00 * 7 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "蔥油", inStockQty: 1322, purchaseQty: 0 }, | |||
] | |||
}, | |||
{ | |||
id: 3, jobNo: "JO20250507003", priority: 70, code: "PP1080", type: "FG", name: "咖哩汁", lastMonthAvgStock: 2400, safetyStock: 2400, inStockQty: 2400, productionQty: 8400.0 * 7, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 54.44, purchaseQty: 544.4 * 7 }, | |||
{ id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 3175.2 * 7 }, | |||
{ id: 3, code: "MG1700", type: "Material", name: "STERILTOM 意大利茄粒", inStockQty: 9.00, purchaseQty: 90 * 7 }, | |||
{ id: 4, code: "FA0533", type: "Material", name: "乾蔥茸", inStockQty: 6.04, purchaseQty: 60.4 * 7 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 6.04, purchaseQty: 60.4 * 7 }, | |||
{ id: 6, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 6.04, purchaseQty: 60.4 * 7 }, | |||
{ id: 7, code: "FA0056", type: "Material", name: "洋蔥肉", inStockQty: 241.98, purchaseQty: 2419.8 * 7 }, | |||
{ id: 8, code: "PP1188", type: "Material", name: "咖喱膽", inStockQty: 36.00, purchaseQty: 360 * 7 }, | |||
{ id: 9, code: "PP8001", type: "Material", name: "咖哩汁箱料粉", inStockQty: 77.42, purchaseQty: 774.2 * 7 }, | |||
{ id: 10, code: "PP1096", type: "Material", name: "白麵撈", inStockQty: 60.00, purchaseQty: 600 * 7 }, | |||
{ id: 10, code: "NA0476", type: "Material", name: "2磅份量三邊覆合袋 (0.1x225x260mm)個計", inStockQty: 600.00, purchaseQty: 6000 * 7 }, | |||
] | |||
}, | |||
{ | |||
id: 4, jobNo: "JO20250507004", priority: 80, code: " PP1188", type: "FG", name: "咖喱膽", lastMonthAvgStock: 1017, safetyStock: 1017, inStockQty: 1016.2, productionQty: 3556.7, | |||
lines: [ | |||
{ id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 * 7 }, | |||
{ id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 * 7 }, | |||
{ id: 3, code: "FA0608", type: "Material", name: "粗蒜茸", inStockQty: 0, purchaseQty: 18.15 * 7 }, | |||
{ id: 4, code: "MG1288", type: "Material", name: "炸紅蔥頭", inStockQty: 0, purchaseQty: 6.05 * 7 }, | |||
{ id: 5, code: "FA0210", type: "Material", name: "薑茸", inStockQty: 0, purchaseQty: 6.05 * 7 }, | |||
{ id: 6, code: "MG0066", type: "Material", name: "咖哩料(5斤x16包+2斤/包)", inStockQty: 0, purchaseQty: 241.98 * 7 }, | |||
] | |||
}, | |||
], | |||
[] | |||
); | |||
return ( | |||
<Grid container spacing={2}> | |||
{/* <Grid item xs={12} key={"all"}> | |||
<Typography variant="overline" display="block" marginBlockEnd={1}> | |||
{t("FG Demand List (7 Days)")} | |||
</Typography> | |||
<EditableSearchResults<FGRecord> | |||
index={7} | |||
items={fakeOverallRecords} | |||
columns={overallColumns} | |||
setPagingController={updatePagingController} | |||
pagingController={pagingController[7]} | |||
isAutoPaging={false} | |||
isEditable={false} | |||
isEdit={isEdit} | |||
hasCollapse={true} | |||
/> | |||
</Grid> */} | |||
{dayPeriod.map((date, index) => ( | |||
<Grid item xs={12} key={index}> | |||
{/* <Typography variant="overline" display="block" marginBlockEnd={1}> | |||
{`${t("FG Demand Date")}: ${date}`} | |||
</Typography> */} | |||
<EditableSearchResults<FGRecord> | |||
items={fakeRecords[index]} // Use the corresponding records for the day | |||
columns={columns} | |||
setPagingController={updatePagingController} | |||
pagingController={pagingController[index]} | |||
isAutoPaging={false} | |||
isEditable={true} | |||
isEdit={isEdit} | |||
hasCollapse={true} | |||
/> | |||
</Grid> | |||
))} | |||
</Grid> | |||
); | |||
}; | |||
export default ViewByFGDetails; |
@@ -0,0 +1 @@ | |||
export { default } from "./DetailScheduleDetailWrapper"; |
@@ -82,7 +82,7 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => { | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("Total Estimated Demand Count")} | |||
label={t("Total Estimated Demand Qty")} | |||
fullWidth | |||
{...register("productionCount", { | |||
required: "type required!", | |||
@@ -338,6 +338,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "inStockQty", | |||
label: t("Available Qty"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
@@ -350,6 +353,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "overallPurchaseQty", | |||
label: t("Total Demand Qty"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.overallPurchaseQty) == "number") { | |||
return decimalFormatter.format(row.overallPurchaseQty) | |||
@@ -361,6 +367,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty1", | |||
label: t("Demand Qty (Day1)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty1) == "number") { | |||
return decimalFormatter.format(row.purchaseQty1) | |||
@@ -372,6 +381,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty2", | |||
label: t("Demand Qty (Day2)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty2) == "number") { | |||
return decimalFormatter.format(row.purchaseQty2) | |||
@@ -383,6 +395,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty3", | |||
label: t("Demand Qty (Day3)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty3) == "number") { | |||
return decimalFormatter.format(row.purchaseQty3) | |||
@@ -394,6 +409,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty4", | |||
label: t("Demand Qty (Day4)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty4) == "number") { | |||
return decimalFormatter.format(row.purchaseQty4) | |||
@@ -404,6 +422,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty5", | |||
label: t("Demand Qty (Day5)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty5) == "number") { | |||
return decimalFormatter.format(row.purchaseQty5) | |||
@@ -415,6 +436,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty6", | |||
label: t("Demand Qty (Day6)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty6) == "number") { | |||
return decimalFormatter.format(row.purchaseQty6) | |||
@@ -426,6 +450,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "purchaseQty7", | |||
label: t("Demand Qty (Day7)"), | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty7) == "number") { | |||
return decimalFormatter.format(row.purchaseQty7) | |||
@@ -460,6 +487,9 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "Available Qty", | |||
type: 'read-only', | |||
// editable: true, | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
@@ -469,8 +499,11 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
}, | |||
{ | |||
field: "purchaseQty", | |||
label: "Purchase Qty", | |||
label: "Demand Qty", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.purchaseQty) == "number") { | |||
return decimalFormatter.format(row.purchaseQty) | |||
@@ -466,6 +466,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "inStockQty", | |||
label: "Available Qty", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
// editable: true, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
@@ -478,6 +481,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "productionQty", | |||
label: "Demand Qty", | |||
type: 'input', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.productionQty) == "number") { | |||
return decimalFormatter.format(row.productionQty ?? 0) | |||
@@ -513,7 +519,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "Last Month Average Stock", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "center", | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.lastMonthAvgStock) == "number") { | |||
@@ -528,7 +534,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "Safety Stock", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "center", | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.safetyStock) == "number") { | |||
@@ -543,7 +549,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "Available Qty", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "center", | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
@@ -30,7 +30,7 @@ interface BaseCriterion<T extends string> { | |||
paramName2?: T; | |||
options?: T[]; | |||
filterObj?: T; | |||
handleSelectionChange: (selectedOptions: T[]) => void; | |||
handleSelectionChange?: (selectedOptions: T[]) => void; | |||
} | |||
interface TextCriterion<T extends string> extends BaseCriterion<T> { | |||
@@ -16,11 +16,12 @@ import CancelIcon from "@mui/icons-material/Close"; | |||
import DeleteIcon from "@mui/icons-material/Delete"; | |||
import TextField from "@mui/material/TextField"; | |||
import MultiSelect from "@/components/SearchBox/MultiSelect"; | |||
import { Collapse } from "@mui/material"; | |||
import { Collapse, Typography } from "@mui/material"; | |||
import TempInputGridForMockUp from "./TempInputGridForMockUp"; | |||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; | |||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | |||
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | |||
import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | |||
export interface ResultWithId { | |||
id: string | number; | |||
@@ -131,6 +132,11 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
return ( | |||
<> | |||
<TableRow hover tabIndex={-1} key={row.id}> | |||
<TableCell> | |||
<IconButton disable={!isEdit}> | |||
<PlayCircleOutlineIcon /> | |||
</IconButton> | |||
</TableCell> | |||
{ | |||
(isEditable || hasCollapse) && <TableCell> | |||
{(editingRowId === row.id) ? ( | |||
@@ -152,6 +158,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
<Typography>View BoM</Typography> | |||
</IconButton> | |||
} | |||
</> | |||
@@ -176,6 +183,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
<Typography>View BoM</Typography> | |||
</IconButton> | |||
} | |||
</> | |||
@@ -183,7 +191,6 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
</TableCell> | |||
} | |||
{columns.map((column, idx) => { | |||
console.log(column) | |||
const columnName = column.field; | |||
return ( | |||
<TableCell key={`${columnName.toString()}-${idx}`}> | |||
@@ -227,7 +234,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
: | |||
<div style={column.style}> | |||
<span onDoubleClick={() => isEdit && handleEditClick(row.id as number)}> | |||
{row[columnName] as String} | |||
{row[columnName] as String} | |||
</span> | |||
</div> | |||
)} | |||
@@ -265,6 +272,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
<Table stickyHeader> | |||
<TableHead> | |||
<TableRow> | |||
<TableCell>Release</TableCell> | |||
{(isEditable || hasCollapse) && <TableCell>Actions</TableCell>} {/* Action Column Header */} | |||
{columns.map((column, idx) => ( | |||
<TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | |||
@@ -22,7 +22,7 @@ import { | |||
} from "react"; | |||
import StyledDataGrid from "../StyledDataGrid"; | |||
import { GridColDef } from "@mui/x-data-grid"; | |||
import { Box, Button, Grid, Typography } from "@mui/material"; | |||
import { Box, Button, Grid, Icon, Typography } from "@mui/material"; | |||
import { useTranslation } from "react-i18next"; | |||
import { Add } from "@mui/icons-material"; | |||
import SaveIcon from "@mui/icons-material/Save"; | |||
@@ -36,6 +36,7 @@ import PlayArrowIcon from "@mui/icons-material/PlayArrow"; | |||
import { createStockInLine, testFetch } from "@/app/api/po/actions"; | |||
import { useSearchParams } from "next/navigation"; | |||
import { decimalFormatter, stockInLineStatusMap } from "@/app/utils/formatUtil"; | |||
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | |||
interface ResultWithId { | |||
id: number; | |||
@@ -184,6 +185,8 @@ function TempInputGridForMockUp({ stockInLine }: Props) { | |||
flex: 0.5, | |||
type: "number", | |||
editable: true, | |||
align: "right", | |||
headerAlign: "right", | |||
renderCell: (row) => { | |||
return decimalFormatter.format(row.value) | |||
} | |||
@@ -194,10 +197,26 @@ function TempInputGridForMockUp({ stockInLine }: Props) { | |||
headerName: "Demand Qty", | |||
flex: 0.5, | |||
editable: true, | |||
align: "right", | |||
headerAlign: "right", | |||
renderCell: (row) => { | |||
return decimalFormatter.format(row.value) | |||
} | |||
}, | |||
{ | |||
field: "status", | |||
headerName: "status", | |||
flex: 0.5, | |||
editable: true, | |||
align: "center", | |||
headerAlign: "center", | |||
renderCell: () => { | |||
return <CheckCircleOutlineIcon | |||
color="success" | |||
fontSize="small" | |||
/> | |||
} | |||
}, | |||
// { | |||
// field: "actions", | |||
// type: "actions", | |||
@@ -398,13 +417,13 @@ function TempInputGridForMockUp({ stockInLine }: Props) { | |||
} | |||
return classname; | |||
}} | |||
// slots={{ | |||
// footer: FooterToolbar, | |||
// noRowsOverlay: NoRowsOverlay, | |||
// }} | |||
// slotProps={{ | |||
// footer: { child: footer }, | |||
// }} | |||
// slots={{ | |||
// footer: FooterToolbar, | |||
// noRowsOverlay: NoRowsOverlay, | |||
// }} | |||
// slotProps={{ | |||
// footer: { child: footer }, | |||
// }} | |||
/> | |||
</> | |||
); | |||