diff --git a/src/app/(main)/dashboard/page.tsx b/src/app/(main)/dashboard/page.tsx index ac1db4a..d259047 100644 --- a/src/app/(main)/dashboard/page.tsx +++ b/src/app/(main)/dashboard/page.tsx @@ -4,6 +4,7 @@ import { Suspense } from "react"; import { getServerI18n } from "@/i18n"; import DashboardPage from "@/components/DashboardPage"; import { SearchParams } from "@/app/utils/fetchUtil"; +import { fetchEscalationLogsByUser } from "@/app/api/escalation"; export const metadata: Metadata = { title: "Dashboard", @@ -14,6 +15,8 @@ type Props = {} & SearchParams; const Dashboard: React.FC = async ({ searchParams }) => { const { t } = await getServerI18n("dashboard"); + fetchEscalationLogsByUser() + return ( }> diff --git a/src/app/(main)/layout.tsx b/src/app/(main)/layout.tsx index dc236bc..4144526 100644 --- a/src/app/(main)/layout.tsx +++ b/src/app/(main)/layout.tsx @@ -37,7 +37,7 @@ export default async function MainLayout({ return ( - + {/* */} <> @@ -62,7 +62,7 @@ export default async function MainLayout({ - + {/* */} ); diff --git a/src/app/(main)/po/edit/page.tsx b/src/app/(main)/po/edit/page.tsx index f701caf..04ea01a 100644 --- a/src/app/(main)/po/edit/page.tsx +++ b/src/app/(main)/po/edit/page.tsx @@ -1,3 +1,4 @@ +import { fetchEscalationCombo } from "@/app/api/user"; import { SearchParams } from "@/app/utils/fetchUtil"; import { TypeEnum } from "@/app/utils/typeEnum"; import CreateProductMaterial from "@/components/CreateItem"; @@ -22,6 +23,9 @@ const PoEdit: React.FC = async ({ searchParams }) => { if (!id) { notFound(); } + + fetchEscalationCombo() + return ( <> {/* {t("Create Material")} */} diff --git a/src/app/api/dashboard/actions.ts b/src/app/api/dashboard/actions.ts index da6d72d..bd0d240 100644 --- a/src/app/api/dashboard/actions.ts +++ b/src/app/api/dashboard/actions.ts @@ -30,9 +30,6 @@ export interface StockInLineEntry { acceptedQty: number; status?: string; expiryDate?: string; - productLotNo?: string; - receiptDate?: string; - dnDate?: string; } export interface PurchaseQcResult { diff --git a/src/app/api/dashboard/index.ts b/src/app/api/dashboard/index.ts index 2bbb799..efc661e 100644 --- a/src/app/api/dashboard/index.ts +++ b/src/app/api/dashboard/index.ts @@ -6,7 +6,7 @@ import { serverFetchJson } from "../../utils/fetchUtil"; import { BASE_API_URL } from "../../../config/api"; import { Uom } from "../settings/uom"; import { RecordsRes } from "../utils"; -import { IQCItems } from "@/components/DashboardPage/QC/SupervisorQcApproval"; +// import { IQCItems } from "@/components/DashboardPage/QC/SupervisorQcApproval"; export interface PoResult { id: number; @@ -84,7 +84,8 @@ export const fetchPoWithStockInLines = cache(async (id: number) => { }); export const fetchIqcLogByUser = cache(async () => { - return serverFetchJson(`${BASE_API_URL}/supervisionApprovalLog/stock-in`, { - next: { tags: ["qcLog"] }, - }); + // return serverFetchJson(`${BASE_API_URL}/supervisionApprovalLog/stock-in`, { + // next: { tags: ["qcLog"] }, + // }); + return undefined; }); diff --git a/src/app/api/escalation/index.ts b/src/app/api/escalation/index.ts new file mode 100644 index 0000000..5c0e7d4 --- /dev/null +++ b/src/app/api/escalation/index.ts @@ -0,0 +1,58 @@ +"server only" + +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 EscalationResult { + id: number; + handler?: string; + handlerDepartment?: string; + handlerName?: string; + handlerTitle?: string; + polId?: number; + poId?: number; + reason?: string; + handlerId?: number; + itemName?: string; + demandQty?: number; + acceptedQty?: number; + purchaseUomCode?: string; + purchaseUomDesc?: string; + stockUomCode?: string; + stockUomDesc?: string; + stockInLineId?: number; + stockOutLineId?: number; + qcFailCount?: number; + qcTotalCount?: number; + poCode?: string; + itemCode?: string; + dnDate?: number[]; + dnNo?: string; +} + +export const fetchEscalationLogsByStockInLines = cache(async(stockInLineIds: number[]) => { + const searchParams = convertObjToURLSearchParams({stockInLineIds: stockInLineIds}) + return serverFetchJson(`${BASE_API_URL}/escalationLog/stockInLines?${searchParams}`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + next: { + tags: ["escalationLogs"], + }, + }, + ); +}); + +export const fetchEscalationLogsByUser = cache(async() => { + return serverFetchJson(`${BASE_API_URL}/escalationLog/user`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + next: { + tags: ["escalationLogs"], + }, + }, + ); +}); \ No newline at end of file diff --git a/src/app/api/mailTemplate/actions.ts b/src/app/api/mailTemplate/actions.ts new file mode 100644 index 0000000..66a78f2 --- /dev/null +++ b/src/app/api/mailTemplate/actions.ts @@ -0,0 +1,17 @@ +"use server"; + +import { serverFetchBlob } from "@/app/utils/fetchUtil"; +import { BASE_API_URL } from "@/config/api"; +import { cache } from "react"; + +export const getMailTemplateForStockInLine = cache(async (stockInLineId: number) => { + console.log("stockInLineId", stockInLineId) + return serverFetchBlob(`${BASE_API_URL}/mailTemplates/getMailTemplateForStockInLine/${stockInLineId}`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + next: { + tags: ["mailTemplateForStockInLine"], + }, + }) +}) \ No newline at end of file diff --git a/src/app/api/pickOrder/actions.ts b/src/app/api/pickOrder/actions.ts index b3e3848..f05d6a5 100644 --- a/src/app/api/pickOrder/actions.ts +++ b/src/app/api/pickOrder/actions.ts @@ -144,47 +144,6 @@ export interface PickOrderLotDetailResponse { } -export interface AssignPickOrderInputs { - pickOrderIds: number[]; - assignTo: number; -} -export const newassignPickOrder = async (data: AssignPickOrderInputs) => { - const pickOrder = await serverFetchJson( - `${BASE_API_URL}/pickOrder/assign`, - { - method: "POST", - body: JSON.stringify(data), - headers: { "Content-Type": "application/json" }, - }, - ); - revalidateTag("pickorder"); - return pickOrder; -}; - -export const newreleasePickOrder = async (data: AssignPickOrderInputs) => { - const pickOrder = await serverFetchJson( - `${BASE_API_URL}/pickOrder/release`, - { - method: "POST", - body: JSON.stringify(data), - headers: { "Content-Type": "application/json" }, - }, - ); - revalidateTag("pickorder"); - return pickOrder; -}; -export const releaseAssignedPickOrders = async (data: AssignPickOrderInputs) => { - const pickOrder = await serverFetchJson( - `${BASE_API_URL}/pickOrder/release-assigned`, - { - method: "POST", - body: JSON.stringify(data), - headers: { "Content-Type": "application/json" }, - }, - ); - revalidateTag("pickorder"); - return pickOrder; -}; export const fetchAllPickOrderDetails = cache(async () => { return serverFetchJson( `${BASE_API_URL}/pickOrder/detail`, diff --git a/src/app/api/po/actions.ts b/src/app/api/po/actions.ts index bd6e972..a013ab4 100644 --- a/src/app/api/po/actions.ts +++ b/src/app/api/po/actions.ts @@ -31,13 +31,17 @@ export interface StockInLineEntry { acceptedQty: number; status?: string; expiryDate?: string; + productLotNo?: string; + receiptDate?: string; + dnDate?: string; } -export interface PurchaseQcResult { +export interface PurchaseQcResult{ qcItemId: number; - isPassed: boolean, + qcPassed: boolean; failQty: number; - remarks?: string + remarks?: string; + } export interface StockInInput { status: string; @@ -110,7 +114,7 @@ export const fetchStockInLineInfo = cache(async (stockInLineId: number) => { export const createStockInLine = async (data: StockInLineEntry) => { const stockInLine = await serverFetchJson< - PostStockInLineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/create`, { method: "POST", body: JSON.stringify(data), @@ -124,7 +128,7 @@ export const updateStockInLine = async ( data: StockInLineEntry & ModalFormInput, ) => { const stockInLine = await serverFetchJson< - PostStockInLineResponse + PostStockInLineResponse >(`${BASE_API_URL}/stockInLine/update`, { method: "POST", body: JSON.stringify(data), diff --git a/src/app/api/po/index.ts b/src/app/api/po/index.ts index a240005..8cff8fc 100644 --- a/src/app/api/po/index.ts +++ b/src/app/api/po/index.ts @@ -15,6 +15,11 @@ export interface PoResult { estimatedArrivalDate: string; completedDate: string; itemDetail?: string; + itemCode?: string; + itemName?: string; + itemQty?: string; + itemSumAcceptedQty?: string; + itemUom?: string; escalated: boolean; status: string; pol?: PurchaseOrderLine[]; @@ -49,7 +54,7 @@ export interface StockUomForPoLine { export interface StockInLine { id: number; - stockInId: number; + stockInId?: number; purchaseOrderId?: number; purchaseOrderLineId: number; itemId: number; @@ -58,22 +63,24 @@ export interface StockInLine { itemType: string; demandQty: number; acceptedQty: number; - qty: number; - processed: number; - price: number; - priceUnit: string; + qty?: number; + processed?: number; + price?: number; + priceUnit?: string; shelfLife?: number; receiptDate?: string; productionDate?: string; + productLotNo?: string; expiryDate?: string; status: string; - supplier: string; - lotNo: string; - poCode: string; - uom: Uom; + supplier?: string; + lotNo?: string; + poCode?: string; + uom?: Uom; defaultWarehouseId: number; // id for now - dnNo: string; - dnDate: number[]; + dnNo?: string; + dnDate?: number[]; + stockQty?: number; } export const fetchPoList = cache(async (queryParams?: Record) => { diff --git a/src/app/api/qc/index.ts b/src/app/api/qc/index.ts index 26094c6..a99d457 100644 --- a/src/app/api/qc/index.ts +++ b/src/app/api/qc/index.ts @@ -15,6 +15,16 @@ export interface QcItemWithChecks { description: string | undefined; } +export interface QcData { + id: number, + code: string, + name: string, + qcDescription: string, + qcPassed: boolean | undefined + failQty: number | undefined + remarks: string | undefined +} + export const fetchQcItemCheckList = cache(async () => { return serverFetchJson(`${BASE_API_URL}/qc/list`, { next: { tags: ["qc"] }, diff --git a/src/app/api/user/index.ts b/src/app/api/user/index.ts index 19396a7..9d50db2 100644 --- a/src/app/api/user/index.ts +++ b/src/app/api/user/index.ts @@ -31,6 +31,15 @@ export type passwordRule = { specialChar: boolean; }; +export interface EscalationCombo { + id: number; + value: number; + label: string; + name: string; + title: string; + department: string; +} + export const preloadUser = () => { fetchUser(); }; @@ -56,3 +65,9 @@ export const fetchPwRules = cache(async () => { next: { tags: ["pwRule"] }, }); }); + +export const fetchEscalationCombo = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/user/escalation-combo`, { + next: { tags: ["escalationCombo"]} + }) +}) diff --git a/src/app/utils/fetchUtil.ts b/src/app/utils/fetchUtil.ts index 3f01795..f9d82b5 100644 --- a/src/app/utils/fetchUtil.ts +++ b/src/app/utils/fetchUtil.ts @@ -3,6 +3,11 @@ import { getServerSession } from "next-auth"; import { headers } from "next/headers"; import { redirect } from "next/navigation"; +export interface BlobResponse { + filename: string; + blobValue: Uint8Array; +} + export interface Pageable { pageSize?: number; pageNum?: number; @@ -86,7 +91,7 @@ export async function serverFetchJson(...args: FetchParams) { } } -export async function serverFetchBlob(...args: FetchParams) { +export async function serverFetchBlob(...args: FetchParams) { const response = await serverFetch(...args); if (response.ok) { diff --git a/src/components/DashboardPage/DashboardPage.tsx b/src/components/DashboardPage/DashboardPage.tsx index 23c7a15..f631d12 100644 --- a/src/components/DashboardPage/DashboardPage.tsx +++ b/src/components/DashboardPage/DashboardPage.tsx @@ -14,13 +14,17 @@ import ApplicationCompletionChart from "./chart/ApplicationCompletionChart"; import OrderCompletionChart from "./chart/OrderCompletionChart"; import DashboardBox from "./Dashboardbox"; import CollapsibleCard from "./CollapsibleCard"; -import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval"; +// import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval"; +import { EscalationResult } from "@/app/api/escalation"; +import EscalationLogTable from "./escalation/EscalationLogTable"; type Props = { - iqc: IQCItems[] + // iqc: IQCItems[] | undefined + escalationLogs: EscalationResult[] }; const DashboardPage: React.FC = ({ - iqc + // iqc, + escalationLogs }) => { const { t } = useTranslation("dashboard"); const router = useRouter(); @@ -29,9 +33,9 @@ const DashboardPage: React.FC = ({ - + - + diff --git a/src/components/DashboardPage/DashboardWrapper.tsx b/src/components/DashboardPage/DashboardWrapper.tsx index 4b35ed1..234ba23 100644 --- a/src/components/DashboardPage/DashboardWrapper.tsx +++ b/src/components/DashboardPage/DashboardWrapper.tsx @@ -4,7 +4,8 @@ import DashboardPage from "./DashboardPage"; import { Typography } from "@mui/material"; import { I18nProvider, getServerI18n } from "@/i18n"; import DashboardLoading from "./DashboardLoading"; -import { fetchIqcLogByUser } from "@/app/api/dashboard"; +import { fetchEscalationLogsByUser } from "@/app/api/escalation"; +// import { fetchIqcLogByUser } from "@/app/api/dashboard"; // export type SessionWithAbilities = { // abilities: string[] @@ -23,16 +24,20 @@ const DashboardWrapper: React.FC & SubComponents = async ({ }) => { const { t } = await getServerI18n("dashboard"); // const session: SessionWithAbilities = await getServerSession(authOptions) - const [iqcLog] = await Promise.all([ - fetchIqcLogByUser() + // const [iqcLog] = await Promise.all([ + // fetchIqcLogByUser() + // ]) + + const [escalationLogs] = await Promise.all([ + fetchEscalationLogsByUser() ]) - console.log(iqcLog) return ( <> {t("Dashboard")} diff --git a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx b/src/components/DashboardPage/escalation/EscalationLogTable.tsx similarity index 52% rename from src/components/DashboardPage/QC/SupervisorQcApproval.tsx rename to src/components/DashboardPage/escalation/EscalationLogTable.tsx index 1611b7f..62f1040 100644 --- a/src/components/DashboardPage/QC/SupervisorQcApproval.tsx +++ b/src/components/DashboardPage/escalation/EscalationLogTable.tsx @@ -2,9 +2,13 @@ import { Box, Card, CardActionArea, CardContent, CardHeader, Grid, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material"; import { useRouter } from "next/navigation"; -import { useCallback, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { usePathname } from "next/navigation"; import { useTranslation } from "react-i18next"; +import { EscalationResult } from "@/app/api/escalation"; +import { Column } from "@/components/SearchResults"; +import SearchResults from "@/components/SearchResults/SearchResults"; +import { arrayToDateString } from "@/app/utils/formatUtil"; export type IQCItems = { id: number; @@ -18,11 +22,11 @@ export type IQCItems = { }; type Props = { - items: IQCItems[]; + items: EscalationResult[]; }; -const SupervisorQcApproval: React.FC = ({ - items +const EscalationLogTable: React.FC = ({ + items }) => { const { t } = useTranslation("dashboard"); const CARD_HEADER = t("stock in escalation list") @@ -31,8 +35,8 @@ const SupervisorQcApproval: React.FC = ({ const router = useRouter(); const [selectedId, setSelectedId] = useState(null); -const navigateTo = useCallback( - (item: IQCItems) => { + const navigateTo = useCallback( + (item: EscalationResult) => { setSelectedId(item.id); console.log(pathname) router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`); @@ -40,17 +44,62 @@ const navigateTo = useCallback( [router, pathname] ); - const handleKeyDown = useCallback( - (e: React.KeyboardEvent, item: IQCItems) => { - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - navigateTo(item); - } - }, - [navigateTo] - ); + const onRowClick = useCallback((item: EscalationResult) => { + router.push(`/po/edit?id=${item.poId}&selectedIds=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`); + }, [router]) + + // const handleKeyDown = useCallback( + // (e: React.KeyboardEvent, item: EscalationResult) => { + // if (e.key === 'Enter' || e.key === ' ') { + // e.preventDefault(); + // navigateTo(item); + // } + // }, + // [navigateTo] + // ); - return ( + const columns = useMemo[]>( + () => [ + { + name: "handler", + label: t("Responsible for handling colleagues") + }, + { + name: "acceptedQty", + label: t("Received Qty"), + align: "right", + headerAlign: "right" + }, + { + name: "purchaseUomDesc", + label: t("Purchase UoM") + }, + { + name: "dnDate", + label: t("DN Date"), + renderCell: (params) => { + return params.dnDate ? arrayToDateString(params.dnDate) : "N/A" + } + }, + { + name: "qcTotalCount", + label: t("QC Completed Count"), + align: "right", + headerAlign: "right" + }, + { + name: "qcFailCount", + label: t("QC Fail Count"), + align: "right", + headerAlign: "right" + }, + { + name: "reason", + label: t("Reason"), + }, + ], []) + + {/* return ( @@ -87,7 +136,15 @@ const navigateTo = useCallback(
- ); - }; + );*/} + return ( + + ) +}; -export default SupervisorQcApproval; +export default EscalationLogTable; diff --git a/src/components/General/LoadingComponent.tsx b/src/components/General/LoadingComponent.tsx new file mode 100644 index 0000000..fc802b2 --- /dev/null +++ b/src/components/General/LoadingComponent.tsx @@ -0,0 +1,19 @@ +import {Box, CircularProgress, Grid} from "@mui/material"; + +export const LoadingComponent: React.FC = () => { + return ( + <> + + + + + + + ) +} +export default LoadingComponent; diff --git a/src/components/InputDataGrid/InputDataGrid.tsx b/src/components/InputDataGrid/InputDataGrid.tsx index 210fb6a..b4e9062 100644 --- a/src/components/InputDataGrid/InputDataGrid.tsx +++ b/src/components/InputDataGrid/InputDataGrid.tsx @@ -84,6 +84,7 @@ export interface SelectionInputDataGridProps { columns: GridColDef[]; validateRow: (newRow: GridRowModel>) => E; needAdd?: boolean; + showRemoveBtn?: boolean; } export type Props = diff --git a/src/components/PickOrderSearch/QcFormVer2.tsx b/src/components/PickOrderSearch/QcFormVer2.tsx index 9c615a2..ebea29d 100644 --- a/src/components/PickOrderSearch/QcFormVer2.tsx +++ b/src/components/PickOrderSearch/QcFormVer2.tsx @@ -49,7 +49,7 @@ import EscalationComponent from "./EscalationComponent"; import QcDataGrid from "./QCDatagrid"; import StockInFormVer2 from "./StockInFormVer2"; import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; -import { ModalFormInput } from "@/app/api/dashboard/actions"; +import { ModalFormInput } from "@/app/api/po/actions"; import { escape } from "lodash"; interface Props { diff --git a/src/components/PoDetail/EscalationComponent.tsx b/src/components/PoDetail/EscalationComponent.tsx index 12e0b81..5337eab 100644 --- a/src/components/PoDetail/EscalationComponent.tsx +++ b/src/components/PoDetail/EscalationComponent.tsx @@ -83,10 +83,18 @@ const EscalationComponent: React.FC = ({ return ( // <> - + {/* */} - + 上報結果 + {/* {isCollapsed ? ( + + ) : ( + + )} */} + + {/* = ({ )} } - /> + /> */} - {forSupervisor ? ( - - - } label="合格" /> - } label="不合格" /> - - - ): undefined} - + + } label="合格" /> + } label="不合格" /> + + + ): undefined} + {forSupervisor && ()} + {/* = ({ onChange={handleInputChange} InputProps={{ inputProps: { min: 1 } }} placeholder="請輸入數量" - /> + /> */} - + {/* - + */} diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index 2c59d5f..fdf737d 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -43,9 +43,11 @@ import { import { checkPolAndCompletePo, fetchPoInClient, + fetchPoListClient, fetchStockInLineInfo, PurchaseQcResult, startPo, + createStockInLine } from "@/app/api/po/actions"; import { useCallback, @@ -66,21 +68,20 @@ import PoQcStockInModal from "./PoQcStockInModal"; import QrModal from "./QrModal"; import { PlayArrow } from "@mui/icons-material"; import DoneIcon from "@mui/icons-material/Done"; -import { getCustomWidth } from "@/app/utils/commonUtil"; +import { downloadFile, getCustomWidth } from "@/app/utils/commonUtil"; import PoInfoCard from "./PoInfoCard"; import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; -import { fetchPoListClient } from "@/app/api/po/actions"; import { List, ListItem, ListItemButton, ListItemText, Divider } from "@mui/material"; -import { createStockInLine } from "@/app/api/dashboard/actions"; import { Controller, FormProvider, useForm } from "react-hook-form"; import dayjs, { Dayjs } from "dayjs"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { DatePicker, LocalizationProvider, zhHK } from "@mui/x-date-pickers"; import { debounce } from "lodash"; +import LoadingComponent from "../General/LoadingComponent"; +import { getMailTemplateForStockInLine } from "@/app/api/mailTemplate/actions"; //import { useRouter } from "next/navigation"; - type Props = { po: PoResult; qc: QcItemWithChecks[]; @@ -115,7 +116,7 @@ const PoSearchList: React.FC<{ return ( - {t("Purchase Orders")} + {t("Purchase Order")} - - {filteredPoList.map((poItem, index) => ( -
- - onSelect(poItem)} - sx={{ - width: '100%', - "&.Mui-selected": { - backgroundColor: "primary.light", - "&:hover": { + {(filteredPoList.length > 0)? ( + + {filteredPoList.map((poItem, index) => ( +
+ + onSelect(poItem)} + sx={{ + width: '100%', + "&.Mui-selected": { backgroundColor: "primary.light", + "&:hover": { + backgroundColor: "primary.light", + }, }, - }, - }} - > - - {poItem.code} - - } - secondary={ - - {t(`${poItem.status.toLowerCase()}`)} - - } - /> - - - {index < filteredPoList.length - 1 && } -
- ))} -
+ }} + > + + {poItem.code} + + } + secondary={ + + {t(`${poItem.status.toLowerCase()}`)} + + } + /> +
+
+ {index < filteredPoList.length - 1 && } +
+ ))} +
) : ( + + ) + } {searchTerm && ( - {t("Found")} {filteredPoList.length} {t("of")} {poList.length} {t("items")} + {`${t("Found")} ${filteredPoList.length} ${t("Purchase Order")}`} + {/* {`${t("Found")} ${filteredPoList.length} of ${poList.length} ${t("Item")}`} */} )}
@@ -184,7 +190,7 @@ interface PolInputResult { const PoDetail: React.FC = ({ po, qc, warehouse }) => { const cameras = useContext(CameraContext); - console.log(cameras); + // console.log(cameras); const { t } = useTranslation("purchaseOrder"); const apiRef = useGridApiRef(); const [purchaseOrder, setPurchaseOrder] = useState({ ...po }); @@ -205,6 +211,12 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { const searchParams = useSearchParams(); const [selectedRow, setSelectedRow] = useState(null); + const defaultPolId = searchParams.get("polId") + useEffect(() => { + if (defaultPolId) { + setSelectedRow(rows.find((r) => r.id.toString() === defaultPolId) ?? null) + } + }, []) const [stockInLine, setStockInLine] = useState([]); const [processedQty, setProcessedQty] = useState(0); @@ -212,6 +224,8 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { const router = useRouter(); const [poList, setPoList] = useState([]); const [selectedPoId, setSelectedPoId] = useState(po.id); + const [focusField, setFocusField] = useState(); + const currentPoId = searchParams.get('id'); const selectedIdsParam = searchParams.get('selectedIds'); // const [selectedRowId, setSelectedRowId] = useState(null); @@ -261,6 +275,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { setProcessedQty(result.pol[0].processed); } } + // if (focusField) {console.log(focusField);focusField.focus();} } } catch (error) { console.error("Failed to fetch PO detail:", error); @@ -319,6 +334,13 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { setPurchaseOrder(newPo); }, [purchaseOrder.id]); + const handleMailTemplateForStockInLine = useCallback(async (stockInLineId: number) => { + const response = await getMailTemplateForStockInLine(stockInLineId) + if (response) { + downloadFile(new Uint8Array(response.blobValue), response.filename); + } + }, []) + useEffect(() => { setRows(purchaseOrder.pol || []); }, [purchaseOrder]); @@ -388,6 +410,9 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { setTimeout(async () => { // post stock in line const oldId = row.id; + const acceptedQty = Number(polInputList[rowIndex].dnQty); + if (isNaN(acceptedQty) || acceptedQty <= 0) { alert("來貨數量必須大於0!"); return; } // Temp check, need update + const postData = { dnNo: dnFormProps.watch("dnNo"), dnDate: outputDateStringToInputDateString(dnFormProps.watch("dnDate")), @@ -396,7 +421,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { itemName: row.itemName, purchaseOrderId: row.purchaseOrderId, purchaseOrderLineId: row.id, - acceptedQty: polInputList[rowIndex].dnQty || 0, + acceptedQty: acceptedQty, productLotNo: polInputList[rowIndex].lotNo || '', // acceptedQty: secondReceiveQty || 0, // acceptedQty: row.acceptedQty, @@ -447,6 +472,10 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { } // setPolInputList(() => temp) }, 300), [rowIndex]); + + // const [focusField, setFocusField] = useState(); + + const purchaseToStockRatio = (row.stockUom.purchaseRatioN ?? 1) / (row.stockUom.purchaseRatioD ?? 1) * (row.stockUom.stockRatioD ?? 1) / (row.stockUom.stockRatioN ?? 1) return ( <> = ({ po, qc, warehouse }) => { {integerFormatter.format(row.qty)} {integerFormatter.format(processedQty)} {row.uom?.code} - {decimalFormatter.format(row.stockUom.stockQty)} + {/* {decimalFormatter.format(row.stockUom.stockQty)} */} + {decimalFormatter.format(row.stockInLine.filter((sil) => sil.purchaseOrderLineId === row.id).reduce((acc, cur) => acc + (cur.acceptedQty ?? 0),0) * purchaseToStockRatio)} {row.stockUom.stockUomCode} {/* {decimalFormatter.format(totalWeight)} {weightUnit} @@ -495,6 +525,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { variant="outlined" defaultValue={polInputList[rowIndex]?.lotNo ?? ''} onChange={handleChange} + // onFocus={(e) => {setFocusField(e.target as HTMLInputElement);}} /> @@ -520,7 +551,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { handleStart() } > - 提交 + {t("submit")} @@ -554,6 +585,8 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { ); } +// ROW END + const [tabIndex, setTabIndex] = useState(0); const handleTabChange = useCallback>( (_e, newValue) => { @@ -824,6 +857,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { itemDetail={selectedRow} warehouse={warehouse} fetchPoDetail={fetchPoDetail} + handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} /> diff --git a/src/components/PoDetail/PoDetailWrapper.tsx b/src/components/PoDetail/PoDetailWrapper.tsx index b5e6db6..3cc27c6 100644 --- a/src/components/PoDetail/PoDetailWrapper.tsx +++ b/src/components/PoDetail/PoDetailWrapper.tsx @@ -10,6 +10,7 @@ import PoDetail from "./PoDetail"; import { QcItemWithChecks } from "@/app/api/qc"; import { fetchWarehouseList } from "@/app/api/warehouse"; import { fetchQcItemCheck } from "@/app/api/qc/actions"; +import { fetchEscalationCombo } from "@/app/api/user"; interface SubComponents { Loading: typeof PoDetailLoading; @@ -20,10 +21,16 @@ type Props = { }; const PoDetailWrapper: React.FC & SubComponents = async ({ id }) => { - const [poWithStockInLine, warehouse, qc] = await Promise.all([ + const [ + poWithStockInLine, + warehouse, + qc, + escalationCombo + ] = await Promise.all([ fetchPoWithStockInLines(id), fetchWarehouseList(), fetchQcItemCheck(), + fetchEscalationCombo(), ]); // const poWithStockInLine = await fetchPoWithStockInLines(id) diff --git a/src/components/PoDetail/PoInfoCard.tsx b/src/components/PoDetail/PoInfoCard.tsx index 7081556..678a28e 100644 --- a/src/components/PoDetail/PoInfoCard.tsx +++ b/src/components/PoDetail/PoInfoCard.tsx @@ -19,7 +19,7 @@ type Props = { po: PoResult; }; -const PoInfoCard: React.FC = async ( +const PoInfoCard: React.FC = ( { // id po diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index c6221cb..88dcbc3 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -74,6 +74,7 @@ interface Props { stockInLine: StockInLine[]; warehouse: WarehouseResult[]; fetchPoDetail: (poId: string) => void; + handleMailTemplateForStockInLine: (stockInLineId: number) => void; } export type StockInLineEntryError = { @@ -112,7 +113,8 @@ function PoInputGrid({ itemDetail, stockInLine, warehouse, - fetchPoDetail + fetchPoDetail, + handleMailTemplateForStockInLine }: Props) { console.log(itemDetail); const { t } = useTranslation("purchaseOrder"); @@ -270,6 +272,7 @@ function PoInputGrid({ const [newOpen, setNewOpen] = useState(false); const stockInLineId = searchParams.get("stockInLineId"); + const poLineId = searchParams.get("poLineId"); const closeNewModal = useCallback(() => { const newParams = new URLSearchParams(searchParams.toString()); newParams.delete("stockInLineId"); // Remove the parameter @@ -282,46 +285,51 @@ const closeNewModal = useCallback(() => { // Open modal const openNewModal = useCallback(() => { - setNewOpen(true); + setNewOpen(() => true); }, []); // Button handler to update the URL and open the modal const handleNewQC = useCallback( - (id: GridRowId, params: any) => async () => { + (id: GridRowId, params: any) => async() => { // console.log(id) // console.log(params) - setBtnIsLoading(true); + // setBtnIsLoading(true); setRowModesModel((prev) => ({ ...prev, [id]: { mode: GridRowModes.View }, })); const qcResult = await fetchQcDefaultValue(id); - setModalInfo({ + setModalInfo(() => ({ ...params.row, qcResult: qcResult, receivedQty: itemDetail.receivedQty, - }); + })); setTimeout(() => { const newParams = new URLSearchParams(searchParams.toString()); newParams.set("stockInLineId", id.toString()); // Ensure `set` to avoid duplicates router.replace(`${pathname}?${newParams.toString()}`); - console.log("hello") + // console.log("hello") openNewModal() - setBtnIsLoading(false); + // setBtnIsLoading(false); }, 200); }, [fetchQcDefaultValue, openNewModal, pathname, router, searchParams] ); + // Open modal if `stockInLineId` exists in the URL + const [firstCheckForSil, setFirstCheckForSil] = useState(false) useEffect(() => { - if (stockInLineId) { - console.log("heeloo") - console.log(stockInLineId) - handleNewQC(stockInLineId, apiRef.current.getRow(stockInLineId)); + if (stockInLineId && itemDetail && !firstCheckForSil) { + // console.log("heeloo") + // console.log(stockInLineId) + // console.log(apiRef.current.getRow(stockInLineId)) + setFirstCheckForSil(true) + const fn = handleNewQC(stockInLineId, {row: apiRef.current.getRow(stockInLineId)}); + fn(); } - }, [stockInLineId, newOpen, handleNewQC, apiRef]); + }, [stockInLineId, poLineId, itemDetail]); const handleEscalation = useCallback( (id: GridRowId, params: any) => () => { // setBtnIsLoading(true); @@ -580,7 +588,7 @@ const closeNewModal = useCallback(() => { }} onClick={handleNewQC(params.row.id, params)} color="inherit" - key="edit" + key={`edit`} />, { variant="contained" color="primary" sx={{ width: '150px' }} - // onClick={formProps.handleSubmit(onSubmitEmailSupplier)} + onClick={() => handleMailTemplateForStockInLine(params.row.id as number)} > {t("email supplier")} } @@ -598,7 +606,7 @@ const closeNewModal = useCallback(() => { // color: "primary.main", // marginRight: 1, }} - onClick={handleNewQC(params.row.id, params)} + // onClick={handleNewQC(params.row.id, params)} color="inherit" key="edit" />, @@ -908,6 +916,7 @@ const closeNewModal = useCallback(() => { open={newOpen} onClose={closeNewModal} itemDetail={modalInfo} + handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} /> ) diff --git a/src/components/PoDetail/QcFormVer2.tsx b/src/components/PoDetail/QcFormVer2.tsx index 2fe055e..37667a9 100644 --- a/src/components/PoDetail/QcFormVer2.tsx +++ b/src/components/PoDetail/QcFormVer2.tsx @@ -41,20 +41,20 @@ import { GridEditInputCell } from "@mui/x-data-grid"; import { StockInLine } from "@/app/api/po"; import { stockInLineStatusMap } from "@/app/utils/formatUtil"; import { fetchQcItemCheck, fetchQcResult } from "@/app/api/qc/actions"; -import { QcItemWithChecks } from "@/app/api/qc"; +import { QcItemWithChecks, QcData } from "@/app/api/qc"; import axios from "@/app/(main)/axios/axiosInstance"; import { NEXT_PUBLIC_API_URL } from "@/config/api"; import axiosInstance from "@/app/(main)/axios/axiosInstance"; import EscalationComponent from "./EscalationComponent"; import QcDataGrid from "./QCDatagrid"; import StockInFormVer2 from "./StockInFormVer2"; -import { dummyEscalationHistory, dummyQCData, QcData } from "./dummyQcTemplate"; -import { ModalFormInput } from "@/app/api/dashboard/actions"; +import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate"; +import { ModalFormInput } from "@/app/api/po/actions"; import { escape } from "lodash"; import { PanoramaSharp } from "@mui/icons-material"; interface Props { - itemDetail: StockInLine; + itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] }; qc: QcItemWithChecks[]; disabled: boolean; qcItems: QcData[] @@ -88,8 +88,10 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI const [tabIndex, setTabIndex] = useState(0); const [rowSelectionModel, setRowSelectionModel] = useState(); const [escalationHistory, setEscalationHistory] = useState(dummyEscalationHistory); - const [qcResult, setQcResult] = useState(); + // const [qcResult, setQcResult] = useState(); const qcAccept = watch("qcAccept"); + const qcResult = watch("qcResult"); + console.log(qcResult); // const [qcAccept, setQcAccept] = useState(true); // const [qcItems, setQcItems] = useState(dummyQCData) @@ -184,43 +186,45 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI const qcColumns: GridColDef[] = [ { - field: "qcItem", + field: "code", headerName: t("qcItem"), flex: 2, renderCell: (params) => ( {params.value}
- {params.row.qcDescription}
+ {params.row.name}
), }, { - field: 'isPassed', + field: 'qcPassed', headerName: t("qcResult"), flex: 1.5, renderCell: (params) => { - const currentValue = params.value; + const currentValue = params.row; + console.log(currentValue.row); return ( { const value = e.target.value; setQcItems((prev) => - prev.map((r): QcData => (r.id === params.id ? { ...r, isPassed: value === "true" } : r)) + prev.map((r): QcData => (r.id === params.id ? { ...r, qcPassed: value === "true" } : r)) ); }} - name={`isPassed-${params.id}`} + name={`qcPassed-${params.id}`} > } label="合格" - disabled={itemDetail.status.toLowerCase() == "completed"} + disabled={disabled} sx={{ - color: currentValue === true ? "green" : "inherit", + color: currentValue.qcPassed === true ? "green" : "inherit", "& .Mui-checked": {color: "green"} }} /> @@ -228,9 +232,9 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI value="false" control={} label="不合格" - disabled={itemDetail.status.toLowerCase() == "completed"} + disabled={disabled} sx={{ - color: currentValue === false ? "red" : "inherit", + color: currentValue.qcPassed === false ? "red" : "inherit", "& .Mui-checked": {color: "red"} }} /> @@ -248,8 +252,8 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI { const v = e.target.value; const next = v === '' ? undefined : Number(v); @@ -257,6 +261,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI setQcItems((prev) => prev.map((r) => (r.id === params.id ? { ...r, failQty: next } : r)) ); + // setValue(`failQty`,failQty); }} onClick={(e) => e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} @@ -274,7 +279,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI { const remarks = e.target.value; // const next = v === '' ? undefined : Number(v); @@ -283,6 +288,9 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI prev.map((r) => (r.id === params.id ? { ...r, remarks: remarks } : r)) ); }} + // {...register(`qcResult.${params.row.rowIndex}.remarks`, { + // required: "remarks required!", + // })} onClick={(e) => e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()} @@ -293,11 +301,6 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI }, ] - useEffect(() => { - console.log(itemDetail); - - }, [itemDetail]); - // Set initial value for acceptQty useEffect(() => { if (itemDetail?.demandQty > 0) { //!== undefined) { @@ -308,10 +311,10 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI }, [itemDetail?.demandQty, itemDetail?.acceptedQty, setValue]); // const [openCollapse, setOpenCollapse] = useState(false) - const [isCollapsed, setIsCollapsed] = useState(false); + const [isCollapsed, setIsCollapsed] = useState(true); - const onFailedOpenCollapse = useCallback((qcItems: QcData[]) => { - const isFailed = qcItems.some((qc) => !qc.isPassed) + const onFailedOpenCollapse = useCallback((qcItems: PurchaseQcResult[]) => { + const isFailed = qcItems.some((qc) => !qc.qcPassed) console.log(isFailed) if (isFailed) { setIsCollapsed(true) @@ -327,10 +330,11 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI useEffect(() => { - console.log(itemDetail); + console.log("ItemDetail in QC:", itemDetail); }, [itemDetail]); + useEffect(() => { // onFailedOpenCollapse(qcItems) // This function is no longer needed }, [qcItems]); // Removed onFailedOpenCollapse from dependency array @@ -366,19 +370,10 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI /> */}
- - {!qcAccept && ( - - - )} )} {tabIndex == 1 && ( @@ -425,7 +420,7 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI field.onChange(value); }} > - } label="接受" /> = ({ qc, itemDetail, disabled, qcItems, setQcI sx={{ width: '150px' }} value={qcAccept? accQty : 0 } defaultValue={accQty} - disabled={!qcAccept || itemDetail.status.toLowerCase() == "completed"} + disabled={!qcAccept || disabled} {...register("acceptQty", { required: "acceptQty required!", })} @@ -442,15 +437,27 @@ const QcFormVer2: React.FC = ({ qc, itemDetail, disabled, qcItems, setQcI helperText={errors.acceptQty?.message} /> - } sx={{"& .Mui-checked": {color: "red"}}} - label="不接受及上報" /> + label="不接受" /> + } + sx={{"& .Mui-checked": {color: "blue"}}} + label="上報品檢結果" /> )} /> + {!qcAccept && ( + + + )} {/* {qcAccept && {t("Escalation Result")} diff --git a/src/components/PoDetail/QcStockInModalVer2.tsx b/src/components/PoDetail/QcStockInModalVer2.tsx index 0006b72..8451db6 100644 --- a/src/components/PoDetail/QcStockInModalVer2.tsx +++ b/src/components/PoDetail/QcStockInModalVer2.tsx @@ -1,7 +1,7 @@ "use client"; import { StockInLine } from "@/app/api/po"; -import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine } from "@/app/api/po/actions"; -import { QcItemWithChecks } from "@/app/api/qc"; +import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine, PurchaseQCInput } from "@/app/api/po/actions"; +import { QcItemWithChecks, QcData } from "@/app/api/qc"; import { Box, Button, @@ -19,10 +19,9 @@ import StockInForm from "./StockInForm"; import StockInFormVer2 from "./StockInFormVer2"; import QcFormVer2 from "./QcFormVer2"; import PutawayForm from "./PutawayForm"; -import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate"; +import { dummyPutawayLine, dummyQCData } from "./dummyQcTemplate"; import { useGridApiRef } from "@mui/x-data-grid"; import {submitDialogWithWarning} from "../Swal/CustomAlerts"; -import { PurchaseQCInput, PutawayInput } from "@/app/api/dashboard/actions"; import { arrayToDateString, arrayToInputDateString, dayjsToInputDateString } from "@/app/utils/formatUtil"; import dayjs from "dayjs"; @@ -36,7 +35,7 @@ const style = { px: 5, pb: 10, display: "block", - width: { xs: "60%", sm: "60%", md: "60%" }, + width: { xs: "90%", sm: "90%", md: "90%" }, // height: { xs: "60%", sm: "60%", md: "60%" }, }; interface CommonProps extends Omit { @@ -55,6 +54,7 @@ interface CommonProps extends Omit { qc?: QcItemWithChecks[]; warehouse?: any[]; // type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; + handleMailTemplateForStockInLine: (stockInLineId: number) => void; } interface Props extends CommonProps { itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] }; @@ -70,8 +70,8 @@ const PoQcStockInModalVer2: React.FC = ({ setItemDetail, qc, warehouse, + handleMailTemplateForStockInLine, }) => { - console.log(warehouse); const { t, i18n: { language }, @@ -113,6 +113,15 @@ const [qcItems, setQcItems] = useState(dummyQCData) setOpenPutaway(isPutaway); }, [open]) + + const [viewOnly, setViewOnly] = useState(false); + + useEffect(() => { + if (itemDetail && itemDetail.status) { + const isViewOnly = itemDetail.status.toLowerCase() == "completed" || itemDetail.status.toLowerCase() == "rejected" + setViewOnly(isViewOnly) + } + }, [itemDetail]); const [openPutaway, setOpenPutaway] = useState(false); const onOpenPutaway = useCallback(() => { @@ -155,21 +164,25 @@ const [qcItems, setQcItems] = useState(dummyQCData) // Get QC data from the shared form context const qcAccept = data.qcAccept; const acceptQty = data.acceptQty as number; + const qcResults = qcItems; + // const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems; // Validate QC data const validationErrors : string[] = []; // Check if all QC items have results - const itemsWithoutResult = qcItems.filter(item => item.isPassed === undefined); + const itemsWithoutResult = qcResults.filter(item => item.qcPassed === undefined); if (itemsWithoutResult.length > 0) { - validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.qcItem).join(', ')}`); + validationErrors.push(`${t("QC items without result")}`); + // validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(', ')}`); } // Check if failed items have failed quantity - const failedItemsWithoutQty = qcItems.filter(item => - item.isPassed === false && (!item.failQty || item.failQty <= 0) + const failedItemsWithoutQty = qcResults.filter(item => + item.qcPassed === false && (!item.failQty || item.failQty <= 0) ); if (failedItemsWithoutQty.length > 0) { - validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`); + validationErrors.push(`${t("Failed items must have failed quantity")}`); + // validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.code).join(', ')}`); } // Check if QC accept decision is made @@ -184,10 +197,16 @@ const [qcItems, setQcItems] = useState(dummyQCData) // Check if dates are input if (data.productionDate === undefined || data.productionDate == null) { - validationErrors.push("Production Date cannot be null!"); + validationErrors.push("請輸入生產日期!"); } if (data.expiryDate === undefined || data.expiryDate == null) { - validationErrors.push("Expiry Date cannot be null!"); + validationErrors.push("請輸入到期日!"); + } + if (!qcResults.every((qc) => qc.qcPassed) && qcAccept) { + validationErrors.push("有不合格檢查項目,無法收貨!"); + // submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?", + // confirmButtonText: t("confirm putaway"), html: ""}); + // return; } if (validationErrors.length > 0) { @@ -205,12 +224,12 @@ const [qcItems, setQcItems] = useState(dummyQCData) qcAccept: qcAccept? qcAccept : false, acceptQty: acceptQty? acceptQty : 0, - qcResult: qcItems.map(item => ({ + qcResult: qcResults.map(item => ({ qcItemId: item.id, - // qcItem: item.qcItem, + // code: item.code, // qcDescription: item.qcDescription, - isPassed: item.isPassed? item.isPassed : false, - failQty: (item.failQty && !item.isPassed) ? item.failQty : 0, + qcPassed: item.qcPassed? item.qcPassed : false, + failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0, // failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, remarks: item.remarks || '' })) @@ -218,42 +237,21 @@ const [qcItems, setQcItems] = useState(dummyQCData) // const qcData = data; console.log("QC Data for submission:", qcData); + + await postStockInLine(qcData); - if (!qcData.qcResult.every((qc) => qc.isPassed) && qcData.qcAccept) { - submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?", - confirmButtonText: t("confirm putaway"), html: ""}); - return; + if (qcData.qcAccept) { + // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", + // confirmButtonText: t("confirm putaway"), html: ""}); + onOpenPutaway(); + } else { + closeHandler({}, "backdropClick"); } - await postStockInLineWithQc(qcData); - // return; + return ; + }, [onOpenPutaway, qcItems], ); - - const postStockInLineWithQc = useCallback(async (qcData: PurchaseQCInput) => { - const args = { - ...qcData - // id: itemDetail.id, - // purchaseOrderId: itemDetail.purchaseOrderId, - // purchaseOrderLineId: itemDetail.purchaseOrderLineId, - // itemId: itemDetail.itemId, - // ...data, - // productionDate: productionDate, - // expiryDate: expiryDate, - // receiptDate: receiptDate, - } as ModalFormInput; - - await postStockInLine(args); - - if (qcData.qcAccept) { - // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", - // confirmButtonText: t("confirm putaway"), html: ""}); - onOpenPutaway(); - } else { - closeHandler({}, "backdropClick"); - } - return ; - },[onOpenPutaway,closeHandler]); const postStockInLine = useCallback(async (args: ModalFormInput) => { const submitData = { @@ -329,8 +327,8 @@ const [qcItems, setQcItems] = useState(dummyQCData) const acceptQty = formProps.watch("acceptedQty") - const checkQcIsPassed = useCallback((qcItems: QcData[]) => { - const isPassed = qcItems.every((qc) => qc.isPassed); + const checkQcIsPassed = useCallback((qcItems: PurchaseQcResult[]) => { + const isPassed = qcItems.every((qc) => qc.qcPassed); console.log(isPassed) if (isPassed) { formProps.setValue("passingQty", acceptQty) @@ -343,7 +341,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) useEffect(() => { // maybe check if submitted before console.log(qcItems) - checkQcIsPassed(qcItems) + // checkQcIsPassed(qcItems) }, [qcItems, checkQcIsPassed]) return ( @@ -368,7 +366,7 @@ const [qcItems, setQcItems] = useState(dummyQCData)