| @@ -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("schedule", "common"); | |||
| return ( | |||
| <Stack spacing={2}> | |||
| <Typography variant="h4">{t("Not Found")}</Typography> | |||
| <Typography variant="body1">{t("The production schedule detail page was not found!")}</Typography> | |||
| <Link href="/settings/scheduling" component={NextLink} variant="body2"> | |||
| {t("Return to all scheduling")} | |||
| </Link> | |||
| </Stack> | |||
| ); | |||
| } | |||
| @@ -8,15 +8,35 @@ import Typography from "@mui/material/Typography"; | |||
| import { Metadata } from "next"; | |||
| import Link from "next/link"; | |||
| import { Suspense } from "react"; | |||
| import RoughScheduleDetailView from "@/components/RoughScheduleDetail/RoughScheudleDetailView"; | |||
| import RoughScheduleDetailView from "@/components/RoughScheduleDetail"; | |||
| import { SearchParams, ServerFetchError } from "@/app/utils/fetchUtil"; | |||
| import { isArray, parseInt } from "lodash"; | |||
| import { notFound } from "next/navigation"; | |||
| import { fetchProdScheduleDetail } from "@/app/api/scheduling"; | |||
| export const metadata: Metadata = { | |||
| title: "Demand Forecast Detail", | |||
| }; | |||
| const roughSchedulingDetail: React.FC = async () => { | |||
| // const project = TypeEnum.PRODUCT | |||
| const { t } = await getServerI18n("project"); | |||
| type Props = SearchParams | |||
| const roughSchedulingDetail: React.FC<Props> = async ({ searchParams }) => { | |||
| const { t } = await getServerI18n("schedule"); | |||
| const id = searchParams["id"] | |||
| const type = "rough" | |||
| if (!id || isArray(id) || !isFinite(parseInt(id))) { | |||
| notFound() | |||
| } | |||
| try { | |||
| await fetchProdScheduleDetail(parseInt(id)) | |||
| } catch(e) { | |||
| if (e instanceof ServerFetchError && (e.response?.status === 404 || e.response?.status === 400)) { | |||
| console.log(e) | |||
| notFound(); | |||
| } | |||
| } | |||
| // preloadClaims(); | |||
| return ( | |||
| @@ -39,9 +59,9 @@ const roughSchedulingDetail: React.FC = async () => { | |||
| {t("Create product")} | |||
| </Button> */} | |||
| </Stack> | |||
| <I18nProvider namespaces={["schedule","project","common"]}> | |||
| <I18nProvider namespaces={["schedule","common"]}> | |||
| <Suspense fallback={<RoughScheduleDetailView.Loading />}> | |||
| <RoughScheduleDetailView /> | |||
| <RoughScheduleDetailView type={type} id={parseInt(id)}/> | |||
| </Suspense> | |||
| </I18nProvider> | |||
| </> | |||
| @@ -19,6 +19,7 @@ export const metadata: Metadata = { | |||
| const roughScheduling: React.FC = async () => { | |||
| // const project = TypeEnum.PRODUCT | |||
| const { t } = await getServerI18n("schedule"); | |||
| const type = "rough" | |||
| // preloadClaims(); | |||
| return ( | |||
| @@ -44,7 +45,7 @@ const roughScheduling: React.FC = async () => { | |||
| </Stack> | |||
| <I18nProvider namespaces={["schedule", "common","items","project"]}> | |||
| <Suspense fallback={<RoughSchedule.Loading />}> | |||
| <RoughSchedule /> | |||
| <RoughSchedule type={type}/> | |||
| </Suspense> | |||
| </I18nProvider> | |||
| </> | |||
| @@ -0,0 +1,43 @@ | |||
| "use server" | |||
| import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; | |||
| import { serverFetchJson } from "@/app/utils/fetchUtil" | |||
| import { BASE_API_URL } from "@/config/api" | |||
| import { cache } from "react" | |||
| export interface SearchProdSchedule { | |||
| scheduleAt?: string; | |||
| schedulePeriod?: string; | |||
| schedulePeriodTo?: string; | |||
| totalEstProdCount?: number; | |||
| type?: "manual" | "detailed" | "rough"; | |||
| pageSize?: number; | |||
| pageNum?: number; | |||
| } | |||
| export interface ProdScheduleResult { | |||
| id: number; | |||
| scheduleAt: number[]; | |||
| schedulePeriod: number[]; | |||
| schedulePeriodTo: number[]; | |||
| totalEstProdCount: number; | |||
| totalFGType: number; | |||
| type: string; | |||
| } | |||
| export interface ProdScheduleResultByPage { | |||
| total: number; | |||
| records: ProdScheduleResult[]; | |||
| } | |||
| export const fetchProdSchedules = cache(async (data: SearchProdSchedule | null) => { | |||
| const params = convertObjToURLSearchParams<SearchProdSchedule>(data) | |||
| // console.log(params) | |||
| return serverFetchJson<ProdScheduleResultByPage>(`${BASE_API_URL}/productionSchedule/getRecordByPage?${params}`, { | |||
| method: "GET", | |||
| headers: { "Content-Type": "application/json" }, | |||
| next: { | |||
| tags: ["prodSchedules"] | |||
| } | |||
| }) | |||
| }) | |||
| @@ -0,0 +1,82 @@ | |||
| import { serverFetchJson } from "@/app/utils/fetchUtil" | |||
| import { BASE_API_URL } from "@/config/api" | |||
| import { cache } from "react" | |||
| import "server-only" | |||
| export type ScheduleType = "rough" | "detail"; | |||
| export interface ProdScheduleResult { | |||
| id: number; | |||
| scheduleAt: number[]; | |||
| schedulePeriod: number[]; | |||
| schedulePeriodTo: number[]; | |||
| totalEstProdCount: number; | |||
| totalFGType: number; | |||
| type: string; | |||
| prodScheduleLinesByFg: ProdScheduleLineResultByFg[]; | |||
| prodScheduleLinesByFgByDate: { [assignDate: number]: ProdScheduleLineResultByFg[] }; | |||
| prodScheduleLinesByBom: ProdScheduleLineResultByBom[]; | |||
| prodScheduleLinesByBomByDate: { [assignDate: number]: ProdScheduleLineResultByBomByDate[] }; | |||
| } | |||
| export interface ProdScheduleLineResultByFg { | |||
| id: number; | |||
| code: string; | |||
| name: string; | |||
| type: string; | |||
| availableQty: number; | |||
| prodQty: number; | |||
| lastMonthAvgSales: number; | |||
| estCloseBal: number; | |||
| priority: number; | |||
| assignDate: number; | |||
| bomMaterials: ProdScheduleLineBomMaterialResult[]; | |||
| } | |||
| export interface ProdScheduleLineBomMaterialResult { | |||
| id: number; | |||
| code: string; | |||
| name: string; | |||
| type: string; | |||
| availableQty: number; | |||
| demandQty: number; | |||
| uomName: string; | |||
| } | |||
| export interface ProdScheduleLineResultByBom { | |||
| id: number, | |||
| code: string, | |||
| name: string, | |||
| type: string, | |||
| availableQty: number, | |||
| totalDemandQty: number, | |||
| demandQty1: number, | |||
| demandQty2: number, | |||
| demandQty3: number, | |||
| demandQty4: number, | |||
| demandQty5: number, | |||
| demandQty6: number, | |||
| demandQty7: number, | |||
| uomName: string, | |||
| } | |||
| export interface ProdScheduleLineResultByBomByDate { | |||
| id: number, | |||
| code: string, | |||
| name: string, | |||
| type: string, | |||
| availableQty: number, | |||
| demandQty: number, | |||
| assignDate: number, | |||
| uomName: string, | |||
| } | |||
| export const fetchProdScheduleDetail = cache(async (id: number) => { | |||
| return serverFetchJson<ProdScheduleResult>(`${BASE_API_URL}/productionSchedule/detail/${id}`, { | |||
| method: "GET", | |||
| headers: { "Content-Type": "application/json" }, | |||
| next: { | |||
| tags: ["prodSchedule"] | |||
| } | |||
| }) | |||
| }) | |||
| @@ -1,65 +1,60 @@ | |||
| "use client"; | |||
| import React, {useCallback, useEffect, useMemo, useState} from "react"; | |||
| import React, { useCallback, useEffect, useMemo, useState } from "react"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import { ItemsResult} from "@/app/api/settings/item"; | |||
| 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 { 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 | |||
| type RecordStructure ={ | |||
| id: number, | |||
| schedulePeriod: string, | |||
| scheduleAt: string | |||
| }; | |||
| import { ProdScheduleResult, ProdScheduleResultByPage, SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | |||
| import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil"; | |||
| import { isEqual, uniqBy } from "lodash"; | |||
| import dayjs from "dayjs"; | |||
| import { defaultPagingController } from "../SearchResults/SearchResults"; | |||
| // type RecordStructure ={ | |||
| // id: number, | |||
| // schedulePeriod: string, | |||
| // scheduleAt: string | |||
| // }; | |||
| type Props = { | |||
| records: RecordStructure[]; | |||
| type: SearchProdSchedule["type"]; | |||
| // initProdSchedules: ProdScheduleResultByPage; | |||
| defaultInputs: SearchProdSchedule; | |||
| }; | |||
| type SearchQuery = Partial<Omit<ItemsResult, "id">>; | |||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "type" | "pageSize" | "pageNum">>; | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const RSOverview: React.FC<Props> = ({ records }) => { | |||
| const [filteredItems, setFilteredItems] = useState<Object[]>(records ?? []); | |||
| const { t } = useTranslation("items"); | |||
| const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | |||
| const [filteredSchedules, setFilteredSchedules] = useState<ProdScheduleResult[]>([]); | |||
| const { t } = useTranslation("scheduling"); | |||
| 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 | |||
| var title = ""; | |||
| var mode = "Search"; | |||
| var redirPath = ""; | |||
| title = "Product"; | |||
| redirPath = "/scheduling/rough"; | |||
| return [mode, redirPath]; | |||
| }, []); | |||
| // const [filterObj, setFilterObj] = useState({}); | |||
| // const [tempSelectedValue, setTempSelectedValue] = useState({}); | |||
| const [pagingController, setPagingController] = useState(defaultPagingController) | |||
| const [totalCount, setTotalCount] = useState(0) | |||
| const [inputs, setInputs] = useState(defaultInputs) | |||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | |||
| () => { | |||
| var searchCriteria: Criterion<SearchParamNames>[] = [ | |||
| { label: t("Schedule Period"), paramName: "schedulePeriod", type: "dateRange" }, | |||
| { label: t("Schedule Period"), label2: t("Schedule Period To"), paramName: "schedulePeriod", type: "dateRange" }, | |||
| { label: t("Scheduled At"), paramName: "scheduleAt", type: "date" }, | |||
| { label: t("Product Count"), paramName: "productCount", type: "input" }, | |||
| { label: t("Product Count"), paramName: "totalEstProdCount", type: "text" }, | |||
| ] | |||
| return searchCriteria | |||
| }, | |||
| [t, records] | |||
| [t] | |||
| ); | |||
| // const onDetailClick = useCallback( | |||
| @@ -70,7 +65,7 @@ const RSOverview: React.FC<Props> = ({ records }) => { | |||
| // ); | |||
| const onDeleteClick = useCallback( | |||
| (item: ItemsResult) => {}, | |||
| (item: ItemsResult) => { }, | |||
| [router] | |||
| ); | |||
| @@ -79,25 +74,36 @@ const RSOverview: React.FC<Props> = ({ records }) => { | |||
| router.push(`/scheduling/rough/edit?id=${record.id}`); | |||
| } | |||
| const columns = useMemo<Column<ItemsResult>[]>( | |||
| const columns = useMemo<Column<ProdScheduleResult>[]>( | |||
| () => [ | |||
| { | |||
| name: "id", | |||
| label: t("Details"), | |||
| onClick: (record)=>onDetailClick(record), | |||
| onClick: (record) => onDetailClick(record), | |||
| buttonIcon: <EditNote />, | |||
| }, | |||
| { | |||
| name: "scheduledPeriod", | |||
| name: "schedulePeriod", | |||
| label: t("Demand Forecast Period"), | |||
| renderCell: (params) => { | |||
| return `${arrayToDateString(params.schedulePeriod)} - ${arrayToDateString(params.schedulePeriodTo)}` | |||
| } | |||
| }, | |||
| { | |||
| name: "scheduledAt", | |||
| label: t("Scheduled At"), | |||
| name: "scheduleAt", | |||
| label: t("Schedule At"), | |||
| renderCell: (params) => { | |||
| return arrayToDateString(params.scheduleAt) | |||
| } | |||
| }, | |||
| { | |||
| name: "productCount", | |||
| name: "totalEstProdCount", | |||
| label: t("Product Count(s)"), | |||
| headerAlign: "right", | |||
| align: "right", | |||
| renderCell: (params) => { | |||
| return decimalFormatter.format(params.totalEstProdCount) | |||
| } | |||
| }, | |||
| // { | |||
| // name: "action", | |||
| @@ -106,92 +112,134 @@ const RSOverview: React.FC<Props> = ({ records }) => { | |||
| // onClick: onDeleteClick, | |||
| // }, | |||
| ], | |||
| [filteredItems] | |||
| [filteredSchedules] | |||
| ); | |||
| useEffect(() => { | |||
| refetchData(filterObj); | |||
| }, [filterObj, pagingController.pageNum, pagingController.pageSize]); | |||
| const refetchData = async (filterObj: SearchQuery) => { | |||
| const authHeader = axiosInstance.defaults.headers['Authorization']; | |||
| if (!authHeader) { | |||
| return; // Exit the function if the token is not set | |||
| // useEffect(() => { | |||
| // refetchData(filterObj); | |||
| // }, [filterObj, pagingController.pageNum, pagingController.pageSize]); | |||
| const refetchData = useCallback(async (query: Record<SearchParamNames, string> | SearchProdSchedule, actionType: "reset" | "search" | "paging") => { | |||
| // console.log(query) | |||
| const params: SearchProdSchedule = { | |||
| scheduleAt: dayjs(query?.scheduleAt).isValid() ? query?.scheduleAt : undefined, | |||
| schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined, | |||
| schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | |||
| totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | |||
| type: "rough", | |||
| pageNum: pagingController.pageNum - 1, | |||
| pageSize: pagingController.pageSize | |||
| } | |||
| const params ={ | |||
| pageNum: pagingController.pageNum, | |||
| pageSize: pagingController.pageSize, | |||
| ...filterObj, | |||
| ...tempSelectedValue, | |||
| const response = await fetchProdSchedules(params) | |||
| // console.log(response) | |||
| if (response) { | |||
| setTotalCount(response.total) | |||
| switch (actionType) { | |||
| case "reset": | |||
| case "search": | |||
| setFilteredSchedules(() => response.records) | |||
| break; | |||
| case "paging": | |||
| setFilteredSchedules((fs) => uniqBy([...fs, ...response.records], "id")) | |||
| break; | |||
| } | |||
| } | |||
| }, [pagingController, setPagingController]) | |||
| 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 | |||
| } | |||
| }; | |||
| useEffect(() => { | |||
| refetchData(inputs, "paging") | |||
| }, [pagingController]) | |||
| // const refetchData = async (filterObj: SearchQuery) => { | |||
| // 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' }); | |||
| // // }, | |||
| // // }); | |||
| // //setFilteredSchedules(response.data.records); | |||
| // // setFilteredSchedules([ | |||
| // // { | |||
| // // 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(); | |||
| }, [records]); | |||
| // setFilteredSchedules(items ?? []); | |||
| // setFilterObj({}); | |||
| // setTempSelectedValue({}); | |||
| refetchData(inputs, "reset"); | |||
| }, []); | |||
| return ( | |||
| <> | |||
| <SearchBox | |||
| criteria={searchCriteria} | |||
| onSearch={(query) => { | |||
| setFilterObj({ | |||
| ...query | |||
| }) | |||
| // resetPagingController() | |||
| setInputs(() => ( | |||
| { | |||
| scheduleAt: query?.scheduleAt, | |||
| schedulePeriod: query?.schedulePeriod, | |||
| schedulePeriodTo: query?.schedulePeriodTo, | |||
| totalEstProdCount: Number(query?.totalEstProdCount) | |||
| } | |||
| )) | |||
| refetchData(query, "search") | |||
| // setFilterObj({ | |||
| // ...query | |||
| // }) | |||
| }} | |||
| onReset={onReset} | |||
| /> | |||
| <SearchResults<ItemsResult> | |||
| items={filteredItems} | |||
| <SearchResults<ProdScheduleResult> | |||
| items={filteredSchedules} | |||
| columns={columns} | |||
| setPagingController={setPagingController} | |||
| pagingController={pagingController} | |||
| isAutoPaging={false} | |||
| hasCollapse={false} | |||
| totalCount={totalCount} | |||
| // isAutoPaging={false} | |||
| /> | |||
| </> | |||
| ); | |||
| @@ -1,21 +1,35 @@ | |||
| import { fetchAllItems } from "@/app/api/settings/item"; | |||
| import { RoughScheduleLoading } from "./RoughScheduleLoading"; | |||
| import RSOverview from "./RoughSchedileSearchView"; | |||
| import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | |||
| interface SubComponents { | |||
| Loading: typeof RoughScheduleLoading; | |||
| } | |||
| type Props = {}; | |||
| type Props = { | |||
| type: SearchProdSchedule["type"] | |||
| }; | |||
| const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | |||
| { | |||
| // type, | |||
| type | |||
| } | |||
| ) => { | |||
| // console.log(type) | |||
| var result = await fetchAllItems(); | |||
| return <RSOverview records={[]} />; | |||
| const defaultInputs: SearchProdSchedule = { | |||
| type: "rough" | |||
| } | |||
| // const [ | |||
| // items, | |||
| // prodSchedules | |||
| // ] = await Promise.all([ | |||
| // fetchAllItems(), | |||
| // fetchProdSchedules(defaultInputs) | |||
| // ]) | |||
| return <RSOverview type={type} defaultInputs={defaultInputs}/>; | |||
| }; | |||
| RoughScheduleWrapper.Loading = RoughScheduleLoading; | |||
| @@ -3,48 +3,53 @@ import { | |||
| Box, | |||
| Card, | |||
| CardContent, | |||
| FormControl, | |||
| Grid, | |||
| Stack, | |||
| TextField, | |||
| Typography, | |||
| } from "@mui/material"; | |||
| import { useFormContext } from "react-hook-form"; | |||
| import { Controller, useFormContext } from "react-hook-form"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import InputDataGrid from "../InputDataGrid"; | |||
| import {useCallback, useEffect, useMemo, useState} from "react"; | |||
| 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 { NumberInputProps } from "@/components/CreateItem/NumberInputProps"; | |||
| import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil"; | |||
| import { ProdScheduleResult } from "@/app/api/scheduling"; | |||
| import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; | |||
| import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||
| type Props = { | |||
| // isEditMode: boolean; | |||
| // type: TypeEnum; | |||
| isEditing: boolean; | |||
| }; | |||
| const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => { | |||
| const DetailInfoCard: React.FC<Props> = ({ isEditing }) => { | |||
| const { | |||
| t, | |||
| i18n: { language }, | |||
| } = useTranslation(); | |||
| const { | |||
| control, | |||
| register, | |||
| getValues, | |||
| watch, | |||
| formState: { errors, defaultValues, touchedFields }, | |||
| } = useFormContext<CreateItemInputs>(); | |||
| } = useFormContext<ProdScheduleResult>(); | |||
| const [details, setDetails] = useState(null); | |||
| // const [details, setDetails] = useState(null); | |||
| useEffect(()=>{ | |||
| console.log("[debug] record details", recordDetails) | |||
| setDetails(recordDetails); | |||
| },[recordDetails]) | |||
| useEffect(() => { | |||
| console.log("[debug] record details", getValues) | |||
| // setDetails(recordDetails); | |||
| }, [getValues]) | |||
| useEffect(()=>{ | |||
| useEffect(() => { | |||
| console.log("[debug] isEdit", isEditing) | |||
| },[isEditing]) | |||
| }, [isEditing]) | |||
| return ( | |||
| <Card sx={{ display: "block" }}> | |||
| @@ -58,39 +63,39 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => { | |||
| <TextField | |||
| label={t("Date")} | |||
| fullWidth | |||
| {...register("scheduledPeriod", { | |||
| required: "name required!", | |||
| })} | |||
| defaultValue={details?.scheduledPeriod} | |||
| // {...register("scheduledPeriod", { | |||
| // required: "name required!", | |||
| // })} | |||
| defaultValue={`${arrayToDateString(getValues("schedulePeriod"))} - ${arrayToDateString(getValues("schedulePeriodTo"))}`} | |||
| disabled={!isEditing} | |||
| error={Boolean(errors.name)} | |||
| helperText={errors.name?.message} | |||
| // error={Boolean(errors.name)} | |||
| // helperText={errors.name?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("Total FG Item")} | |||
| fullWidth | |||
| {...register("productCount", { | |||
| required: "code required!", | |||
| })} | |||
| defaultValue={details?.productCount} | |||
| // {...register("totalFGType", { | |||
| // required: "Total FG Item required!", | |||
| // })} | |||
| defaultValue={typeof (getValues("totalFGType")) == "number" ? integerFormatter.format(getValues("totalFGType")) : getValues("totalFGType")} | |||
| disabled={!isEditing} | |||
| error={Boolean(errors.code)} | |||
| helperText={errors.code?.message} | |||
| // error={Boolean(errors.code)} | |||
| // helperText={errors.code?.message} | |||
| /> | |||
| </Grid> | |||
| <Grid item xs={6}> | |||
| <TextField | |||
| label={t("Total Estimated Demand Qty")} | |||
| fullWidth | |||
| {...register("productionCount", { | |||
| required: "type required!", | |||
| })} | |||
| disabled={!isEditing} | |||
| defaultValue={typeof(details?.productionCount) == "number" ? integerFormatter.format(details?.productionCount) : details?.productionCount} | |||
| error={Boolean(errors.type)} | |||
| helperText={errors.type?.message} | |||
| label={t("Total Estimated Demand Qty")} | |||
| fullWidth | |||
| // {...register("totalEstProdCount", { | |||
| // required: "Qty required!", | |||
| // })} | |||
| disabled={!isEditing} | |||
| defaultValue={typeof (getValues("totalFGType")) == "number" ? integerFormatter.format(getValues("totalEstProdCount")) : getValues("totalEstProdCount")} | |||
| // error={Boolean(errors.type)} | |||
| // helperText={errors.type?.message} | |||
| /> | |||
| </Grid> | |||
| </Grid> | |||
| @@ -2,46 +2,25 @@ import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
| import { fetchItem } from "@/app/api/settings/item"; | |||
| import GeneralLoading from "@/components/General/GeneralLoading"; | |||
| import RoughScheduleDetailView from "@/components/RoughScheduleDetail/RoughScheudleDetailView"; | |||
| import React from "react"; | |||
| import { ScheduleType, fetchProdScheduleDetail } from "@/app/api/scheduling"; | |||
| interface SubComponents { | |||
| Loading: typeof GeneralLoading; | |||
| } | |||
| type Props = { | |||
| id?: number | |||
| // type: TypeEnum; | |||
| type: ScheduleType; | |||
| }; | |||
| const RoughScheduleDetailWrapper: (id: { id: any }) => Promise<JSX.Element> = async ({ id: any }) => { | |||
| var result | |||
| var defaultValues: Partial<CreateItemInputs> | undefined | |||
| // console.log(type) | |||
| var qcChecks | |||
| if (id) { | |||
| result = await fetchItem(id); | |||
| const item = result.item | |||
| qcChecks = result.qcChecks | |||
| const activeRows = qcChecks.filter(it => it.isActive).map(i => i.id) | |||
| console.log(qcChecks) | |||
| defaultValues = { | |||
| type: item?.type, | |||
| id: item?.id, | |||
| code: item?.code, | |||
| name: item?.name, | |||
| description: item?.description, | |||
| remarks: item?.remarks, | |||
| shelfLife: item?.shelfLife, | |||
| countryOfOrigin: item?.countryOfOrigin, | |||
| maxQty: item?.maxQty, | |||
| qcChecks: qcChecks, | |||
| qcChecks_active: activeRows | |||
| }; | |||
| } | |||
| const RoughScheduleDetailWrapper: React.FC<Props> & SubComponents = async ({ id, type }) => { | |||
| const prodSchedule = id ? await fetchProdScheduleDetail(id) : undefined | |||
| return ( | |||
| <RoughScheduleDetailView | |||
| isEditMode={Boolean(id)} | |||
| defaultValues={defaultValues} | |||
| qcChecks={qcChecks || []} | |||
| type={type} | |||
| defaultValues={prodSchedule} | |||
| /> | |||
| ); | |||
| }; | |||
| @@ -14,28 +14,30 @@ import { | |||
| 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 { 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/RoughScheduleDetail/DetailInfoCard"; | |||
| import ViewByFGDetails, {FGRecord} from "@/components/RoughScheduleDetail/ViewByFGDetails"; | |||
| import ViewByFGDetails from "@/components/RoughScheduleDetail/ViewByFGDetails"; | |||
| import ViewByBomDetails from "@/components/RoughScheduleDetail/ViewByBomDetails"; | |||
| import EditableSearchResults, {Column} from "@/components/SearchResults/EditableSearchResults"; | |||
| import ScheduleTable from "@/components/ScheduleTable"; | |||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | |||
| import { ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||
| import { arrayToDayjs, dayjsToDateString } from "@/app/utils/formatUtil"; | |||
| type Props = { | |||
| isEditMode: boolean; | |||
| // type: TypeEnum; | |||
| defaultValues: Partial<CreateItemInputs> | undefined; | |||
| qcChecks: ItemQc[] | |||
| type: ScheduleType; | |||
| defaultValues: Partial<ProdScheduleResult> | undefined; | |||
| // qcChecks: ItemQc[] | |||
| }; | |||
| const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| isEditMode, | |||
| // type, | |||
| type, | |||
| defaultValues, | |||
| qcChecks | |||
| }) => { | |||
| // console.log(type) | |||
| const apiRef = useGridApiRef(); | |||
| @@ -47,35 +49,9 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| const router = useRouter(); | |||
| const [isEdit, setIsEdit] = useState(false); | |||
| //const title = "Demand Forecast Detail" | |||
| const [mode, redirPath] = useMemo(() => { | |||
| // var typeId = TypeEnum.CONSUMABLE_ID | |||
| var title = ""; | |||
| var mode = ""; | |||
| var 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/rough/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<CreateItemInputs>({ | |||
| const formProps = useForm<ProdScheduleResult>({ | |||
| defaultValues: defaultValues ? defaultValues : { | |||
| }, | |||
| }); | |||
| @@ -88,7 +64,18 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| [], | |||
| ); | |||
| const dayPeriod = useMemo<string[]>(() => { | |||
| const from = arrayToDayjs(formProps.getValues("schedulePeriod")) | |||
| const to = arrayToDayjs(formProps.getValues("schedulePeriodTo")) | |||
| const diffDays = Math.abs(from.diff(to, "day")) | |||
| let result: string[] = [] | |||
| for (let i = 0; i <= diffDays; i++) { | |||
| result.push(dayjsToDateString(from.add(i, "day"))) | |||
| } | |||
| return result; | |||
| }, []) | |||
| const [pagingController, setPagingController] = useState({ | |||
| pageNum: 1, | |||
| @@ -101,7 +88,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| router.replace(`/scheduling/rough`); | |||
| }; | |||
| const onSubmit = useCallback<SubmitHandler<CreateItemInputs & {}>>( | |||
| const onSubmit = useCallback<SubmitHandler<ProdScheduleResult>>( | |||
| async (data, event) => { | |||
| let hasErrors = false; | |||
| console.log(errors) | |||
| @@ -122,12 +109,12 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| ); | |||
| // multiple tabs | |||
| const onSubmitError = useCallback<SubmitErrorHandler<CreateItemInputs>>( | |||
| (errors) => {}, | |||
| const onSubmitError = useCallback<SubmitErrorHandler<ProdScheduleResult>>( | |||
| (errors) => { }, | |||
| [] | |||
| ); | |||
| const onClickEdit = () =>{ | |||
| const onClickEdit = () => { | |||
| setIsEdit(!isEdit) | |||
| } | |||
| @@ -139,57 +126,57 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| component="form" | |||
| onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} | |||
| > | |||
| {/*<Grid>*/} | |||
| {/* <Typography mb={2} variant="h4">*/} | |||
| {/* {t(`${mode} ${title}`)}*/} | |||
| {/* </Typography>*/} | |||
| {/*</Grid>*/} | |||
| <DetailInfoCard | |||
| recordDetails={{ | |||
| id: 1, | |||
| scheduledPeriod: "2025-05-11 to 2025-05-17", | |||
| scheduledAt: "2025-05-07", | |||
| productCount: 13, | |||
| productionCount: 21000 | |||
| }} | |||
| {/*<Grid>*/} | |||
| {/* <Typography mb={2} variant="h4">*/} | |||
| {/* {t(`${mode} ${title}`)}*/} | |||
| {/* </Typography>*/} | |||
| {/*</Grid>*/} | |||
| <DetailInfoCard | |||
| // recordDetails={{ | |||
| // id: 1, | |||
| // scheduledPeriod: "2025-05-11 to 2025-05-17", | |||
| // scheduledAt: "2025-05-07", | |||
| // productCount: 13, | |||
| // productionCount: 21000 | |||
| // }} | |||
| isEditing={isEdit} | |||
| /> | |||
| <Stack | |||
| /> | |||
| {/* <Stack | |||
| direction="row" | |||
| justifyContent="space-between" | |||
| flexWrap="wrap" | |||
| rowGap={2} | |||
| > | |||
| <Button | |||
| > | |||
| <Button | |||
| variant="contained" | |||
| onClick={onClickEdit} | |||
| // startIcon={<Add />} | |||
| //LinkComponent={Link} | |||
| //href="qcCategory/create" | |||
| > | |||
| {isEdit ? t("Save") : t("Edit")} | |||
| </Button> | |||
| </Stack> | |||
| // 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 ? t(" (Selected)") : "")} iconPosition="end"/> | |||
| <Tab label={t("View By Material") + (tabIndex === 1 ? t(" (Selected)") : "")} iconPosition="end" /> | |||
| </Tabs> | |||
| <Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable"> | |||
| <Tab label={t("View By FG") + (tabIndex === 0 ? t(" (Selected)") : "")} iconPosition="end" /> | |||
| <Tab label={t("View By Material") + (tabIndex === 1 ? t(" (Selected)") : "")} iconPosition="end" /> | |||
| </Tabs> | |||
| {serverError && ( | |||
| <Typography variant="body2" color="error" alignSelf="flex-end"> | |||
| {serverError} | |||
| </Typography> | |||
| )} | |||
| {tabIndex === 0 && <ViewByFGDetails isEdit={isEdit} apiRef={apiRef}/>} | |||
| {tabIndex === 1 && <ViewByBomDetails isEdit={isEdit} apiRef={apiRef} isHideButton={true} />} | |||
| <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| {tabIndex === 0 && <ViewByFGDetails type={type} isEdit={isEdit} apiRef={apiRef} dayPeriod={dayPeriod} />} | |||
| {tabIndex === 1 && <ViewByBomDetails type={type} isEdit={isEdit} apiRef={apiRef} dayPeriod={dayPeriod}/>} | |||
| {/* <Stack direction="row" justifyContent="flex-end" gap={1}> | |||
| <Button | |||
| name="submit" | |||
| variant="contained" | |||
| startIcon={<Check />} | |||
| type="submit" | |||
| // disabled={submitDisabled} | |||
| // disabled={submitDisabled} | |||
| > | |||
| {isEditMode ? t("Save") : t("Confirm")} | |||
| </Button> | |||
| @@ -200,7 +187,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
| > | |||
| {t("Cancel")} | |||
| </Button> | |||
| </Stack> | |||
| </Stack> */} | |||
| </Stack> | |||
| </FormProvider> | |||
| </> | |||
| @@ -0,0 +1,592 @@ | |||
| // View By Bom Details | |||
| const dayPeriod = [ | |||
| '2025-05-11', | |||
| '2025-05-12', | |||
| '2025-05-13', | |||
| '2025-05-14', | |||
| '2025-05-15', | |||
| '2025-05-16', | |||
| '2025-05-17', | |||
| ]; | |||
| // const fakeRecordLine = useMemo<FGRecord[][]>( | |||
| const fakeRecordLine = [ | |||
| [ | |||
| { 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[][]>( | |||
| const fakeRecords = [ | |||
| [ | |||
| { | |||
| 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", 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 fakeOverallRecords = useMemo<FGRecord[]>( | |||
| const fakeOverallRecords = [ | |||
| { | |||
| id: 1, 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: 2, 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: 3, 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 }, | |||
| ] | |||
| }, | |||
| { | |||
| id: 4, 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 }, | |||
| ] | |||
| }, | |||
| ] | |||
| // View By Bom Details | |||
| const dayPeriod1 = [ | |||
| '2025-05-11', | |||
| '2025-05-12', | |||
| '2025-05-13', | |||
| '2025-05-14', | |||
| '2025-05-15', | |||
| '2025-05-16', | |||
| '2025-05-17', | |||
| ]; | |||
| // const fakeOverallRecords = useMemo<FGOverallRecord[]>( | |||
| const fakeOverallRecords1 = [ | |||
| { | |||
| 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 fakeRecords = useMemo<FGRecord[][]>( | |||
| const fakeRecords1 = [ | |||
| [ | |||
| { 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 }, | |||
| ], | |||
| ] | |||
| @@ -9,248 +9,67 @@ import { | |||
| GridRowSelectionModel, | |||
| useGridApiRef, | |||
| } from "@mui/x-data-grid"; | |||
| import {MutableRefObject, useCallback, useEffect, useMemo, useState} from "react"; | |||
| import { useFormContext } from "react-hook-form"; | |||
| import { MutableRefObject, useCallback, useEffect, useMemo, useState } from "react"; | |||
| import { useFieldArray, 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 { 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 EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults"; | |||
| import { decimalFormatter } from "@/app/utils/formatUtil"; | |||
| import { GridRenderCellParams } from "@mui/x-data-grid"; | |||
| import { ProdScheduleLineResultByBom, ProdScheduleLineResultByBomByDate, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||
| import ScheduleTable from "@/components/ScheduleTable"; | |||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | |||
| type Props = { | |||
| apiRef: MutableRefObject<GridApiCommunity> | |||
| isEdit: boolean | |||
| type: ScheduleType | |||
| dayPeriod: string[] | |||
| }; | |||
| type EntryError = | |||
| | { | |||
| [field in keyof QcChecksInputs]?: string; | |||
| } | |||
| | undefined; | |||
| export type FGRecord = { | |||
| id: string | number | |||
| code: string; | |||
| name: string; | |||
| inStockQty: number; | |||
| purchaseQty: number; | |||
| } | |||
| // 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; | |||
| } | |||
| // 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"); | |||
| console.log("lang:", i18n.language, "t(code):", t("code")); | |||
| const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) => { | |||
| const { t, i18n: { language }, } = useTranslation("schedule"); | |||
| const { | |||
| control, | |||
| getValues, | |||
| formState: { errors, defaultValues, touchedFields }, | |||
| } = useFormContext<CreateItemInputs>(); | |||
| // const apiRef = useGridApiRef(); | |||
| } = useFormContext<ProdScheduleResult>(); | |||
| // 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 { fields } = useFieldArray({ | |||
| control, | |||
| name: "prodScheduleLinesByBom" | |||
| }) | |||
| const [pagingController, setPagingController] = useState([ | |||
| { | |||
| @@ -295,10 +114,15 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| }, | |||
| ]) | |||
| const updatePagingController = (updatedObj) => { | |||
| const updatePagingController = (updatedObj: { | |||
| pageNum: number; | |||
| pageSize: number; | |||
| totalCount: number; | |||
| index?: number | undefined; | |||
| }) => { | |||
| setPagingController((prevState) => { | |||
| return prevState.map((item, index) => { | |||
| if (index === updatedObj?.index){ | |||
| if (index === updatedObj?.index) { | |||
| return { | |||
| ...item, | |||
| pageNum: item.pageNum, | |||
| @@ -329,139 +153,142 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| field: "type", | |||
| label: t("type"), | |||
| type: 'read-only', | |||
| renderCell: (params) => { | |||
| return t(params.type) | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "inStockQty", | |||
| field: "availableQty", | |||
| label: t("Available Qty"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.inStockQty) == "number") { | |||
| return decimalFormatter.format(row.inStockQty) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.availableQty) == "number") { | |||
| return decimalFormatter.format(row.availableQty) | |||
| } | |||
| return row.inStockQty | |||
| return row.availableQty | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "overallPurchaseQty", | |||
| field: "totalDemandQty", | |||
| label: t("Total Demand Qty"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.overallPurchaseQty) == "number") { | |||
| return decimalFormatter.format(row.overallPurchaseQty) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.totalDemandQty) == "number") { | |||
| return decimalFormatter.format(row.totalDemandQty) | |||
| } | |||
| return row.overallPurchaseQty | |||
| return row.totalDemandQty | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty1", | |||
| field: "demandQty1", | |||
| label: t("Demand Qty (Day1)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty1) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty1) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty1) == "number") { | |||
| return decimalFormatter.format(row.demandQty1) | |||
| } | |||
| return row.purchaseQty1 | |||
| return row.demandQty1 | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty2", | |||
| field: "demandQty2", | |||
| label: t("Demand Qty (Day2)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty2) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty2) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty2) == "number") { | |||
| return decimalFormatter.format(row.demandQty2) | |||
| } | |||
| return row.purchaseQty2 | |||
| return row.demandQty2 | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty3", | |||
| field: "demandQty3", | |||
| label: t("Demand Qty (Day3)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty3) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty3) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty3) == "number") { | |||
| return decimalFormatter.format(row.demandQty3) | |||
| } | |||
| return row.purchaseQty3 | |||
| return row.demandQty3 | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty4", | |||
| field: "demandQty4", | |||
| label: t("Demand Qty (Day4)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty4) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty4) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty4) == "number") { | |||
| return decimalFormatter.format(row.demandQty4) | |||
| } | |||
| return row.purchaseQty4 | |||
| return row.demandQty4 | |||
| } | |||
| },{ | |||
| field: "purchaseQty5", | |||
| }, { | |||
| field: "demandQty5", | |||
| label: t("Demand Qty (Day5)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty5) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty5) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty5) == "number") { | |||
| return decimalFormatter.format(row.demandQty5) | |||
| } | |||
| return row.purchaseQty5 | |||
| return row.demandQty5 | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty6", | |||
| field: "demandQty6", | |||
| label: t("Demand Qty (Day6)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty6) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty6) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty6) == "number") { | |||
| return decimalFormatter.format(row.demandQty6) | |||
| } | |||
| return row.purchaseQty6 | |||
| return row.demandQty6 | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty7", | |||
| field: "demandQty7", | |||
| label: t("Demand Qty (Day7)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGOverallRecord) => { | |||
| if (typeof(row.purchaseQty7) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty7) | |||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||
| if (typeof (row.demandQty7) == "number") { | |||
| return decimalFormatter.format(row.demandQty7) | |||
| } | |||
| return row.purchaseQty7 | |||
| return row.demandQty7 | |||
| } | |||
| }, | |||
| ], | |||
| [t] | |||
| ); | |||
| const columns = useMemo<Column<any>[]>( | |||
| const columns = useMemo<Column<ProdScheduleLineResultByBomByDate>[]>( | |||
| () => [ | |||
| { | |||
| field: "code", | |||
| @@ -478,56 +305,62 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| field: "type", | |||
| label: t("type"), | |||
| type: 'read-only', | |||
| renderCell: (params) => { | |||
| return t(params.type) | |||
| } | |||
| }, | |||
| { | |||
| field: "inStockQty", | |||
| field: "availableQty", | |||
| label: t("Available Qty"), | |||
| type: 'read-only', | |||
| // editable: true, | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.inStockQty) == "number") { | |||
| return decimalFormatter.format(row.inStockQty) | |||
| renderCell: (row: ProdScheduleLineResultByBomByDate) => { | |||
| if (typeof (row.availableQty) == "number") { | |||
| return decimalFormatter.format(row.availableQty) | |||
| } | |||
| return row.inStockQty | |||
| return row.availableQty | |||
| } | |||
| }, | |||
| { | |||
| field: "purchaseQty", | |||
| field: "demandQty", | |||
| label: t("Demand Qty"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.purchaseQty) == "number") { | |||
| return decimalFormatter.format(row.purchaseQty) | |||
| renderCell: (row: ProdScheduleLineResultByBomByDate) => { | |||
| if (typeof (row.demandQty) == "number") { | |||
| return decimalFormatter.format(row.demandQty) | |||
| } | |||
| return row.purchaseQty | |||
| return row.demandQty | |||
| } | |||
| }, | |||
| ], | |||
| [] | |||
| ); | |||
| console.log(getValues("prodScheduleLinesByBom")) | |||
| 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} | |||
| <ScheduleTable<ProdScheduleLineResultByBom> | |||
| // index={7} | |||
| type={type} | |||
| items={getValues("prodScheduleLinesByBom")} | |||
| columns={overallColumns} | |||
| setPagingController={updatePagingController} | |||
| pagingController={pagingController[7]} | |||
| isAutoPaging={true} | |||
| isEditable={false} | |||
| isEdit={false} | |||
| hasCollapse={false} | |||
| /> | |||
| </Grid> | |||
| {dayPeriod.map((date, index) => ( | |||
| @@ -535,15 +368,17 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| <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 | |||
| <ScheduleTable<ProdScheduleLineResultByBomByDate> | |||
| // index={index} | |||
| type={type} | |||
| items={getValues("prodScheduleLinesByBomByDate")[index + 1]} // Use the corresponding records for the day | |||
| columns={columns} | |||
| setPagingController={updatePagingController} | |||
| pagingController={pagingController[index]} | |||
| isAutoPaging={true} | |||
| isEditable={false} | |||
| isEdit={isEdit} | |||
| hasCollapse={false} | |||
| /> | |||
| </Grid> | |||
| ))} | |||
| @@ -9,379 +9,56 @@ import { | |||
| GridRowSelectionModel, | |||
| useGridApiRef, | |||
| } from "@mui/x-data-grid"; | |||
| import {MutableRefObject, useCallback, useMemo, useState} from "react"; | |||
| import { useFormContext } from "react-hook-form"; | |||
| import { MutableRefObject, useCallback, useMemo, useState } from "react"; | |||
| import { useFieldArray, 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 { 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"; | |||
| import ScheduleTable from "@/components/ScheduleTable"; | |||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | |||
| import { arrayToDayjs, dayjsToDateString, decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | |||
| import { ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||
| type Props = { | |||
| apiRef: MutableRefObject<GridApiCommunity> | |||
| isEdit: Boolean | |||
| isEdit: boolean | |||
| type: ScheduleType | |||
| dayPeriod: string[] | |||
| }; | |||
| type EntryError = | |||
| | { | |||
| [field in keyof QcChecksInputs]?: string; | |||
| } | |||
| | undefined; | |||
| export type FGRecord = { | |||
| id: string | number | |||
| code: string; | |||
| name: string; | |||
| inStockQty: number; | |||
| productionQty?: number; | |||
| purchaseQty?: number | |||
| } | |||
| // export type FGRecord = { | |||
| // id: string | number | |||
| // code: string; | |||
| // name: string; | |||
| // inStockQty: number; | |||
| // productionQty?: number; | |||
| // purchaseQty?: number | |||
| // } | |||
| const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) => { | |||
| const { | |||
| t, | |||
| i18n: { language }, | |||
| } = useTranslation("schedule"); | |||
| const { | |||
| control, | |||
| getValues, | |||
| formState: { errors, defaultValues, touchedFields }, | |||
| } = useFormContext<CreateItemInputs>(); | |||
| // const apiRef = useGridApiRef(); | |||
| } = useFormContext<ProdScheduleResult>(); | |||
| const dayPeriod = [ | |||
| '2025-05-11', | |||
| '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 { fields } = useFieldArray({ | |||
| control, | |||
| name: "prodScheduleLinesByFg" | |||
| }) | |||
| // const apiRef = useGridApiRef(); | |||
| const fakeRecords = useMemo<FGRecord[][]>( | |||
| () => [ | |||
| [ | |||
| { 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", 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 }, | |||
| ] | |||
| }, | |||
| ], | |||
| ], | |||
| [] | |||
| ); | |||
| console.log("%c DayPeriod: ", 'background: #222; color: #bada55', dayPeriod) | |||
| const [pagingController, setPagingController] = useState([ | |||
| { | |||
| @@ -426,10 +103,15 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| }, | |||
| ]) | |||
| const updatePagingController = (updatedObj) => { | |||
| const updatePagingController = (updatedObj: { | |||
| pageNum: number; | |||
| pageSize: number; | |||
| totalCount: number; | |||
| index?: number | undefined; | |||
| }) => { | |||
| setPagingController((prevState) => { | |||
| return prevState.map((item, index) => { | |||
| if (index === updatedObj?.index){ | |||
| if (index === updatedObj?.index) { | |||
| return { | |||
| ...item, | |||
| pageNum: item.pageNum, | |||
| @@ -443,7 +125,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| }); | |||
| }; | |||
| const columns = useMemo<Column<any>[]>( | |||
| const columns = useMemo<Column<ProdScheduleLineResultByFg>[]>( | |||
| () => [ | |||
| { | |||
| field: "code", | |||
| @@ -463,39 +145,39 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "inStockQty", | |||
| field: "availableQty", | |||
| label: t("Available Qty"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| // editable: true, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.inStockQty) == "number") { | |||
| return decimalFormatter.format(row.inStockQty) | |||
| renderCell: (row) => { | |||
| if (typeof (row.availableQty) == "number") { | |||
| return decimalFormatter.format(row.availableQty) | |||
| } | |||
| return row.inStockQty | |||
| return row.availableQty | |||
| } | |||
| }, | |||
| { | |||
| field: "productionQty", | |||
| field: "prodQty", | |||
| label: t("Demand Qty"), | |||
| type: 'input', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.productionQty) == "number") { | |||
| return decimalFormatter.format(row.productionQty ?? 0) | |||
| renderCell: (row) => { | |||
| if (typeof (row.prodQty) == "number") { | |||
| return decimalFormatter.format(row.prodQty ?? 0) | |||
| } | |||
| return row.productionQty | |||
| return row.prodQty | |||
| } | |||
| }, | |||
| ], | |||
| [] | |||
| ); | |||
| const overallColumns = useMemo<Column<any>[]>( | |||
| const overallColumns = useMemo<Column<ProdScheduleLineResultByFg>[]>( | |||
| () => [ | |||
| { | |||
| field: "code", | |||
| @@ -512,114 +194,75 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| field: "type", | |||
| label: t("type"), | |||
| type: 'read-only', | |||
| renderCell: (params) => { | |||
| return t(params.type) | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "lastMonthAvgStock", | |||
| field: "lastMonthAvgSales", | |||
| label: t("Last Month Average Stock"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.lastMonthAvgStock) == "number") { | |||
| return decimalFormatter.format(row.lastMonthAvgStock) | |||
| renderCell: (row) => { | |||
| if (typeof (row.lastMonthAvgSales) == "number") { | |||
| return decimalFormatter.format(row.lastMonthAvgSales) | |||
| } | |||
| return row.lastMonthAvgStock | |||
| return row.lastMonthAvgSales | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "safetyStock", | |||
| field: "estCloseBal", | |||
| label: t("Safety Stock"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.safetyStock) == "number") { | |||
| return decimalFormatter.format(row.safetyStock) | |||
| renderCell: (row) => { | |||
| if (typeof (row.estCloseBal) == "number") { | |||
| return decimalFormatter.format(row.estCloseBal) | |||
| } | |||
| return row.safetyStock | |||
| return row.estCloseBal | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "inStockQty", | |||
| field: "availableQty", | |||
| label: t("Available Qty"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.inStockQty) == "number") { | |||
| return decimalFormatter.format(row.inStockQty) | |||
| renderCell: (row) => { | |||
| if (typeof (row.availableQty) == "number") { | |||
| return decimalFormatter.format(row.availableQty) | |||
| } | |||
| return row.inStockQty | |||
| return row.availableQty | |||
| } | |||
| // editable: true, | |||
| }, | |||
| { | |||
| field: "productionQty", | |||
| field: "prodQty", | |||
| label: t("Demand Qty (7 Days)"), | |||
| type: 'read-only', | |||
| style: { | |||
| textAlign: "right", | |||
| }, | |||
| renderCell: (row: FGRecord) => { | |||
| if (typeof(row.productionQty) == "number") { | |||
| return decimalFormatter.format(row.productionQty) | |||
| renderCell: (row) => { | |||
| if (typeof (row.prodQty) == "number") { | |||
| return decimalFormatter.format(row.prodQty) | |||
| } | |||
| return row.productionQty | |||
| return row.prodQty | |||
| } | |||
| }, | |||
| ], | |||
| [] | |||
| ); | |||
| const fakeOverallRecords = useMemo<FGRecord[]>( | |||
| () => [ | |||
| { id: 1, 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: 2, 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: 3, 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 }, | |||
| ] | |||
| }, | |||
| { id: 4, 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 }, | |||
| ] | |||
| }, | |||
| ], | |||
| [] | |||
| ); | |||
| console.log(getValues("prodScheduleLinesByFg")) | |||
| return ( | |||
| <Grid container spacing={2}> | |||
| @@ -627,9 +270,10 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | |||
| {t("FG Demand List (7 Days)")} | |||
| </Typography> | |||
| <EditableSearchResults<FGRecord> | |||
| index={7} | |||
| items={fakeOverallRecords} | |||
| <ScheduleTable<ProdScheduleLineResultByFg> | |||
| // index={7} | |||
| type={type} | |||
| items={getValues("prodScheduleLinesByFg")} | |||
| columns={overallColumns} | |||
| setPagingController={updatePagingController} | |||
| pagingController={pagingController[7]} | |||
| @@ -644,8 +288,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| <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 | |||
| <ScheduleTable<ProdScheduleLineResultByFg> | |||
| type={type} | |||
| items={getValues("prodScheduleLinesByFgByDate")[index + 1]} // Use the corresponding records for the day | |||
| columns={columns} | |||
| setPagingController={updatePagingController} | |||
| pagingController={pagingController[index]} | |||
| @@ -0,0 +1,255 @@ | |||
| "use client"; | |||
| import { | |||
| FooterPropsOverrides, | |||
| GridActionsCellItem, | |||
| GridCellParams, | |||
| GridRowId, | |||
| GridRowIdGetter, | |||
| GridRowModel, | |||
| GridRowModes, | |||
| GridRowModesModel, | |||
| GridToolbarContainer, | |||
| useGridApiRef, | |||
| } from "@mui/x-data-grid"; | |||
| import { | |||
| Dispatch, | |||
| MutableRefObject, | |||
| SetStateAction, | |||
| useCallback, | |||
| useEffect, | |||
| useMemo, | |||
| useState, | |||
| } from "react"; | |||
| import StyledDataGrid from "../StyledDataGrid"; | |||
| import { GridColDef } from "@mui/x-data-grid"; | |||
| 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"; | |||
| import DeleteIcon from "@mui/icons-material/Delete"; | |||
| import CancelIcon from "@mui/icons-material/Cancel"; | |||
| import FactCheckIcon from "@mui/icons-material/FactCheck"; | |||
| import ShoppingCartIcon from "@mui/icons-material/ShoppingCart"; | |||
| // import PoQcModal from "./PoQcModal"; | |||
| import PlayArrowIcon from "@mui/icons-material/PlayArrow"; | |||
| import { useSearchParams } from "next/navigation"; | |||
| import { decimalFormatter } from "@/app/utils/formatUtil"; | |||
| import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | |||
| import HighlightOffIcon from '@mui/icons-material/HighlightOff'; | |||
| import { ProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling"; | |||
| interface ResultWithId { | |||
| id: number; | |||
| } | |||
| interface Props { | |||
| bomMaterial: ProdScheduleLineBomMaterialResult[]; | |||
| type: ScheduleType | |||
| } | |||
| export type BomMaterialEntryError = { | |||
| [field in keyof any]?: string; | |||
| }; | |||
| export type BomMaterialRow = Partial< | |||
| any & { | |||
| isActive: boolean | undefined; | |||
| _isNew: boolean; | |||
| _error: BomMaterialEntryError; | |||
| } & ResultWithId | |||
| >; | |||
| class ProcessRowUpdateError extends Error { | |||
| public readonly row: BomMaterialRow; | |||
| public readonly errors: BomMaterialEntryError | undefined; | |||
| constructor(row: BomMaterialRow, message?: string, errors?: BomMaterialEntryError) { | |||
| super(message); | |||
| this.row = row; | |||
| this.errors = errors; | |||
| Object.setPrototypeOf(this, ProcessRowUpdateError.prototype); | |||
| } | |||
| } | |||
| function BomMaterialTable({ bomMaterial }: Props) { | |||
| const { t } = useTranslation("schedule"); | |||
| const apiRef = useGridApiRef(); | |||
| const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({}); | |||
| const getRowId = useCallback<GridRowIdGetter<BomMaterialRow>>( | |||
| (row) => row.id as number, | |||
| [] | |||
| ); | |||
| const [entries, setEntries] = useState<BomMaterialRow[]>(bomMaterial || []); | |||
| const columns = useMemo<GridColDef[]>( | |||
| () => [ | |||
| { | |||
| field: "code", | |||
| headerName: t("Code"), | |||
| flex: 1, | |||
| }, | |||
| { | |||
| field: "name", | |||
| headerName: t("Name"), | |||
| flex: 1, | |||
| }, | |||
| { | |||
| field: "type", | |||
| headerName: t("type"), | |||
| flex: 1, | |||
| renderCell: (row) => { | |||
| return t(row.value) | |||
| } | |||
| }, | |||
| { | |||
| field: "availableQty", | |||
| headerName: t("Available Qty"), | |||
| flex: 0.5, | |||
| type: "number", | |||
| editable: true, | |||
| align: "right", | |||
| headerAlign: "right", | |||
| renderCell: (row) => { | |||
| return decimalFormatter.format(row.value) | |||
| } | |||
| // replace with tooltip + content | |||
| }, | |||
| { | |||
| field: "demandQty", | |||
| headerName: t("Demand Qty"), | |||
| flex: 0.5, | |||
| editable: true, | |||
| align: "right", | |||
| headerAlign: "right", | |||
| renderCell: (row) => { | |||
| return decimalFormatter.format(row.value) | |||
| } | |||
| }, | |||
| { | |||
| field: "status", | |||
| headerName: t("status"), | |||
| flex: 0.5, | |||
| editable: true, | |||
| align: "center", | |||
| headerAlign: "center", | |||
| renderCell: (params) => { | |||
| return params.row.availableQty - params.row.demandQty >= 0 ? | |||
| <CheckCircleOutlineIcon | |||
| color="success" | |||
| fontSize="small" | |||
| /> : | |||
| <HighlightOffIcon | |||
| color="error" | |||
| fontSize="small" | |||
| /> | |||
| } | |||
| }, | |||
| ], | |||
| [] | |||
| ); | |||
| const validation = useCallback( | |||
| ( | |||
| newRow: GridRowModel<BomMaterialRow> | |||
| ): BomMaterialEntryError | undefined => { | |||
| const error: BomMaterialEntryError = {}; | |||
| console.log(newRow); | |||
| return Object.keys(error).length > 0 ? error : undefined; | |||
| }, | |||
| [] | |||
| ); | |||
| const processRowUpdate = useCallback( | |||
| (newRow: GridRowModel<BomMaterialRow>, originalRow: GridRowModel<BomMaterialRow>) => { | |||
| const errors = validation(newRow); // change to validation | |||
| if (errors) { | |||
| throw new ProcessRowUpdateError( | |||
| originalRow, | |||
| "validation error", | |||
| errors | |||
| ); | |||
| } | |||
| const { _isNew, _error, ...updatedRow } = newRow; | |||
| const rowToSave = { | |||
| ...updatedRow, | |||
| } satisfies BomMaterialRow; | |||
| const newEntries = entries.map((e) => | |||
| getRowId(e) === getRowId(originalRow) ? rowToSave : e | |||
| ); | |||
| setEntries(newEntries); | |||
| //update remaining qty | |||
| const total = newEntries.reduce((acc, curr) => acc + (curr.acceptedQty || 0), 0); | |||
| return rowToSave; | |||
| }, | |||
| [getRowId, entries] | |||
| ); | |||
| const onProcessRowUpdateError = useCallback( | |||
| (updateError: ProcessRowUpdateError) => { | |||
| const errors = updateError.errors; | |||
| const oldRow = updateError.row; | |||
| apiRef.current.updateRows([{ ...oldRow, _error: errors }]); | |||
| }, | |||
| [apiRef] | |||
| ); | |||
| return ( | |||
| <> | |||
| <StyledDataGrid | |||
| getRowId={getRowId} | |||
| apiRef={apiRef} | |||
| autoHeight | |||
| sx={{ | |||
| "--DataGrid-overlayHeight": "100px", | |||
| ".MuiDataGrid-row .MuiDataGrid-cell.hasError": { | |||
| border: "1px solid", | |||
| borderColor: "error.main", | |||
| }, | |||
| ".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": { | |||
| border: "1px solid", | |||
| borderColor: "warning.main", | |||
| }, | |||
| }} | |||
| disableColumnMenu | |||
| editMode="row" | |||
| rows={entries} | |||
| rowModesModel={rowModesModel} | |||
| onRowModesModelChange={setRowModesModel} | |||
| processRowUpdate={processRowUpdate} | |||
| onProcessRowUpdateError={onProcessRowUpdateError} | |||
| columns={columns} | |||
| getCellClassName={(params: GridCellParams<BomMaterialRow>) => { | |||
| let classname = ""; | |||
| if (params.row._error) { | |||
| classname = "hasError"; | |||
| } | |||
| return classname; | |||
| }} | |||
| // slots={{ | |||
| // footer: FooterToolbar, | |||
| // noRowsOverlay: NoRowsOverlay, | |||
| // }} | |||
| // slotProps={{ | |||
| // footer: { child: footer }, | |||
| // }} | |||
| /> | |||
| </> | |||
| ); | |||
| } | |||
| const NoRowsOverlay: React.FC = () => { | |||
| const { t } = useTranslation("home"); | |||
| return ( | |||
| <Box | |||
| display="flex" | |||
| justifyContent="center" | |||
| alignItems="center" | |||
| height="100%" | |||
| > | |||
| <Typography variant="caption">{t("Add some entries!")}</Typography> | |||
| </Box> | |||
| ); | |||
| }; | |||
| const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => { | |||
| return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>; | |||
| }; | |||
| export default BomMaterialTable; | |||
| @@ -0,0 +1,334 @@ | |||
| "use client"; | |||
| import React, { CSSProperties, DetailedHTMLProps, HTMLAttributes, useEffect, useState } from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import Table from "@mui/material/Table"; | |||
| import TableBody from "@mui/material/TableBody"; | |||
| import TableCell from "@mui/material/TableCell"; | |||
| import TableContainer from "@mui/material/TableContainer"; | |||
| import TableHead from "@mui/material/TableHead"; | |||
| import TablePagination from "@mui/material/TablePagination"; | |||
| import TableRow from "@mui/material/TableRow"; | |||
| import IconButton from "@mui/material/IconButton"; | |||
| import EditIcon from "@mui/icons-material/Edit"; | |||
| import SaveIcon from "@mui/icons-material/Save"; | |||
| 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, Typography } from "@mui/material"; | |||
| import BomMaterialTable from "./BomMaterialTable"; | |||
| 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'; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { ProdScheduleLineBomMaterialResult, ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||
| export interface ResultWithId { | |||
| id: string | number; | |||
| // id: number; | |||
| } | |||
| interface BaseColumn<T extends ResultWithId> { | |||
| field: keyof T; | |||
| label: string; | |||
| type: string; | |||
| options?: T[]; | |||
| renderCell?: (params: T) => React.ReactNode; | |||
| style?: Partial<HTMLElement["style"]> & { [propName: string]: string } & CSSProperties; | |||
| } | |||
| interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { | |||
| onClick: (item: T) => void; | |||
| buttonIcon: React.ReactNode; | |||
| buttonColor?: "inherit" | "default" | "primary" | "secondary"; | |||
| } | |||
| export type Column<T extends ResultWithId> = | |||
| | BaseColumn<T> | |||
| | ColumnWithAction<T>; | |||
| interface Props<T extends ResultWithId> { | |||
| index?: number, | |||
| items: T[], | |||
| columns: Column<T>[], | |||
| noWrapper?: boolean, | |||
| setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number }) => void, | |||
| pagingController: { pageNum: number; pageSize: number; totalCount: number }, | |||
| isAutoPaging: boolean, | |||
| isEdit: boolean, | |||
| isEditable: boolean, | |||
| hasCollapse: boolean, | |||
| type: ScheduleType | |||
| } | |||
| function ScheduleTable<T extends ResultWithId>({ | |||
| type, | |||
| index = 7, | |||
| items, | |||
| columns, | |||
| noWrapper, | |||
| pagingController, | |||
| setPagingController, | |||
| isAutoPaging = true, | |||
| isEdit = false, | |||
| isEditable = true, | |||
| hasCollapse = false, | |||
| }: Props<T>) { | |||
| const [page, setPage] = useState(0); | |||
| const [rowsPerPage, setRowsPerPage] = useState(10); | |||
| const [editingRowId, setEditingRowId] = useState<number | null>(null); | |||
| const [editedItems, setEditedItems] = useState<T[]>(items); | |||
| const { t } = useTranslation("schedule"); | |||
| useEffect(() => { | |||
| setEditedItems(items) | |||
| }, [items]) | |||
| const handleChangePage = (_event: unknown, newPage: number) => { | |||
| setPage(newPage); | |||
| if (setPagingController) { | |||
| setPagingController({ ...pagingController, pageNum: newPage + 1, index: (index ?? -1)}); | |||
| } | |||
| }; | |||
| const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
| setRowsPerPage(+event.target.value); | |||
| setPage(0); | |||
| if (setPagingController) { | |||
| setPagingController({ ...pagingController, pageSize: +event.target.value, pageNum: 1, index: index }); | |||
| } | |||
| }; | |||
| const handleEditClick = (id: number) => { | |||
| setEditingRowId(id); | |||
| }; | |||
| const handleSaveClick = (item: T) => { | |||
| setEditingRowId(null); | |||
| // Call API or any save logic here | |||
| setEditedItems((prev) => | |||
| prev.map((row) => (row.id === item.id ? { ...row } : row)) | |||
| ); | |||
| }; | |||
| const handleInputChange = (id: number, field: keyof T, value: string | number[]) => { | |||
| setEditedItems((prev) => | |||
| prev.map((item) => | |||
| item.id === id ? { ...item, [field]: value } : item | |||
| ) | |||
| ); | |||
| }; | |||
| const handleDeleteClick = (id: number) => { | |||
| // Implement delete logic here | |||
| setEditedItems((prev) => prev.filter(item => item.id !== id)); | |||
| }; | |||
| useEffect(() => { | |||
| console.log("[debug] isEdit in table", isEdit) | |||
| //TODO: switch all record to not in edit mode and save the changes | |||
| if (!isEdit) { | |||
| editedItems?.forEach(item => { | |||
| // Call save logic here | |||
| // console.log("Saving item:", item); | |||
| // Reset editing state if needed | |||
| }); | |||
| setEditingRowId(null); | |||
| } | |||
| }, [isEdit]) | |||
| function isRoughType( | |||
| type: ScheduleType | |||
| ): type is "rough" { | |||
| return type === "rough"; | |||
| } | |||
| function isDetailType( | |||
| type: ScheduleType | |||
| ): type is "detail" { | |||
| return type === "detail"; | |||
| } | |||
| function Row(props: { row: T }) { | |||
| const { row } = props; | |||
| const [open, setOpen] = useState(false); | |||
| // console.log(row) | |||
| return ( | |||
| <> | |||
| <TableRow hover tabIndex={-1} key={row.id}> | |||
| {isDetailType(type) && <TableCell> | |||
| <IconButton disabled={!isEdit}> | |||
| <PlayCircleOutlineIcon /> | |||
| </IconButton> | |||
| </TableCell>} | |||
| { | |||
| (isEditable || hasCollapse) && <TableCell> | |||
| {(editingRowId === row.id) ? ( | |||
| <> | |||
| { | |||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||
| <SaveIcon /> | |||
| </IconButton> | |||
| } | |||
| { | |||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||
| <CancelIcon /> | |||
| </IconButton> | |||
| } | |||
| { | |||
| hasCollapse && <IconButton | |||
| aria-label="expand row" | |||
| size="small" | |||
| onClick={() => setOpen(!open)} | |||
| > | |||
| {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
| <Typography>{t("View BoM")}</Typography> | |||
| </IconButton> | |||
| } | |||
| </> | |||
| ) : ( | |||
| <> | |||
| { | |||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} | |||
| onClick={() => handleEditClick(row.id as number)}> | |||
| <EditIcon /> | |||
| </IconButton> | |||
| } | |||
| { | |||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} | |||
| onClick={() => handleDeleteClick(row.id as number)}> | |||
| <DeleteIcon /> | |||
| </IconButton> | |||
| } | |||
| { | |||
| hasCollapse && <IconButton | |||
| aria-label="expand row" | |||
| size="small" | |||
| onClick={() => setOpen(!open)} | |||
| > | |||
| {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
| <Typography>{t("View BoM")}</Typography> | |||
| </IconButton> | |||
| } | |||
| </> | |||
| )} | |||
| </TableCell> | |||
| } | |||
| {columns.map((column, idx) => { | |||
| const columnName = column.field; | |||
| return ( | |||
| <TableCell key={`${columnName.toString()}-${idx}`}> | |||
| {editingRowId === row.id ? ( | |||
| (() => { | |||
| switch (column.type) { | |||
| case 'input': | |||
| return ( | |||
| <TextField | |||
| hiddenLabel={true} | |||
| fullWidth | |||
| defaultValue={row[columnName] as string} | |||
| onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)} | |||
| /> | |||
| ); | |||
| // case 'multi-select': | |||
| // //TODO: May need update if use | |||
| // return ( | |||
| // <MultiSelect | |||
| // //label={column.label} | |||
| // options={column.options ?? []} | |||
| // selectedValues={[]} | |||
| // onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)} | |||
| // /> | |||
| // ); | |||
| case 'read-only': | |||
| return ( | |||
| <span> | |||
| {row[columnName] as string} | |||
| </span> | |||
| ); | |||
| default: | |||
| return null; // Handle any default case if needed | |||
| } | |||
| })() | |||
| ) : ( | |||
| column.renderCell ? | |||
| <div style={column.style}> | |||
| {column.renderCell(row)} | |||
| </div> | |||
| : | |||
| <div style={column.style}> | |||
| <span onDoubleClick={() => isEdit && handleEditClick(row.id as number)}> | |||
| {row[columnName] as String} | |||
| </span> | |||
| </div> | |||
| )} | |||
| </TableCell> | |||
| ); | |||
| })} | |||
| </TableRow> | |||
| <TableRow> | |||
| { | |||
| hasCollapse && | |||
| <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}> | |||
| <Collapse in={open} timeout="auto" unmountOnExit> | |||
| <Table> | |||
| <TableBody> | |||
| <TableRow> | |||
| <TableCell> | |||
| <BomMaterialTable | |||
| type={type} | |||
| bomMaterial={(row as unknown as ProdScheduleLineResultByFg).bomMaterials} | |||
| /> | |||
| </TableCell> | |||
| </TableRow> | |||
| </TableBody> | |||
| </Table> | |||
| </Collapse> | |||
| </TableCell> | |||
| } | |||
| </TableRow> | |||
| </> | |||
| ) | |||
| } | |||
| const table = ( | |||
| <> | |||
| <TableContainer sx={{ maxHeight: 440 }}> | |||
| <Table stickyHeader> | |||
| <TableHead> | |||
| <TableRow> | |||
| {isDetailType(type) && <TableCell>{t("Release")}</TableCell>} | |||
| {(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */} | |||
| {columns.map((column, idx) => ( | |||
| <TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | |||
| {column.label} | |||
| </TableCell> | |||
| ))} | |||
| </TableRow> | |||
| </TableHead> | |||
| <TableBody> | |||
| {/* {(isAutoPaging ? editedItems.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) : editedItems).map((item) => ( */} | |||
| {(editedItems?.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage))?.map((item) => ( | |||
| <Row key={item.id} row={item} /> | |||
| ))} | |||
| </TableBody> | |||
| </Table> | |||
| </TableContainer> | |||
| <TablePagination | |||
| rowsPerPageOptions={[10, 25, 100]} | |||
| component="div" | |||
| // count={pagingController.totalCount === 0 ? editedItems.length : pagingController.totalCount} | |||
| count={editedItems?.length ?? 0} | |||
| rowsPerPage={rowsPerPage} | |||
| page={page} | |||
| onPageChange={handleChangePage} | |||
| onRowsPerPageChange={handleChangeRowsPerPage} | |||
| /> | |||
| </> | |||
| ); | |||
| return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>; | |||
| } | |||
| export default ScheduleTable; | |||
| @@ -0,0 +1 @@ | |||
| export { default } from "./ScheduleTable" | |||
| @@ -24,20 +24,20 @@ | |||
| "Product Count": "產品數量", | |||
| "Scheduled At": "排程時間", | |||
| "Demand Forecast Period": "需求預測期間", | |||
| "FG & Material Demand Forecast Detail": "FG 及材料需求預測詳情", | |||
| "FG & Material Demand Forecast": "FG 及材料需求預測", | |||
| "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情", | |||
| "FG & Material Demand Forecast": "成品及物料需求預測", | |||
| "Total Estimated Demand Qty": "總預估需求量", | |||
| "View By FG": "依 FG 分類", | |||
| "View By Material": "依材料分類", | |||
| "View By FG": "依成品分類", | |||
| "View By Material": "依物料分類", | |||
| " (Selected)": " (已選擇)", | |||
| "Total FG Item": "總 FG 項目", | |||
| "Total FG Item": "總成品項目", | |||
| "Release": "發佈", | |||
| "Actions": "動作", | |||
| "FG Demand List (7 Days)": "FG 需求列表(7 天)", | |||
| "FG Demand Date": "FG 需求日期", | |||
| "FG Demand Qty": "FG 需求數量", | |||
| "Material Demand Date": "材料需求日期", | |||
| "Material Demand List": "材料需求列表", | |||
| "FG Demand List (7 Days)": "成品需求列表(7 天)", | |||
| "FG Demand Date": "成品需求日期", | |||
| "FG Demand Qty": "成品需求數量", | |||
| "Material Demand Date": "物料需求日期", | |||
| "Material Demand List": "物料需求列表", | |||
| "Available Qty": "可用數量", | |||
| "Demand Qty": "需求數量", | |||
| "Confirm": "確認", | |||
| @@ -50,7 +50,7 @@ | |||
| "Selected": "已選擇", | |||
| "Unselected": "未選擇", | |||
| "status": "狀態", | |||
| "Material Demand List (7 Days)": "材料需求列表(7 天)", | |||
| "Material Demand List (7 Days)": "物料需求列表(7 天)", | |||
| "Mon": "週一", | |||
| "Tue": "週二", | |||
| "Wed": "週三", | |||
| @@ -59,14 +59,15 @@ | |||
| "Sat": "週六", | |||
| "Sun": "週日", | |||
| "Last Month Average Stock": "上個月平均庫存", | |||
| "Last Month Average Sales": "上個月平均銷售", | |||
| "Safety Stock": "安全庫存", | |||
| "Demand Qty (7 Days)": "需求數量(7 天)", | |||
| "Estimated Production Time": "預估生產時間", | |||
| "Production Priority": "生產優先順序", | |||
| "View BoM": "查看 BoM", | |||
| "View BoM": "查看物料清單", | |||
| "Date": "日期", | |||
| "Detail Scheduling": "詳細排程", | |||
| "FG Production Schedule": "FG 生產排程", | |||
| "FG Production Schedule": "成品生產排程", | |||
| "Production Date": "生產日期", | |||
| "Total Job Order": "總工單數量", | |||
| "Total Production Qty": "總生產數量", | |||
| @@ -76,6 +77,6 @@ | |||
| "Job Status": "工單狀態", | |||
| "Job Priority": "工單優先順序", | |||
| "Job Date": "工單日期", | |||
| "Job Qty": "工單數量" | |||
| "Job Qty": "工單數量", | |||
| "mat": "物料" | |||
| } | |||