FPSMS-frontend
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

946 rindas
28 KiB

  1. "use client";
  2. import {
  3. FooterPropsOverrides,
  4. GridActionsCellItem,
  5. GridCellParams,
  6. GridRowId,
  7. GridRowIdGetter,
  8. GridRowModel,
  9. GridRowModes,
  10. GridRowModesModel,
  11. GridToolbarContainer,
  12. useGridApiRef,
  13. } from "@mui/x-data-grid";
  14. import {
  15. Dispatch,
  16. MutableRefObject,
  17. SetStateAction,
  18. useCallback,
  19. useEffect,
  20. useMemo,
  21. useState,
  22. } from "react";
  23. import StyledDataGrid from "../StyledDataGrid";
  24. import { GridColDef } from "@mui/x-data-grid";
  25. import { Box, Button, Grid, Typography } from "@mui/material";
  26. import { useTranslation } from "react-i18next";
  27. import { Add } from "@mui/icons-material";
  28. import SaveIcon from "@mui/icons-material/Save";
  29. import DeleteIcon from "@mui/icons-material/Delete";
  30. import CancelIcon from "@mui/icons-material/Cancel";
  31. import FactCheckIcon from "@mui/icons-material/FactCheck";
  32. import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
  33. import { QcItemWithChecks } from "src/app/api/qc";
  34. import PlayArrowIcon from "@mui/icons-material/PlayArrow";
  35. import { PurchaseOrderLine, StockInLine } from "@/app/api/po";
  36. import { createStockInLine, PurchaseQcResult } from "@/app/api/po/actions";
  37. import { usePathname, useRouter, useSearchParams } from "next/navigation";
  38. import {
  39. returnWeightUnit,
  40. calculateWeight,
  41. stockInLineStatusMap,
  42. } from "@/app/utils/formatUtil";
  43. // import PoQcStockInModal from "./PoQcStockInModal";
  44. import NotificationImportantIcon from "@mui/icons-material/NotificationImportant";
  45. import { WarehouseResult } from "@/app/api/warehouse";
  46. import LooksOneIcon from "@mui/icons-material/LooksOne";
  47. import LooksTwoIcon from "@mui/icons-material/LooksTwo";
  48. import Looks3Icon from "@mui/icons-material/Looks3";
  49. import axiosInstance from "@/app/(main)/axios/axiosInstance";
  50. // import axios, { AxiosRequestConfig } from "axios";
  51. import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api";
  52. import qs from "qs";
  53. import QrCodeIcon from "@mui/icons-material/QrCode";
  54. import { downloadFile } from "@/app/utils/commonUtil";
  55. import { fetchPoQrcode } from "@/app/api/pdf/actions";
  56. import { fetchQcResult } from "@/app/api/qc/actions";
  57. import PoQcStockInModal from "./PoQcStockInModal";
  58. import DoDisturbIcon from "@mui/icons-material/DoDisturb";
  59. import { useSession } from "next-auth/react";
  60. import PoQcStockInModalVer2 from "./QcStockInModalVer2";
  61. import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";
  62. interface ResultWithId {
  63. id: number;
  64. }
  65. interface Props {
  66. qc: QcItemWithChecks[];
  67. setRows: Dispatch<SetStateAction<PurchaseOrderLine[]>>;
  68. setStockInLine: Dispatch<SetStateAction<StockInLine[]>>;
  69. setProcessedQty: Dispatch<SetStateAction<number>>;
  70. itemDetail: PurchaseOrderLine;
  71. stockInLine: StockInLine[];
  72. warehouse: WarehouseResult[];
  73. }
  74. export type StockInLineEntryError = {
  75. [field in keyof StockInLine]?: string;
  76. };
  77. export type StockInLineRow = Partial<
  78. StockInLine & {
  79. isActive: boolean | undefined;
  80. _isNew: boolean;
  81. _error: StockInLineEntryError;
  82. } & ResultWithId
  83. >;
  84. class ProcessRowUpdateError extends Error {
  85. public readonly row: StockInLineRow;
  86. public readonly errors: StockInLineEntryError | undefined;
  87. constructor(
  88. row: StockInLineRow,
  89. message?: string,
  90. errors?: StockInLineEntryError,
  91. ) {
  92. super(message);
  93. this.row = row;
  94. this.errors = errors;
  95. Object.setPrototypeOf(this, ProcessRowUpdateError.prototype);
  96. }
  97. }
  98. function PoInputGrid({
  99. qc,
  100. setRows,
  101. setStockInLine,
  102. setProcessedQty,
  103. itemDetail,
  104. stockInLine,
  105. warehouse,
  106. }: Props) {
  107. console.log(itemDetail);
  108. const { t } = useTranslation("purchaseOrder");
  109. const apiRef = useGridApiRef();
  110. const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({});
  111. const getRowId = useCallback<GridRowIdGetter<StockInLineRow>>(
  112. (row) => row.id as number,
  113. [],
  114. );
  115. console.log(stockInLine);
  116. const [entries, setEntries] = useState<StockInLineRow[]>(stockInLine || []);
  117. useEffect(() => {
  118. setEntries(stockInLine)
  119. }, [stockInLine])
  120. const [modalInfo, setModalInfo] = useState<
  121. StockInLine & { qcResult?: PurchaseQcResult[] }
  122. >();
  123. const pathname = usePathname()
  124. const router = useRouter();
  125. const searchParams = useSearchParams();
  126. const [qcOpen, setQcOpen] = useState(false);
  127. const [escalOpen, setEscalOpen] = useState(false);
  128. const [stockInOpen, setStockInOpen] = useState(false);
  129. const [putAwayOpen, setPutAwayOpen] = useState(false);
  130. const [rejectOpen, setRejectOpen] = useState(false);
  131. const [btnIsLoading, setBtnIsLoading] = useState(false);
  132. const [currQty, setCurrQty] = useState(() => {
  133. const total = entries.reduce(
  134. (acc, curr) => acc + (curr.acceptedQty || 0),
  135. 0,
  136. );
  137. return total;
  138. });
  139. const { data: session } = useSession();
  140. useEffect(() => {
  141. const completedList = entries.filter(
  142. (e) => stockInLineStatusMap[e.status!] >= 8,
  143. );
  144. const processedQty = completedList.reduce(
  145. (acc, curr) => acc + (curr.acceptedQty || 0),
  146. 0,
  147. );
  148. setProcessedQty(processedQty);
  149. }, [entries, setProcessedQty]);
  150. const handleDelete = useCallback(
  151. (id: GridRowId) => () => {
  152. setEntries((es) => es.filter((e) => getRowId(e) !== id));
  153. },
  154. [getRowId],
  155. );
  156. const closeQcModal = useCallback(() => {
  157. setQcOpen(false);
  158. }, []);
  159. const openQcModal = useCallback(() => {
  160. setQcOpen(true);
  161. }, []);
  162. const closeStockInModal = useCallback(() => {
  163. setStockInOpen(false);
  164. }, []);
  165. const openStockInModal = useCallback(() => {
  166. setStockInOpen(true);
  167. }, []);
  168. const closePutAwayModal = useCallback(() => {
  169. setPutAwayOpen(false);
  170. }, []);
  171. const openPutAwayModal = useCallback(() => {
  172. setPutAwayOpen(true);
  173. }, []);
  174. const closeEscalationModal = useCallback(() => {
  175. setEscalOpen(false);
  176. }, []);
  177. const openEscalationModal = useCallback(() => {
  178. setEscalOpen(true);
  179. }, []);
  180. const closeRejectModal = useCallback(() => {
  181. setRejectOpen(false);
  182. }, []);
  183. const openRejectModal = useCallback(() => {
  184. setRejectOpen(true);
  185. }, []);
  186. const handleStart = useCallback(
  187. (id: GridRowId, params: any) => () => {
  188. setBtnIsLoading(true);
  189. setRowModesModel((prev) => ({
  190. ...prev,
  191. [id]: { mode: GridRowModes.View },
  192. }));
  193. setTimeout(async () => {
  194. // post stock in line
  195. const oldId = params.row.id;
  196. const postData = {
  197. itemId: params.row.itemId,
  198. itemNo: params.row.itemNo,
  199. itemName: params.row.itemName,
  200. purchaseOrderId: params.row.purchaseOrderId,
  201. purchaseOrderLineId: params.row.purchaseOrderLineId,
  202. acceptedQty: params.row.acceptedQty,
  203. };
  204. const res = await createStockInLine(postData);
  205. console.log(res);
  206. setEntries((prev) =>
  207. prev.map((p) => (p.id === oldId ? (res.entity as StockInLine) : p)),
  208. );
  209. setStockInLine(
  210. (prev) =>
  211. prev.map((p) =>
  212. p.id === oldId ? (res.entity as StockInLine) : p,
  213. ) as StockInLine[],
  214. );
  215. setBtnIsLoading(false);
  216. // do post directly to test
  217. // openStartModal();
  218. }, 200);
  219. },
  220. [setStockInLine],
  221. );
  222. const fetchQcDefaultValue = useCallback(async (stockInLineId: GridRowId) => {
  223. return await fetchQcResult(stockInLineId as number);
  224. }, []);
  225. const handleQC = useCallback(
  226. (id: GridRowId, params: any) => async () => {
  227. setBtnIsLoading(true);
  228. setRowModesModel((prev) => ({
  229. ...prev,
  230. [id]: { mode: GridRowModes.View },
  231. }));
  232. const qcResult = await fetchQcDefaultValue(id);
  233. console.log(params.row);
  234. console.log(qcResult);
  235. setModalInfo({
  236. ...params.row,
  237. qcResult: qcResult,
  238. });
  239. // set default values
  240. setTimeout(() => {
  241. // open qc modal
  242. console.log("delayed");
  243. openQcModal();
  244. setBtnIsLoading(false);
  245. }, 200);
  246. },
  247. [fetchQcDefaultValue, openQcModal],
  248. );
  249. const [newOpen, setNewOpen] = useState(false);
  250. const stockInLineId = searchParams.get("stockInLineId");
  251. const closeNewModal = useCallback(() => {
  252. const newParams = new URLSearchParams(searchParams.toString());
  253. newParams.delete("stockInLineId"); // Remove the parameter
  254. router.replace(`${pathname}?${newParams.toString()}`);
  255. setTimeout(() => {
  256. setNewOpen(false); // Close the modal first
  257. }, 300); // Add a delay to avoid immediate re-trigger of useEffect
  258. }, [searchParams, pathname, router]);
  259. // Open modal
  260. const openNewModal = useCallback(() => {
  261. setNewOpen(true);
  262. }, []);
  263. // Button handler to update the URL and open the modal
  264. const handleNewQC = useCallback(
  265. (id: GridRowId, params: any) => async () => {
  266. // console.log(id)
  267. // console.log(params)
  268. setBtnIsLoading(true);
  269. setRowModesModel((prev) => ({
  270. ...prev,
  271. [id]: { mode: GridRowModes.View },
  272. }));
  273. const qcResult = await fetchQcDefaultValue(id);
  274. setModalInfo({
  275. ...params.row,
  276. qcResult: qcResult,
  277. receivedQty: itemDetail.receivedQty,
  278. });
  279. setTimeout(() => {
  280. const newParams = new URLSearchParams(searchParams.toString());
  281. newParams.set("stockInLineId", id.toString()); // Ensure `set` to avoid duplicates
  282. router.replace(`${pathname}?${newParams.toString()}`);
  283. console.log("hello")
  284. openNewModal()
  285. setBtnIsLoading(false);
  286. }, 200);
  287. },
  288. [fetchQcDefaultValue, openNewModal, pathname, router, searchParams]
  289. );
  290. // Open modal if `stockInLineId` exists in the URL
  291. useEffect(() => {
  292. if (stockInLineId) {
  293. console.log("heeloo")
  294. console.log(stockInLineId)
  295. handleNewQC(stockInLineId, apiRef.current.getRow(stockInLineId));
  296. }
  297. }, [stockInLineId, newOpen, handleNewQC, apiRef]);
  298. const handleEscalation = useCallback(
  299. (id: GridRowId, params: any) => () => {
  300. // setBtnIsLoading(true);
  301. setRowModesModel((prev) => ({
  302. ...prev,
  303. [id]: { mode: GridRowModes.View },
  304. }));
  305. setModalInfo(params.row);
  306. setTimeout(() => {
  307. // open qc modal
  308. console.log("delayed");
  309. openEscalationModal();
  310. // setBtnIsLoading(false);
  311. }, 200);
  312. },
  313. [openEscalationModal],
  314. );
  315. const handleReject = useCallback(
  316. (id: GridRowId, params: any) => () => {
  317. setRowModesModel((prev) => ({
  318. ...prev,
  319. [id]: { mode: GridRowModes.View },
  320. }));
  321. setModalInfo(params.row);
  322. setTimeout(() => {
  323. // open stock in modal
  324. // openPutAwayModal();
  325. // return the record with its status as pending
  326. // update layout
  327. console.log("delayed");
  328. openRejectModal();
  329. // printQrcode(params.row);
  330. }, 200);
  331. },
  332. [openRejectModal],
  333. );
  334. const handleStockIn = useCallback(
  335. (id: GridRowId, params: any) => () => {
  336. // setBtnIsLoading(true);
  337. setRowModesModel((prev) => ({
  338. ...prev,
  339. [id]: { mode: GridRowModes.View },
  340. }));
  341. setModalInfo(params.row);
  342. setTimeout(() => {
  343. // open stock in modal
  344. openStockInModal();
  345. // return the record with its status as pending
  346. // update layout
  347. console.log("delayed");
  348. // setBtnIsLoading(false);
  349. }, 200);
  350. },
  351. [openStockInModal],
  352. );
  353. const handlePutAway = useCallback(
  354. (id: GridRowId, params: any) => () => {
  355. // setBtnIsLoading(true);
  356. setRowModesModel((prev) => ({
  357. ...prev,
  358. [id]: { mode: GridRowModes.View },
  359. }));
  360. setModalInfo(params.row);
  361. setTimeout(() => {
  362. // open stock in modal
  363. openPutAwayModal();
  364. // return the record with its status as pending
  365. // update layout
  366. console.log("delayed");
  367. // setBtnIsLoading(false);
  368. }, 200);
  369. },
  370. [openPutAwayModal],
  371. );
  372. const printQrcode = useCallback(
  373. async (row: any) => {
  374. setBtnIsLoading(true);
  375. console.log(row.id);
  376. const postData = { stockInLineIds: [row.id] };
  377. // const postData = { stockInLineIds: [42,43,44] };
  378. const response = await fetchPoQrcode(postData);
  379. if (response) {
  380. console.log(response);
  381. downloadFile(new Uint8Array(response.blobValue), response.filename!);
  382. }
  383. setBtnIsLoading(false);
  384. },
  385. [],
  386. );
  387. // const handleQrCode = useCallback(
  388. // (id: GridRowId, params: any) => () => {
  389. // setRowModesModel((prev) => ({
  390. // ...prev,
  391. // [id]: { mode: GridRowModes.View },
  392. // }));
  393. // setModalInfo(params.row);
  394. // setTimeout(() => {
  395. // // open stock in modal
  396. // // openPutAwayModal();
  397. // // return the record with its status as pending
  398. // // update layout
  399. // console.log("delayed");
  400. // printQrcode(params.row);
  401. // }, 200);
  402. // },
  403. // [printQrcode],
  404. // );
  405. const columns = useMemo<GridColDef[]>(
  406. () => [
  407. // {
  408. // field: "itemNo",
  409. // headerName: t("itemNo"),
  410. // width: 100,
  411. // // flex: 0.4,
  412. // },
  413. {
  414. field: "dnNo",
  415. headerName: t("dnNo"),
  416. width: 125,
  417. renderCell: () => {
  418. return <>DN0000001</>
  419. }
  420. // flex: 0.4,
  421. },
  422. {
  423. field: "dnDate",
  424. headerName: t("dnDate"),
  425. width: 125,
  426. renderCell: () => {
  427. return <>07/08/2025</>
  428. }
  429. // flex: 0.4,
  430. },
  431. // {
  432. // field: "itemName",
  433. // headerName: t("itemName"),
  434. // width: 100,
  435. // // flex: 0.6,
  436. // },
  437. {
  438. field: "acceptedQty",
  439. headerName: t("acceptedQty"),
  440. // flex: 0.5,
  441. width: 125,
  442. type: "number",
  443. // editable: true,
  444. // replace with tooltip + content
  445. renderCell: (params) => {
  446. return integerFormatter.format(params.value)
  447. }
  448. },
  449. {
  450. field: "uom",
  451. headerName: t("uom"),
  452. width: 120,
  453. // flex: 0.5,
  454. renderCell: (params) => {
  455. return params.row.uom.code;
  456. },
  457. },
  458. // {
  459. // field: "weight",
  460. // headerName: t("weight"),
  461. // width: 120,
  462. // // flex: 0.5,
  463. // renderCell: (params) => {
  464. // const weight = calculateWeight(
  465. // params.row.acceptedQty,
  466. // params.row.uom,
  467. // );
  468. // const weightUnit = returnWeightUnit(params.row.uom);
  469. // return `${decimalFormatter.format(weight)} ${weightUnit}`;
  470. // },
  471. // },
  472. {
  473. field: "status",
  474. headerName: t("Status"),
  475. width: 70,
  476. // flex: 0.5,
  477. renderCell: (params) => {
  478. return t(`${params.row.status}`);
  479. },
  480. },
  481. {
  482. field: "actions",
  483. type: "actions",
  484. // headerName: `${t("start")} | ${t("qc")} | ${t("escalation")} | ${t(
  485. // "stock in",
  486. // )} | ${t("putaway")} | ${t("delete")}`,
  487. headerName: "動作",
  488. // headerName: "start | qc | escalation | stock in | putaway | delete",
  489. width: 300,
  490. // flex: 2,
  491. cellClassName: "actions",
  492. getActions: (params) => {
  493. // console.log(params.row.status);
  494. const status = params.row.status.toLowerCase();
  495. // console.log(stockInLineStatusMap[status]);
  496. // console.log(session?.user?.abilities?.includes("APPROVAL"));
  497. return [
  498. <GridActionsCellItem
  499. icon={<Button variant="contained">{t("qc processing")}</Button>}
  500. label="start"
  501. sx={{
  502. color: "primary.main",
  503. // marginRight: 1,
  504. }}
  505. // disabled={!(stockInLineStatusMap[status] === 0)}
  506. // set _isNew to false after posting
  507. // or check status
  508. onClick={handleNewQC(params.row.id, params)}
  509. color="inherit"
  510. key="edit"
  511. />,
  512. <GridActionsCellItem
  513. icon={<Button variant="contained">{t("putawayBtn")}</Button>}
  514. label="start"
  515. sx={{
  516. color: "primary.main",
  517. // marginRight: 1,
  518. }}
  519. // disabled={!(stockInLineStatusMap[status] === 0)}
  520. // set _isNew to false after posting
  521. // or check status
  522. onClick={handleStart(params.row.id, params)}
  523. color="inherit"
  524. key="edit"
  525. />,
  526. // <GridActionsCellItem
  527. // icon={<Button variant="contained">{t("qc processing")}</Button>}
  528. // label="start"
  529. // sx={{
  530. // color: "primary.main",
  531. // // marginRight: 1,
  532. // }}
  533. // disabled={!(stockInLineStatusMap[status] === 0)}
  534. // // set _isNew to false after posting
  535. // // or check status
  536. // onClick={handleStart(params.row.id, params)}
  537. // color="inherit"
  538. // key="edit"
  539. // />,
  540. // <GridActionsCellItem
  541. // icon={<FactCheckIcon />}
  542. // label="qc"
  543. // sx={{
  544. // color: "primary.main",
  545. // // marginRight: 1,
  546. // }}
  547. // disabled={
  548. // // stockInLineStatusMap[status] === 9 ||
  549. // stockInLineStatusMap[status] < 1
  550. // }
  551. // // set _isNew to false after posting
  552. // // or check status
  553. // onClick={handleQC(params.row.id, params)}
  554. // color="inherit"
  555. // key="edit"
  556. // />,
  557. // <GridActionsCellItem
  558. // icon={<NotificationImportantIcon />}
  559. // label="escalation"
  560. // sx={{
  561. // color: "primary.main",
  562. // // marginRight: 1,
  563. // }}
  564. // disabled={
  565. // stockInLineStatusMap[status] === 9 ||
  566. // stockInLineStatusMap[status] <= 0 ||
  567. // stockInLineStatusMap[status] >= 5
  568. // }
  569. // // set _isNew to false after posting
  570. // // or check status
  571. // onClick={handleEscalation(params.row.id, params)}
  572. // color="inherit"
  573. // key="edit"
  574. // />,
  575. // <GridActionsCellItem
  576. // icon={<ShoppingCartIcon />}
  577. // label="stockin"
  578. // sx={{
  579. // color: "primary.main",
  580. // // marginRight: 1,
  581. // }}
  582. // disabled={
  583. // stockInLineStatusMap[status] === 9 ||
  584. // stockInLineStatusMap[status] <= 2 ||
  585. // stockInLineStatusMap[status] >= 7 ||
  586. // (stockInLineStatusMap[status] >= 3 &&
  587. // stockInLineStatusMap[status] <= 5 &&
  588. // !session?.user?.abilities?.includes("APPROVAL"))
  589. // }
  590. // // set _isNew to false after posting
  591. // // or check status
  592. // onClick={handleStockIn(params.row.id, params)}
  593. // color="inherit"
  594. // key="edit"
  595. // />,
  596. // <GridActionsCellItem
  597. // icon={<ShoppingCartIcon />}
  598. // label="putaway"
  599. // sx={{
  600. // color: "primary.main",
  601. // // marginRight: 1,
  602. // }}
  603. // disabled={
  604. // stockInLineStatusMap[status] === 9 ||
  605. // stockInLineStatusMap[status] < 7
  606. // }
  607. // // set _isNew to false after posting
  608. // // or check status
  609. // onClick={handlePutAway(params.row.id, params)}
  610. // color="inherit"
  611. // key="edit"
  612. // />,
  613. // // <GridActionsCellItem
  614. // // icon={<QrCodeIcon />}
  615. // // label="putaway"
  616. // // sx={{
  617. // // color: "primary.main",
  618. // // // marginRight: 1,
  619. // // }}
  620. // // disabled={stockInLineStatusMap[status] === 9 || stockInLineStatusMap[status] !== 8}
  621. // // // set _isNew to false after posting
  622. // // // or check status
  623. // // onClick={handleQrCode(params.row.id, params)}
  624. // // color="inherit"
  625. // // key="edit"
  626. // // />,
  627. // <GridActionsCellItem
  628. // icon={
  629. // stockInLineStatusMap[status] >= 1 ? (
  630. // <DoDisturbIcon />
  631. // ) : (
  632. // <DeleteIcon />
  633. // )
  634. // }
  635. // label="Delete"
  636. // sx={{
  637. // color: "error.main",
  638. // }}
  639. // disabled={
  640. // stockInLineStatusMap[status] >= 7 &&
  641. // stockInLineStatusMap[status] <= 9
  642. // }
  643. // onClick={
  644. // stockInLineStatusMap[status] === 0
  645. // ? handleDelete(params.row.id)
  646. // : handleReject(params.row.id, params)
  647. // }
  648. // color="inherit"
  649. // key="edit"
  650. // />,
  651. ];
  652. },
  653. },
  654. ],
  655. [t, handleStart, handleQC, handleEscalation, session?.user?.abilities, handleStockIn, handlePutAway, handleDelete, handleReject],
  656. );
  657. const addRow = useCallback(() => {
  658. console.log(itemDetail);
  659. const newEntry = {
  660. id: Date.now(),
  661. _isNew: true,
  662. itemId: itemDetail.itemId,
  663. purchaseOrderId: itemDetail.purchaseOrderId,
  664. purchaseOrderLineId: itemDetail.id,
  665. itemNo: itemDetail.itemNo,
  666. itemName: itemDetail.itemName,
  667. acceptedQty: itemDetail.qty - currQty, // this bug
  668. uom: itemDetail.uom,
  669. status: "draft",
  670. };
  671. setEntries((e) => [...e, newEntry]);
  672. setRowModesModel((model) => ({
  673. ...model,
  674. [getRowId(newEntry)]: {
  675. mode: GridRowModes.Edit,
  676. // fieldToFocus: "projectId",
  677. },
  678. }));
  679. }, [currQty, getRowId, itemDetail]);
  680. const validation = useCallback(
  681. (
  682. newRow: GridRowModel<StockInLineRow>,
  683. // rowModel: GridRowSelectionModel
  684. ): StockInLineEntryError | undefined => {
  685. const error: StockInLineEntryError = {};
  686. console.log(newRow);
  687. console.log(currQty);
  688. if (newRow.acceptedQty && newRow.acceptedQty > itemDetail.qty) {
  689. error["acceptedQty"] = t("qty cannot be greater than remaining qty");
  690. }
  691. return Object.keys(error).length > 0 ? error : undefined;
  692. },
  693. [currQty, itemDetail.qty, t],
  694. );
  695. const processRowUpdate = useCallback(
  696. (
  697. newRow: GridRowModel<StockInLineRow>,
  698. originalRow: GridRowModel<StockInLineRow>,
  699. ) => {
  700. const errors = validation(newRow); // change to validation
  701. if (errors) {
  702. throw new ProcessRowUpdateError(
  703. originalRow,
  704. "validation error",
  705. errors,
  706. );
  707. }
  708. const { _isNew, _error, ...updatedRow } = newRow;
  709. const rowToSave = {
  710. ...updatedRow,
  711. } satisfies StockInLineRow;
  712. const newEntries = entries.map((e) =>
  713. getRowId(e) === getRowId(originalRow) ? rowToSave : e,
  714. );
  715. setStockInLine(newEntries as StockInLine[]);
  716. console.log("triggered");
  717. setEntries(newEntries);
  718. //update remaining qty
  719. const total = newEntries.reduce(
  720. (acc, curr) => acc + (curr.acceptedQty || 0),
  721. 0,
  722. );
  723. setCurrQty(total);
  724. return rowToSave;
  725. },
  726. [validation, entries, setStockInLine, getRowId],
  727. );
  728. const onProcessRowUpdateError = useCallback(
  729. (updateError: ProcessRowUpdateError) => {
  730. const errors = updateError.errors;
  731. const oldRow = updateError.row;
  732. apiRef.current.updateRows([{ ...oldRow, _error: errors }]);
  733. },
  734. [apiRef],
  735. );
  736. const footer = (
  737. <>
  738. {/* <Box display="flex" gap={2} alignItems="center">
  739. <Button
  740. disableRipple
  741. variant="outlined"
  742. startIcon={<Add />}
  743. disabled={itemDetail.qty - currQty <= 0}
  744. onClick={addRow}
  745. size="small"
  746. >
  747. {t("Record pol")}
  748. </Button>
  749. </Box> */}
  750. </>
  751. );
  752. return (
  753. <>
  754. <StyledDataGrid
  755. getRowId={getRowId}
  756. apiRef={apiRef}
  757. autoHeight
  758. sx={{
  759. "--DataGrid-overlayHeight": "100px",
  760. ".MuiDataGrid-row .MuiDataGrid-cell.hasError": {
  761. border: "1px solid",
  762. borderColor: "error.main",
  763. },
  764. ".MuiDataGrid-row .MuiDataGrid-cell.hasWarning": {
  765. border: "1px solid",
  766. borderColor: "warning.main",
  767. },
  768. }}
  769. disableColumnMenu
  770. editMode="row"
  771. rows={entries}
  772. rowModesModel={rowModesModel}
  773. onRowModesModelChange={setRowModesModel}
  774. processRowUpdate={processRowUpdate}
  775. onProcessRowUpdateError={onProcessRowUpdateError}
  776. columns={columns}
  777. isCellEditable={(params) => {
  778. const status = params.row.status.toLowerCase();
  779. return (
  780. stockInLineStatusMap[status] >= 0 ||
  781. stockInLineStatusMap[status] <= 1
  782. );
  783. }}
  784. getCellClassName={(params: GridCellParams<StockInLineRow>) => {
  785. let classname = "";
  786. if (params.row._error) {
  787. classname = "hasError";
  788. }
  789. return classname;
  790. }}
  791. slots={{
  792. footer: FooterToolbar,
  793. noRowsOverlay: NoRowsOverlay,
  794. }}
  795. slotProps={{
  796. footer: { child: footer },
  797. }}
  798. />
  799. {modalInfo !== undefined && (
  800. <>
  801. <PoQcStockInModalVer2
  802. // setRows={setRows}
  803. setEntries={setEntries}
  804. setStockInLine={setStockInLine}
  805. setItemDetail={setModalInfo}
  806. qc={qc}
  807. warehouse={warehouse}
  808. open={newOpen}
  809. onClose={closeNewModal}
  810. itemDetail={modalInfo}
  811. />
  812. </>
  813. )
  814. }
  815. {modalInfo !== undefined && (
  816. <>
  817. <PoQcStockInModal
  818. type={"qc"}
  819. // setRows={setRows}
  820. setEntries={setEntries}
  821. setStockInLine={setStockInLine}
  822. setItemDetail={setModalInfo}
  823. qc={qc}
  824. open={qcOpen}
  825. onClose={closeQcModal}
  826. itemDetail={modalInfo}
  827. />
  828. </>
  829. )}
  830. {modalInfo !== undefined && (
  831. <>
  832. <PoQcStockInModal
  833. type={"escalation"}
  834. // setRows={setRows}
  835. setEntries={setEntries}
  836. setStockInLine={setStockInLine}
  837. setItemDetail={setModalInfo}
  838. // qc={qc}
  839. open={escalOpen}
  840. onClose={closeEscalationModal}
  841. itemDetail={modalInfo}
  842. />
  843. </>
  844. )}
  845. {modalInfo !== undefined && (
  846. <>
  847. <PoQcStockInModal
  848. type={"reject"}
  849. // setRows={setRows}
  850. setEntries={setEntries}
  851. setStockInLine={setStockInLine}
  852. setItemDetail={setModalInfo}
  853. // qc={qc}
  854. open={rejectOpen}
  855. onClose={closeRejectModal}
  856. itemDetail={modalInfo}
  857. />
  858. </>
  859. )}
  860. {modalInfo !== undefined && (
  861. <>
  862. <PoQcStockInModal
  863. type={"stockIn"}
  864. // setRows={setRows}
  865. setEntries={setEntries}
  866. setStockInLine={setStockInLine}
  867. // qc={qc}
  868. setItemDetail={setModalInfo}
  869. open={stockInOpen}
  870. onClose={closeStockInModal}
  871. itemDetail={modalInfo}
  872. />
  873. </>
  874. )}
  875. {modalInfo !== undefined && (
  876. <>
  877. <PoQcStockInModal
  878. type={"putaway"}
  879. // setRows={setRows}
  880. setEntries={setEntries}
  881. setStockInLine={setStockInLine}
  882. setItemDetail={setModalInfo}
  883. open={putAwayOpen}
  884. warehouse={warehouse}
  885. onClose={closePutAwayModal}
  886. itemDetail={modalInfo}
  887. />
  888. </>
  889. )}
  890. </>
  891. );
  892. }
  893. const NoRowsOverlay: React.FC = () => {
  894. const { t } = useTranslation("home");
  895. return (
  896. <Box
  897. display="flex"
  898. justifyContent="center"
  899. alignItems="center"
  900. height="100%"
  901. >
  902. <Typography variant="caption">{t("Add some entries!")}</Typography>
  903. </Box>
  904. );
  905. };
  906. const FooterToolbar: React.FC<FooterPropsOverrides> = ({ child }) => {
  907. return <GridToolbarContainer sx={{ p: 2 }}>{child}</GridToolbarContainer>;
  908. };
  909. export default PoInputGrid;