FPSMS-frontend
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 

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