FPSMS-frontend
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

381 linhas
12 KiB

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