FPSMS-frontend
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

PoInputGrid.tsx 31 KiB

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