FPSMS-frontend
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

666 行
24 KiB

  1. "use client";
  2. import { QcItemWithChecks, QcData } from "@/app/api/qc";
  3. import {
  4. Autocomplete,
  5. Box,
  6. Button,
  7. Divider,
  8. Grid,
  9. Modal,
  10. ModalProps,
  11. Stack,
  12. Tab,
  13. Tabs,
  14. TabsProps,
  15. TextField,
  16. Typography,
  17. } from "@mui/material";
  18. import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
  19. import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form";
  20. import { StockInLineRow } from "./PoInputGrid";
  21. import { useTranslation } from "react-i18next";
  22. import StockInForm from "./StockInForm";
  23. import QcComponent from "./QcComponent";
  24. import { dummyPutAwayLine, dummyQCData } from "./dummyQcTemplate";
  25. import PutAwayForm from "./PutAwayForm";
  26. import { GridRowModes, GridRowSelectionModel, useGridApiRef } from "@mui/x-data-grid";
  27. import {msg, submitDialogWithWarning} from "../Swal/CustomAlerts";
  28. import { INPUT_DATE_FORMAT, arrayToDateString, dayjsToInputDateString } from "@/app/utils/formatUtil";
  29. import dayjs from "dayjs";
  30. import { fetchPoQrcode } from "@/app/api/pdf/actions";
  31. import { downloadFile } from "@/app/utils/commonUtil";
  32. import { PrinterCombo } from "@/app/api/settings/printer";
  33. import { EscalationResult } from "@/app/api/escalation";
  34. import { SessionWithTokens } from "@/config/authConfig";
  35. import { GridRowModesModel } from "@mui/x-data-grid";
  36. import { isEmpty } from "lodash";
  37. import { EscalationCombo } from "@/app/api/user";
  38. import { truncateSync } from "fs";
  39. import { ModalFormInput, StockInLineInput, StockInLine } from "@/app/api/stockIn";
  40. import { PurchaseQcResult, StockInLineEntry, updateStockInLine, printQrCodeForSil, PrintQrCodeForSilRequest } from "@/app/api/stockIn/actions";
  41. import { fetchStockInLineInfo } from "@/app/api/stockIn/actions";
  42. import { fetchQcResult } from "@/app/api/qc/actions";
  43. import { fetchEscalationLogsByStockInLines } from "@/app/api/escalation/actions";
  44. import LoadingComponent from "../General/LoadingComponent";
  45. const style = {
  46. position: "absolute",
  47. top: "50%",
  48. left: "50%",
  49. transform: "translate(-50%, -50%)",
  50. bgcolor: "background.paper",
  51. // pt: 5,
  52. // px: 5,
  53. // pb: 10,
  54. display: "block",
  55. width: { xs: "90%", sm: "90%", md: "90%" },
  56. height: { xs: "90%", sm: "90%", md: "90%" },
  57. };
  58. interface CommonProps extends Omit<ModalProps, "children"> {
  59. // itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] } | undefined;
  60. inputDetail: StockInLineInput | undefined;
  61. session: SessionWithTokens | null;
  62. warehouse?: any[];
  63. printerCombo: PrinterCombo[];
  64. onClose: () => void;
  65. }
  66. interface Props extends CommonProps {
  67. // itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] };
  68. }
  69. const PoQcStockInModalVer2: React.FC<Props> = ({
  70. open,
  71. onClose,
  72. // itemDetail,
  73. inputDetail,
  74. session,
  75. warehouse,
  76. printerCombo,
  77. }) => {
  78. const {
  79. t,
  80. i18n: { language },
  81. } = useTranslation("purchaseOrder");
  82. const [stockInLineInfo, setStockInLineInfo] = useState<StockInLine>();
  83. const [isLoading, setIsLoading] = useState<Boolean>(false);
  84. // const [viewOnly, setViewOnly] = useState(false);
  85. // Select Printer
  86. const [selectedPrinter, setSelectedPrinter] = useState(printerCombo[0]);
  87. const [printQty, setPrintQty] = useState(1);
  88. const [tabIndex, setTabIndex] = useState(0);
  89. const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
  90. (_e, newValue) => {
  91. setTabIndex(newValue);
  92. },
  93. [],
  94. );
  95. const fetchStockInLineData = useCallback(
  96. async (stockInLineId: number) => {
  97. try {
  98. const res = await fetchStockInLineInfo(stockInLineId);
  99. if (res) {
  100. console.log("%c Fetched Stock In Line: ", "color:orange", res);
  101. setStockInLineInfo({...inputDetail, ...res});
  102. fetchQcResultData(stockInLineId);
  103. } else throw("Result is undefined");
  104. } catch (e) {
  105. console.log("%c Error when fetching Stock In Line: ", "color:red", e);
  106. }
  107. },[fetchStockInLineInfo, inputDetail]
  108. );
  109. const fetchQcResultData = useCallback( // TODO: put this inside QC Component
  110. async (stockInLineId: number) => {
  111. try {
  112. const res = await fetchQcResult(stockInLineId);
  113. if (res.length > 0) {
  114. console.log("%c Fetched Qc Result: ", "color:orange", res);
  115. setStockInLineInfo((prev) => ({...prev, qcResult: res} as StockInLine));
  116. formProps.setValue("qcResult", res);
  117. fetchEscalationLogData(stockInLineId);
  118. } else {setStockInLineInfo((prev) => ({...prev, qcResult: []} as StockInLine));}
  119. // } else throw("Result is undefined");
  120. } catch (e) {
  121. console.log("%c Error when fetching Qc Result: ", "color:red", e);
  122. }
  123. },[fetchQcResult]
  124. );
  125. const fetchEscalationLogData = useCallback(
  126. async (stockInLineId: number) => {
  127. try {
  128. const res = await fetchEscalationLogsByStockInLines([stockInLineId]);
  129. if (res.length > 0) {
  130. console.log("%c Fetched Escalation Log: ", "color:orange", res[0]);
  131. setStockInLineInfo((prev) => ({...prev, escResult: res} as StockInLine));
  132. // formProps.setValue("escalationLog", res[0]);
  133. } else throw("Result is undefined");
  134. } catch (e) {
  135. console.log("%c Error when fetching EscalationLog: ", "color:red", e);
  136. }
  137. },[fetchEscalationLogsByStockInLines]
  138. );
  139. // Fetch info if id is input
  140. useEffect(() => {
  141. setIsLoading(true);
  142. if (inputDetail && open) {
  143. console.log("%c Opened Modal with input:", "color:yellow", inputDetail);
  144. if (inputDetail.id) {
  145. const id = inputDetail.id;
  146. fetchStockInLineData(id);
  147. }
  148. }
  149. }, [open]);
  150. // Make sure stock in line info is fetched
  151. useEffect(() => {
  152. if (stockInLineInfo) {
  153. if (stockInLineInfo.id) {
  154. if (isLoading) {
  155. formProps.reset({
  156. ...defaultNewValue
  157. });
  158. console.log("%c Modal loaded successfully", "color:lime");
  159. setIsLoading(false);
  160. }
  161. }
  162. }
  163. }, [stockInLineInfo]);
  164. const defaultNewValue = useMemo(() => {
  165. const d = stockInLineInfo;
  166. if (d !== undefined) {
  167. // console.log("%c sil info", "color:yellow", d )
  168. return (
  169. {
  170. ...d,
  171. // status: d.status ?? "pending",
  172. productionDate: d.productionDate ? arrayToDateString(d.productionDate, "input") : undefined,
  173. expiryDate: d.expiryDate ? arrayToDateString(d.expiryDate, "input") : undefined,
  174. receiptDate: d.receiptDate ? arrayToDateString(d.receiptDate, "input")
  175. : dayjs().add(0, "month").format(INPUT_DATE_FORMAT),
  176. acceptQty: d.demandQty?? d.acceptedQty,
  177. // escResult: (d.escResult && d.escResult?.length > 0) ? d.escResult : [],
  178. // qcResult: (d.qcResult && d.qcResult?.length > 0) ? d.qcResult : [],//[...dummyQCData],
  179. warehouseId: d.defaultWarehouseId ?? 1,
  180. putAwayLines: d.putAwayLines?.map((line) => ({...line, printQty: 1, _isNew: false, _disableDelete: true})) ?? [],
  181. } as ModalFormInput
  182. )
  183. } return undefined
  184. }, [stockInLineInfo])
  185. // const [qcItems, setQcItems] = useState(dummyQCData)
  186. const formProps = useForm<ModalFormInput>({
  187. defaultValues: {
  188. ...defaultNewValue,
  189. },
  190. });
  191. const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>(
  192. () => {
  193. setStockInLineInfo(undefined);
  194. formProps.reset({});
  195. onClose?.();
  196. },
  197. [onClose],
  198. );
  199. const isPutaway = () => {
  200. if (stockInLineInfo) {
  201. const status = stockInLineInfo.status;
  202. return status == "received";
  203. } else return false;
  204. };
  205. // Get show putaway
  206. const showPutaway = useMemo(() => {
  207. if (stockInLineInfo) {
  208. const status = stockInLineInfo.status;
  209. return status !== "pending" && status !== "escalated" && status !== "rejected";
  210. }
  211. return false;
  212. }, [stockInLineInfo]);
  213. // Get is view only
  214. const viewOnly = useMemo(() => {
  215. if (stockInLineInfo) {
  216. if (stockInLineInfo.status) {
  217. const status = stockInLineInfo.status;
  218. const isViewOnly = status.toLowerCase() == "completed"
  219. || status.toLowerCase() == "partially_completed" // TODO update DB
  220. || status.toLowerCase() == "rejected"
  221. || (status.toLowerCase() == "escalated" && session?.id != stockInLineInfo.handlerId)
  222. if (showPutaway) { setTabIndex(1); } else { setTabIndex(0); }
  223. return isViewOnly;
  224. }
  225. }
  226. return true;
  227. }, [stockInLineInfo])
  228. const [openPutaway, setOpenPutaway] = useState(false);
  229. const onOpenPutaway = useCallback(() => {
  230. setOpenPutaway(true);
  231. }, []);
  232. const onClosePutaway = useCallback(() => {
  233. setOpenPutaway(false);
  234. }, []);
  235. // Stock In submission handler
  236. const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>(
  237. async (data, event) => {
  238. console.log("Stock In Submission:", event!.nativeEvent);
  239. // Extract only stock-in related fields
  240. const stockInData = {
  241. // quantity: data.quantity,
  242. // receiptDate: data.receiptDate,
  243. // batchNumber: data.batchNumber,
  244. // expiryDate: data.expiryDate,
  245. // warehouseId: data.warehouseId,
  246. // location: data.location,
  247. // unitCost: data.unitCost,
  248. data: data,
  249. // Add other stock-in specific fields from your form
  250. };
  251. console.log("Stock In Data:", stockInData);
  252. // Handle stock-in submission logic here
  253. // e.g., call API, update state, etc.
  254. },
  255. [],
  256. );
  257. // QC submission handler
  258. const onSubmitErrorQc = useCallback<SubmitErrorHandler<ModalFormInput>>(
  259. async (data, event) => {
  260. console.log("Error", data);
  261. }, []
  262. );
  263. // QC submission handler
  264. const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>(
  265. async (data, event) => {
  266. console.log("QC Submission:", event!.nativeEvent);
  267. // TODO: Move validation into QC page
  268. // if (errors.length > 0) {
  269. // alert(`未完成品檢: ${errors.map((err) => err[1].message)}`);
  270. // return;
  271. // }
  272. // Get QC data from the shared form context
  273. const qcAccept = data.qcDecision == 1;
  274. // const qcAccept = data.qcAccept;
  275. let acceptQty = Number(data.acceptQty);
  276. const qcResults = data.qcResult?.filter((qc) => qc.escalationLogId === undefined) || []; // Remove old QC data
  277. // const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems;
  278. // const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems;
  279. // Validate QC data
  280. const validationErrors : string[] = [];
  281. // Check if failed items have failed quantity
  282. const failedItemsWithoutQty = qcResults.filter(item =>
  283. item.qcPassed === false && (!item.failQty || item.failQty <= 0)
  284. );
  285. if (failedItemsWithoutQty.length > 0) {
  286. validationErrors.push(`${t("Failed items must have failed quantity")}`);
  287. // validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.code).join(', ')}`);
  288. }
  289. // Check if QC accept decision is made
  290. if (data.qcDecision === undefined) {
  291. // if (qcAccept === undefined) {
  292. validationErrors.push(t("QC decision is required"));
  293. }
  294. // Check if accept quantity is valid
  295. if (data.qcDecision == 2) {
  296. acceptQty = 0;
  297. } else {
  298. if (acceptQty === undefined || acceptQty <= 0) {
  299. validationErrors.push("Accept quantity must be greater than 0");
  300. }
  301. }
  302. // Check if dates are input
  303. if (data.productionDate === undefined || data.productionDate == null) {
  304. alert("請輸入生產日期!");
  305. return;
  306. }
  307. if (data.expiryDate === undefined || data.expiryDate == null) {
  308. alert("請輸入到期日!");
  309. return;
  310. }
  311. if (!qcResults.every((qc) => qc.qcPassed) && qcAccept && stockInLineInfo?.status != "escalated") { //TODO: fix it please!
  312. validationErrors.push("有不合格檢查項目,無法收貨!");
  313. // submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?",
  314. // confirmButtonText: t("confirm putaway"), html: ""});
  315. // return;
  316. }
  317. // Check if all QC items have results
  318. const itemsWithoutResult = qcResults.filter(item => item.qcPassed === undefined);
  319. if (itemsWithoutResult.length > 0 && stockInLineInfo?.status != "escalated") { //TODO: fix it please!
  320. validationErrors.push(`${t("QC items without result")}`);
  321. // validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(', ')}`);
  322. }
  323. if (validationErrors.length > 0) {
  324. console.error("QC Validation failed:", validationErrors);
  325. alert(`未完成品檢: ${validationErrors}`);
  326. return;
  327. }
  328. const qcData = {
  329. dnNo : data.dnNo? data.dnNo : "DN00000",
  330. // dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()),
  331. productionDate : arrayToDateString(data.productionDate, "input"),
  332. expiryDate : arrayToDateString(data.expiryDate, "input"),
  333. receiptDate : arrayToDateString(data.receiptDate, "input"),
  334. qcAccept: qcAccept? qcAccept : false,
  335. acceptQty: acceptQty? acceptQty : 0,
  336. // qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({
  337. qcResult: qcResults.map(item => ({
  338. // id: item.id,
  339. qcItemId: item.qcItemId,
  340. // code: item.code,
  341. // qcDescription: item.qcDescription,
  342. qcPassed: item.qcPassed? item.qcPassed : false,
  343. failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0,
  344. // failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0,
  345. remarks: item.remarks || '',
  346. })),
  347. };
  348. // const qcData = data;
  349. console.log("QC Data for submission:", qcData);
  350. if (data.qcDecision == 3) { // Escalate
  351. if (data.escalationLog?.handlerId == undefined) { alert("請選擇上報負責同事!"); return; }
  352. else if (data.escalationLog?.handlerId < 1) { alert("上報負責同事資料有誤"); return; }
  353. const escalationLog = {
  354. type : "qc",
  355. status : "pending", // TODO: update with supervisor decision
  356. reason : data.escalationLog?.reason,
  357. recordDate : dayjsToInputDateString(dayjs()),
  358. handlerId : data.escalationLog?.handlerId,
  359. }
  360. console.log("Escalation Data for submission", escalationLog);
  361. await postStockInLine({...qcData, escalationLog});
  362. } else {
  363. await postStockInLine(qcData);
  364. }
  365. if (qcData.qcAccept) {
  366. // submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?",
  367. // confirmButtonText: t("confirm putaway"), html: ""});
  368. // onOpenPutaway();
  369. closeHandler({}, "backdropClick");
  370. // setTabIndex(1); // Need to go Putaway tab?
  371. } else {
  372. closeHandler({}, "backdropClick");
  373. }
  374. msg("已更新來貨狀態");
  375. return ;
  376. },
  377. [onOpenPutaway, formProps.formState.errors],
  378. );
  379. const postStockInLine = useCallback(async (args: ModalFormInput) => {
  380. const submitData = {
  381. ...stockInLineInfo, ...args
  382. } as StockInLineEntry & ModalFormInput;
  383. console.log("Submitting", submitData);
  384. const res = await updateStockInLine(submitData);
  385. return res;
  386. }, [stockInLineInfo])
  387. // Put away model
  388. const [pafRowModesModel, setPafRowModesModel] = useState<GridRowModesModel>({})
  389. const [pafRowSelectionModel, setPafRowSelectionModel] = useState<GridRowSelectionModel>([])
  390. const pafSubmitDisable = useMemo(() => {
  391. return Object.entries(pafRowModesModel).length > 0 || Object.entries(pafRowModesModel).some(([key, value], index) => value.mode === GridRowModes.Edit)
  392. }, [pafRowModesModel])
  393. // Putaway submission handler
  394. const onSubmitPutaway = useCallback<SubmitHandler<ModalFormInput>>(
  395. async (data, event) => {
  396. // Extract only putaway related fields
  397. const putawayData = {
  398. acceptQty: Number(data.acceptQty?? (stockInLineInfo?.demandQty?? (stockInLineInfo?.acceptedQty))), //TODO improve
  399. warehouseId: data.warehouseId,
  400. status: data.status, //TODO Fix it!
  401. // ...data,
  402. // dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()),
  403. productionDate : arrayToDateString(data.productionDate, "input"),
  404. expiryDate : arrayToDateString(data.expiryDate, "input"),
  405. receiptDate : arrayToDateString(data.receiptDate, "input"),
  406. // for putaway data
  407. inventoryLotLines: data.putAwayLines?.filter((line) => line._isNew !== false)
  408. // Add other putaway specific fields
  409. } as ModalFormInput;
  410. console.log("Putaway Data:", putawayData);
  411. console.log("DEBUG",data.putAwayLines);
  412. // if (data.putAwayLines!!.filter((line) => line._isNew !== false).length <= 0) {
  413. // alert("請新增上架資料!");
  414. // return;
  415. // }
  416. if (data.putAwayLines!!.filter((line) => /[^0-9]/.test(String(line.qty))).length > 0) { //TODO Improve
  417. alert("上架數量不正確!");
  418. return;
  419. }
  420. if (data.putAwayLines!!.reduce((acc, cur) => acc + Number(cur.qty), 0) > putawayData.acceptQty!!) {
  421. alert(`上架數量不能大於 ${putawayData.acceptQty}!`);
  422. return;
  423. }
  424. // Handle putaway submission logic here
  425. const res = await postStockInLine(putawayData);
  426. console.log("result ", res);
  427. // Close modal after successful putaway
  428. closeHandler({}, "backdropClick");
  429. },
  430. [closeHandler],
  431. );
  432. // Print handler
  433. const [isPrinting, setIsPrinting] = useState(false)
  434. const handlePrint = useCallback(async () => {
  435. // console.log("Print putaway documents");
  436. console.log("%c data", "background: white; color: red", formProps.watch("putAwayLines"));
  437. // Handle print logic here
  438. // window.print();
  439. // const postData = { stockInLineIds: [itemDetail.id]};
  440. // const response = await fetchPoQrcode(postData);
  441. // if (response) {
  442. // downloadFile(new Uint8Array(response.blobValue), response.filename)
  443. // }
  444. try {
  445. setIsPrinting(() => true)
  446. if ((formProps.watch("putAwayLines") ?? []).filter((line) => /[^0-9]/.test(String(line.printQty))).length > 0) { //TODO Improve
  447. alert("列印數量不正確!");
  448. return;
  449. }
  450. // console.log(pafRowSelectionModel)
  451. const printList = formProps.watch("putAwayLines")?.filter((line) => ((pafRowSelectionModel ?? []).some((model) => model === line.id))) ?? []
  452. // const printQty = printList.reduce((acc, cur) => acc + cur.printQty, 0)
  453. // console.log(printQty)
  454. const data: PrintQrCodeForSilRequest = {
  455. stockInLineId: stockInLineInfo?.id ?? 0,
  456. printerId: selectedPrinter.id,
  457. printQty: printQty
  458. }
  459. const response = await printQrCodeForSil(data);
  460. if (response) {
  461. console.log(response)
  462. }
  463. } finally {
  464. setIsPrinting(() => false)
  465. }
  466. // }, [pafRowSelectionModel, printQty, selectedPrinter]);
  467. }, [stockInLineInfo?.id, pafRowSelectionModel, printQty, selectedPrinter]);
  468. const acceptQty = formProps.watch("acceptedQty")
  469. // const checkQcIsPassed = useCallback((qcItems: PurchaseQcResult[]) => {
  470. // const isPassed = qcItems.every((qc) => qc.qcPassed);
  471. // console.log(isPassed)
  472. // if (isPassed) {
  473. // formProps.setValue("passingQty", acceptQty)
  474. // } else {
  475. // formProps.setValue("passingQty", 0)
  476. // }
  477. // return isPassed
  478. // }, [acceptQty, formProps])
  479. return (
  480. <>
  481. <FormProvider {...formProps}>
  482. <Modal open={open} onClose={closeHandler}>
  483. <Box
  484. sx={{
  485. ...style,
  486. // padding: 2,
  487. maxHeight: "90vh",
  488. overflowY: "auto",
  489. marginLeft: 3,
  490. marginRight: 3,
  491. // overflow: "hidden",
  492. display: 'flex',
  493. flexDirection: 'column',
  494. }}
  495. >
  496. {(!isLoading && stockInLineInfo) ? (<>
  497. <Box sx={{ position: 'sticky', top: 0, bgcolor: 'background.paper',
  498. zIndex: 5, borderBottom: 2, borderColor: 'divider', width: "100%"}}>
  499. <Tabs
  500. value={tabIndex}
  501. onChange={handleTabChange}
  502. variant="scrollable"
  503. sx={{pl: 2, pr: 2, pt: 2}}
  504. >
  505. <Tab label={
  506. showPutaway ? t("dn and qc info") : t("qc processing")
  507. } iconPosition="end" />
  508. {showPutaway && <Tab label={t("putaway processing")} iconPosition="end" />}
  509. </Tabs>
  510. </Box>
  511. <Grid
  512. container
  513. justifyContent="flex-start"
  514. alignItems="flex-start"
  515. sx={{padding: 2}}
  516. >
  517. <Grid item xs={12}>
  518. {tabIndex === 0 &&
  519. <Box>
  520. <Grid item xs={12}>
  521. <Typography variant="h6" display="block" marginBlockEnd={1}>
  522. {t("Delivery Detail")}
  523. </Typography>
  524. </Grid>
  525. <StockInForm itemDetail={stockInLineInfo} disabled={viewOnly || showPutaway} />
  526. {stockInLineInfo.qcResult ?
  527. <QcComponent
  528. itemDetail={stockInLineInfo}
  529. disabled={viewOnly || showPutaway}
  530. /> : <LoadingComponent/>
  531. }
  532. <Stack direction="row" justifyContent="flex-end" gap={1} sx={{pt:2}}>
  533. {(!viewOnly && !showPutaway) && (<Button
  534. id="Submit"
  535. type="button"
  536. variant="contained"
  537. color="primary"
  538. sx={{ mt: 1 }}
  539. onClick={formProps.handleSubmit(onSubmitQc, onSubmitErrorQc)}
  540. >
  541. {t("confirm qc result")}
  542. </Button>)}
  543. </Stack>
  544. </Box>
  545. }
  546. {tabIndex === 1 &&
  547. <Box>
  548. <PutAwayForm
  549. itemDetail={stockInLineInfo}
  550. warehouse={warehouse!}
  551. disabled={viewOnly}
  552. setRowModesModel={setPafRowModesModel}
  553. setRowSelectionModel={setPafRowSelectionModel}
  554. />
  555. </Box>
  556. }
  557. </Grid>
  558. </Grid>
  559. {tabIndex == 1 && (
  560. <Stack direction="row" justifyContent="flex-end" gap={1} sx={{m:3, mt:"auto"}}>
  561. <Autocomplete
  562. disableClearable
  563. options={printerCombo}
  564. defaultValue={selectedPrinter}
  565. onChange={(event, value) => {
  566. setSelectedPrinter(value)
  567. }}
  568. renderInput={(params) => (
  569. <TextField
  570. {...params}
  571. variant="outlined"
  572. label={t("Printer")}
  573. sx={{ width: 300}}
  574. />
  575. )}
  576. />
  577. <TextField
  578. variant="outlined"
  579. label={t("Print Qty")}
  580. defaultValue={printQty}
  581. onChange={(event) => {
  582. event.target.value = event.target.value.replace(/[^0-9]/g, '')
  583. setPrintQty(Number(event.target.value))
  584. }}
  585. sx={{ width: 300}}
  586. />
  587. <Button
  588. id="printButton"
  589. type="button"
  590. variant="contained"
  591. color="primary"
  592. sx={{ mt: 1 }}
  593. onClick={handlePrint}
  594. disabled={isPrinting || printerCombo.length <= 0 || pafSubmitDisable}
  595. >
  596. {isPrinting ? t("Printing") : t("print")}
  597. </Button>
  598. </Stack>
  599. )}
  600. </>) : <LoadingComponent/>}
  601. </Box>
  602. </Modal>
  603. </FormProvider>
  604. </>
  605. );
  606. };
  607. export default PoQcStockInModalVer2;