FPSMS-frontend
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

378 Zeilen
12 KiB

  1. "use client";
  2. import { StockInLine } from "@/app/api/po";
  3. import { ModalFormInput, PurchaseQcResult } from "@/app/api/po/actions";
  4. import { QcItemWithChecks } from "@/app/api/qc";
  5. import {
  6. Box,
  7. Button,
  8. Grid,
  9. Modal,
  10. ModalProps,
  11. Stack,
  12. Typography,
  13. } from "@mui/material";
  14. import { Dispatch, SetStateAction, useCallback, useEffect, useState } from "react";
  15. import { FormProvider, SubmitHandler, useForm } from "react-hook-form";
  16. import { StockInLineRow } from "./PoInputGrid";
  17. import { useTranslation } from "react-i18next";
  18. import StockInForm from "./StockInForm";
  19. import StockInFormVer2 from "./StockInFormVer2";
  20. import QcFormVer2 from "./QcFormVer2";
  21. import PutawayForm from "./PutawayForm";
  22. import { dummyPutawayLine, dummyQCData, QcData } from "./dummyQcTemplate";
  23. import { useGridApiRef } from "@mui/x-data-grid";
  24. import {submitDialogWithWarning} from "../Swal/CustomAlerts";
  25. const style = {
  26. position: "absolute",
  27. top: "50%",
  28. left: "50%",
  29. transform: "translate(-50%, -50%)",
  30. bgcolor: "background.paper",
  31. pt: 5,
  32. px: 5,
  33. pb: 10,
  34. display: "block",
  35. width: { xs: "60%", sm: "60%", md: "60%" },
  36. // height: { xs: "60%", sm: "60%", md: "60%" },
  37. };
  38. interface CommonProps extends Omit<ModalProps, "children"> {
  39. // setRows: Dispatch<SetStateAction<PurchaseOrderLine[]>>;
  40. setEntries?: Dispatch<SetStateAction<StockInLineRow[]>>;
  41. setStockInLine?: Dispatch<SetStateAction<StockInLine[]>>;
  42. itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] };
  43. setItemDetail: Dispatch<
  44. SetStateAction<
  45. | (StockInLine & {
  46. warehouseId?: number;
  47. })
  48. | undefined
  49. >
  50. >;
  51. qc?: QcItemWithChecks[];
  52. warehouse?: any[];
  53. // type: "qc" | "stockIn" | "escalation" | "putaway" | "reject";
  54. }
  55. interface Props extends CommonProps {
  56. itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] };
  57. }
  58. const PoQcStockInModalVer2: React.FC<Props> = ({
  59. // type,
  60. // setRows,
  61. setEntries,
  62. setStockInLine,
  63. open,
  64. onClose,
  65. itemDetail,
  66. setItemDetail,
  67. qc,
  68. warehouse,
  69. }) => {
  70. console.log(warehouse);
  71. const {
  72. t,
  73. i18n: { language },
  74. } = useTranslation("purchaseOrder");
  75. const [qcItems, setQcItems] = useState(dummyQCData)
  76. const formProps = useForm<ModalFormInput>({
  77. defaultValues: {
  78. ...itemDetail,
  79. putawayLine: dummyPutawayLine,
  80. // receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT),
  81. // warehouseId: itemDetail.defaultWarehouseId || 0
  82. },
  83. });
  84. const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>(
  85. (...args) => {
  86. onClose?.(...args);
  87. // reset();
  88. },
  89. [onClose],
  90. );
  91. const [openPutaway, setOpenPutaway] = useState(false);
  92. const onOpenPutaway = useCallback(() => {
  93. setOpenPutaway(true);
  94. }, []);
  95. const onClosePutaway = useCallback(() => {
  96. setOpenPutaway(false);
  97. }, []);
  98. // Stock In submission handler
  99. const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>(
  100. async (data, event) => {
  101. console.log("Stock In Submission:", event!.nativeEvent);
  102. // Extract only stock-in related fields
  103. const stockInData = {
  104. // quantity: data.quantity,
  105. // receiptDate: data.receiptDate,
  106. // batchNumber: data.batchNumber,
  107. // expiryDate: data.expiryDate,
  108. // warehouseId: data.warehouseId,
  109. // location: data.location,
  110. // unitCost: data.unitCost,
  111. data: data,
  112. // Add other stock-in specific fields from your form
  113. };
  114. console.log("Stock In Data:", stockInData);
  115. // Handle stock-in submission logic here
  116. // e.g., call API, update state, etc.
  117. },
  118. [],
  119. );
  120. // QC submission handler
  121. const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>(
  122. async (data, event) => {
  123. console.log("QC Submission:", event!.nativeEvent);
  124. // Get QC data from the shared form context
  125. const qcAccept = data.qcAccept;
  126. const acceptQty = data.acceptQty;
  127. // Validate QC data
  128. const validationErrors : string[] = [];
  129. // Check if all QC items have results
  130. const itemsWithoutResult = qcItems.filter(item => item.isPassed === undefined);
  131. if (itemsWithoutResult.length > 0) {
  132. validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.qcItem).join(', ')}`);
  133. }
  134. // Check if failed items have failed quantity
  135. const failedItemsWithoutQty = qcItems.filter(item =>
  136. item.isPassed === false && (!item.failedQty || item.failedQty <= 0)
  137. );
  138. if (failedItemsWithoutQty.length > 0) {
  139. validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.qcItem).join(', ')}`);
  140. }
  141. // Check if QC accept decision is made
  142. // if (qcAccept === undefined) {
  143. // validationErrors.push("QC accept/reject decision is required");
  144. // }
  145. // Check if accept quantity is valid
  146. if (acceptQty === undefined || acceptQty <= 0) {
  147. validationErrors.push("Accept quantity must be greater than 0");
  148. }
  149. if (validationErrors.length > 0) {
  150. console.error("QC Validation failed:", validationErrors);
  151. alert(`未完成品檢: ${validationErrors}`);
  152. return;
  153. }
  154. const qcData = {
  155. qcAccept: qcAccept,
  156. acceptQty: acceptQty,
  157. qcItems: qcItems.map(item => ({
  158. id: item.id,
  159. qcItem: item.qcItem,
  160. qcDescription: item.qcDescription,
  161. isPassed: item.isPassed,
  162. failedQty: (item.failedQty && !item.isPassed) || 0,
  163. remarks: item.remarks || ''
  164. }))
  165. };
  166. // const qcData = data;
  167. console.log("QC Data for submission:", qcData);
  168. // await submitQcData(qcData);
  169. if (!qcData.qcItems.every((qc) => qc.isPassed) && qcData.qcAccept) {
  170. submitDialogWithWarning(onOpenPutaway, t, {title:"有不合格檢查項目,確認接受收貨?", confirmButtonText: "Confirm", html: ""});
  171. return;
  172. }
  173. if (qcData.qcAccept) {
  174. onOpenPutaway();
  175. } else {
  176. onClose();
  177. }
  178. },
  179. [onOpenPutaway, qcItems],
  180. );
  181. // Email supplier handler
  182. const onSubmitEmailSupplier = useCallback<SubmitHandler<ModalFormInput>>(
  183. async (data, event) => {
  184. console.log("Email Supplier Submission:", event!.nativeEvent);
  185. // Extract only email supplier related fields
  186. const emailData = {
  187. // supplierEmail: data.supplierEmail,
  188. // issueDescription: data.issueDescription,
  189. // qcComments: data.qcComments,
  190. // defectNotes: data.defectNotes,
  191. // attachments: data.attachments,
  192. // escalationReason: data.escalationReason,
  193. data: data,
  194. // Add other email-specific fields
  195. };
  196. console.log("Email Supplier Data:", emailData);
  197. // Handle email supplier logic here
  198. // e.g., send email to supplier, log escalation, etc.
  199. },
  200. [],
  201. );
  202. // Putaway submission handler
  203. const onSubmitPutaway = useCallback<SubmitHandler<ModalFormInput>>(
  204. async (data, event) => {
  205. console.log("Putaway Submission:", event!.nativeEvent);
  206. // Extract only putaway related fields
  207. const putawayData = {
  208. // putawayLine: data.putawayLine,
  209. // putawayLocation: data.putawayLocation,
  210. // binLocation: data.binLocation,
  211. // putawayQuantity: data.putawayQuantity,
  212. // putawayNotes: data.putawayNotes,
  213. data: data,
  214. // Add other putaway specific fields
  215. };
  216. console.log("Putaway Data:", putawayData);
  217. // Handle putaway submission logic here
  218. // Close modal after successful putaway
  219. closeHandler({}, "backdropClick");
  220. },
  221. [closeHandler],
  222. );
  223. // Print handler
  224. const onPrint = useCallback(() => {
  225. console.log("Print putaway documents");
  226. // Handle print logic here
  227. window.print();
  228. }, []);
  229. const acceptQty = formProps.watch("acceptedQty")
  230. const checkQcIsPassed = useCallback((qcItems: QcData[]) => {
  231. const isPassed = qcItems.every((qc) => qc.isPassed);
  232. console.log(isPassed)
  233. if (isPassed) {
  234. formProps.setValue("passingQty", acceptQty)
  235. } else {
  236. formProps.setValue("passingQty", 0)
  237. }
  238. return isPassed
  239. }, [acceptQty, formProps])
  240. useEffect(() => {
  241. // maybe check if submitted before
  242. console.log(qcItems)
  243. checkQcIsPassed(qcItems)
  244. }, [qcItems, checkQcIsPassed])
  245. return (
  246. <>
  247. <FormProvider {...formProps}>
  248. <Modal open={open} onClose={closeHandler}>
  249. <Box
  250. sx={{
  251. ...style,
  252. padding: 2,
  253. maxHeight: "90vh",
  254. overflowY: "auto",
  255. marginLeft: 3,
  256. marginRight: 3,
  257. }}
  258. >
  259. {openPutaway ? (
  260. <Box
  261. component="form"
  262. onSubmit={formProps.handleSubmit(onSubmitPutaway)}
  263. >
  264. <PutawayForm
  265. itemDetail={itemDetail}
  266. warehouse={warehouse!}
  267. disabled={false}
  268. />
  269. <Stack direction="row" justifyContent="flex-end" gap={1}>
  270. <Button
  271. id="printButton"
  272. type="button"
  273. variant="contained"
  274. color="primary"
  275. sx={{ mt: 1 }}
  276. onClick={onPrint}
  277. >
  278. {t("print")}
  279. </Button>
  280. <Button
  281. id="putawaySubmit"
  282. type="submit"
  283. variant="contained"
  284. color="primary"
  285. sx={{ mt: 1 }}
  286. >
  287. {t("confirm putaway")}
  288. </Button>
  289. </Stack>
  290. </Box>
  291. ) : (
  292. <>
  293. <Grid
  294. container
  295. justifyContent="flex-start"
  296. alignItems="flex-start"
  297. >
  298. <Grid item xs={12}>
  299. <Typography variant="h6" display="block" marginBlockEnd={1}>
  300. {t("qc processing")}
  301. </Typography>
  302. </Grid>
  303. <Grid item xs={12}>
  304. <StockInFormVer2 itemDetail={itemDetail} disabled={false} />
  305. </Grid>
  306. </Grid>
  307. <Stack direction="row" justifyContent="flex-end" gap={1}>
  308. <Button
  309. id="stockInSubmit"
  310. type="button"
  311. variant="contained"
  312. color="primary"
  313. onClick={formProps.handleSubmit(onSubmitStockIn)}
  314. >
  315. {t("submitStockIn")}
  316. </Button>
  317. </Stack>
  318. <Grid
  319. container
  320. justifyContent="flex-start"
  321. alignItems="flex-start"
  322. >
  323. <QcFormVer2
  324. qc={qc!}
  325. itemDetail={itemDetail}
  326. disabled={false}
  327. qcItems={qcItems}
  328. setQcItems={setQcItems}
  329. />
  330. </Grid>
  331. <Stack direction="row" justifyContent="flex-end" gap={1}>
  332. <Button
  333. id="emailSupplier"
  334. type="button"
  335. variant="contained"
  336. color="primary"
  337. sx={{ mt: 1 }}
  338. onClick={formProps.handleSubmit(onSubmitEmailSupplier)}
  339. >
  340. {t("email supplier")}
  341. </Button>
  342. <Button
  343. id="qcSubmit"
  344. type="button"
  345. variant="contained"
  346. color="primary"
  347. sx={{ mt: 1 }}
  348. onClick={formProps.handleSubmit(onSubmitQc)}
  349. >
  350. {t("confirm putaway")}
  351. </Button>
  352. </Stack>
  353. </>
  354. )}
  355. </Box>
  356. </Modal>
  357. </FormProvider>
  358. </>
  359. );
  360. };
  361. export default PoQcStockInModalVer2;