FPSMS-frontend
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

QcStockInModal.tsx 26 KiB

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