diff --git a/src/app/api/jo/actions.ts b/src/app/api/jo/actions.ts index 058c217..e4416d3 100644 --- a/src/app/api/jo/actions.ts +++ b/src/app/api/jo/actions.ts @@ -1,11 +1,12 @@ "use server"; import { cache } from 'react'; -import { Pageable, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; +import { Pageable, serverFetchBlob, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; import { JobOrder, JoStatus, Machine, Operator } from "."; import { BASE_API_URL } from "@/config/api"; import { revalidateTag } from "next/cache"; import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; +import { FileResponse } from "@/app/api/pdf/actions"; export interface SaveJo { bomId: number; @@ -155,7 +156,7 @@ export const printFGStockInLabel = cache(async(data: PrintFGStockInLabelRequest) } return serverFetchWithNoContent( - `${BASE_API_URL}/jo/print-FGPickRecordLabel?${params.toString()}`, + `${BASE_API_URL}/jo/print-FGStockInLabel?${params.toString()}`, { method: "GET", next: { @@ -1027,3 +1028,20 @@ export async function PrintPickRecord(request: PrintPickRecordRequest){ return { success: true, message: "Print job sent successfully (Pick Record)" } as PrintPickRecordResponse; } + +export interface ExportFGStockInLabelRequest { + stockInLineId: number; +} + +export const fetchFGStockInLabel = async (data: ExportFGStockInLabelRequest): Promise => { + const reportBlob = await serverFetchBlob( + `${BASE_API_URL}/jo/FGStockInLabel`, + { + method: "POST", + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + }, + ); + + return reportBlob; +}; \ No newline at end of file diff --git a/src/components/ProductionProcess/ProductionProcessList.tsx b/src/components/ProductionProcess/ProductionProcessList.tsx index 8a46fc2..857979a 100644 --- a/src/components/ProductionProcess/ProductionProcessList.tsx +++ b/src/components/ProductionProcess/ProductionProcessList.tsx @@ -94,7 +94,8 @@ const ProductProcessList: React.FC = ({ onSelectProcess setModalInfo({ id: process.stockInLineId, - expiryDate: dayjs().add(1, "month").format(OUTPUT_DATE_FORMAT), + //expiryDate: dayjs().add(1, "month").format(OUTPUT_DATE_FORMAT), + // 视需要补 itemId、jobOrderId 等 }); setOpenModal(true); diff --git a/src/components/Qc/QcComponent.tsx b/src/components/Qc/QcComponent.tsx index 089dfcc..031e93d 100644 --- a/src/components/Qc/QcComponent.tsx +++ b/src/components/Qc/QcComponent.tsx @@ -413,10 +413,11 @@ useEffect(() => { } else { return 60} }; - const formattedDesc = (content: string = "") => { + const formattedDesc = (content: string | null | undefined = "") => { + const safeContent = content || ""; return ( <> - {content.split("\\n").map((line, index) => ( + {safeContent.split("\\n").map((line, index) => ( {line}
))} diff --git a/src/components/Qc/QcStockInModal.tsx b/src/components/Qc/QcStockInModal.tsx index bf40183..3da6c8e 100644 --- a/src/components/Qc/QcStockInModal.tsx +++ b/src/components/Qc/QcStockInModal.tsx @@ -40,7 +40,7 @@ import { StockInLineEntry, updateStockInLine, printQrCodeForSil, PrintQrCodeForS import { fetchStockInLineInfo } from "@/app/api/stockIn/actions"; import FgStockInForm from "../StockIn/FgStockInForm"; import LoadingComponent from "../General/LoadingComponent"; -import { printFGStockInLabel, PrintFGStockInLabelRequest } from "@/app/api/jo/actions"; +import { printFGStockInLabel, PrintFGStockInLabelRequest, fetchFGStockInLabel } from "@/app/api/jo/actions"; const style = { position: "absolute", @@ -119,7 +119,7 @@ const QcStockInModal: React.FC = ({ const res = await fetchStockInLineInfo(stockInLineId); if (res) { console.log("%c Fetched Stock In Line: ", "color:orange", res); - setStockInLineInfo({...inputDetail, ...res, expiryDate: inputDetail?.expiryDate}); // TODO review to overwrite res with inputDetail instead (revise PO fetching data) + setStockInLineInfo({...inputDetail, ...res, expiryDate: res.expiryDate}); // fetchQcResultData(stockInLineId); } else throw("Result is undefined"); @@ -168,8 +168,8 @@ const QcStockInModal: React.FC = ({ { ...d, // status: d.status ?? "pending", - productionDate: d.productionDate ? arrayToDateString(d.productionDate, "input") : undefined, - expiryDate: d.expiryDate ? arrayToDateString(d.expiryDate, "input") : undefined, + productionDate: d.productionDate ? arrayToDateString(d.productionDate, "input") : dayjs().format(INPUT_DATE_FORMAT), + expiryDate: d.expiryDate ? (Array.isArray(d.expiryDate) ? arrayToDateString(d.expiryDate, "input") : d.expiryDate) : undefined, receiptDate: d.receiptDate ? arrayToDateString(d.receiptDate, "input") : dayjs().add(0, "month").format(INPUT_DATE_FORMAT), acceptQty: d.status != StockInStatus.REJECTED ? (d.demandQty?? d.acceptedQty) : 0, @@ -350,9 +350,9 @@ const QcStockInModal: React.FC = ({ const qcData = { dnNo : data.dnNo? data.dnNo : "DN00000", // dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()), - productionDate : arrayToDateString(data.productionDate, "input"), - expiryDate : arrayToDateString(data.expiryDate, "input"), - receiptDate : arrayToDateString(data.receiptDate, "input"), + productionDate : data.productionDate ? (Array.isArray(data.productionDate) ? arrayToDateString(data.productionDate, "input") : data.productionDate) : undefined, + expiryDate : data.expiryDate ? (Array.isArray(data.expiryDate) ? arrayToDateString(data.expiryDate, "input") : data.expiryDate) : undefined, + receiptDate : data.receiptDate ? (Array.isArray(data.receiptDate) ? arrayToDateString(data.receiptDate, "input") : data.receiptDate) : undefined, qcAccept: qcAccept? qcAccept : false, acceptQty: acceptQty? acceptQty : 0, @@ -540,24 +540,38 @@ const QcStockInModal: React.FC = ({ // return isPassed // }, [acceptQty, formProps]) - const printQrcode = useCallback( - async () => { - setIsPrinting(true); - try { - const postData = { stockInLineIds: [stockInLineInfo?.id] }; - const response = await fetchPoQrcode(postData); - if (response) { - console.log(response); - downloadFile(new Uint8Array(response.blobValue), response.filename!); - } - } catch (e) { - console.log("%c Error downloading QR Code", "color:red", e); - } finally { +const printQrcode = useCallback( + async () => { + setIsPrinting(true); + try { + let response; + + if (printSource === "productionProcess") { + // Use FG Stock In Label download API for production process + if (!stockInLineInfo?.id) { + console.error("Stock In Line ID is required for download"); setIsPrinting(false); + return; } - }, - [stockInLineInfo], - ); + const postData = { stockInLineId: stockInLineInfo.id }; + response = await fetchFGStockInLabel(postData); + } else { + const postData = { stockInLineIds: [stockInLineInfo?.id] }; + response = await fetchPoQrcode(postData); + } + + if (response) { + console.log(response); + downloadFile(new Uint8Array(response.blobValue), response.filename!); + } + } catch (e) { + console.log("%c Error downloading QR Code", "color:red", e); + } finally { + setIsPrinting(false); + } + }, + [stockInLineInfo, printSource], +); return ( <> diff --git a/src/components/StockIn/FgStockInForm.tsx b/src/components/StockIn/FgStockInForm.tsx index af46970..bad913f 100644 --- a/src/components/StockIn/FgStockInForm.tsx +++ b/src/components/StockIn/FgStockInForm.tsx @@ -12,11 +12,12 @@ import { TextField, Tooltip, Typography, + Button, } from "@mui/material"; import { Controller, useFormContext } from "react-hook-form"; import { useTranslation } from "react-i18next"; import StyledDataGrid from "../StyledDataGrid"; -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { GridColDef, GridRowIdGetter, @@ -35,6 +36,11 @@ import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; import dayjs from "dayjs"; +import CalculateExpiryDateModal from "./CalculateExpiryDateModal"; +import { InputAdornment } from "@mui/material"; +import { dayjsToDateString } from "@/app/utils/formatUtil"; + + // change PurchaseQcResult to stock in entry props interface Props { itemDetail: StockInLine; @@ -115,6 +121,8 @@ const FgStockInForm: React.FC = ({ console.log(errors); }, [errors]); + const [openModal, setOpenModal] = useState(false); + const [openExpDatePicker, setOpenExpDatePicker] = useState(false); const productionDate = watch("productionDate"); const expiryDate = watch("expiryDate"); const uom = watch("uom"); @@ -140,7 +148,23 @@ const FgStockInForm: React.FC = ({ console.log("%c StockInForm itemDetail update: ", "color: brown", itemDetail); }, [itemDetail]); - return ( + const handleOpenModal = useCallback(() => { + setOpenModal(true); + }, []); + + const handleOnModalClose = useCallback(() => { + setOpenExpDatePicker(false); + setOpenModal(false); + }, []); + + const handleReturnExpiryDate = useCallback((result: dayjs.Dayjs) => { + if (result) { + setValue("expiryDate", dayjsToDateString(result)); + } + }, [setValue]); + +return ( + <> {/* @@ -250,6 +274,44 @@ const FgStockInForm: React.FC = ({ />) } + + { + return ( + + { + if (!date) return; + setValue( + "productionDate", + date.format(INPUT_DATE_FORMAT), + ); + }} + inputRef={field.ref} + slotProps={{ + textField: { + error: Boolean(errors.productionDate?.message), + helperText: errors.productionDate?.message, + }, + }} + /> + + ); + }} + /> + + {/* {putawayMode || (<> {/* {putawayMode || (<> = ({ dateAdapter={AdapterDayjs} adapterLocale={`${language}-hk`} > - { - if (!date) return; - console.log(date.format(INPUT_DATE_FORMAT)); - setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); - // field.onChange(date); - }} - inputRef={field.ref} - slotProps={{ - textField: { - // required: true, - error: Boolean(errors.expiryDate?.message), - helperText: errors.expiryDate?.message, - }, - }} - /> + { + if (!date) return; + console.log(date.format(INPUT_DATE_FORMAT)); + setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); + }} + inputRef={field.ref} + open={openExpDatePicker && !openModal} + onOpen={() => setOpenExpDatePicker(true)} + onClose={() => setOpenExpDatePicker(false)} + slotProps={{ + textField: { + InputProps: { + ...(!disabled && { + endAdornment: ( + + + + ), + }) + }, + error: Boolean(errors.expiryDate?.message), + helperText: errors.expiryDate?.message, + onClick: () => setOpenExpDatePicker(true), + }, + }} + /> ); }} @@ -442,6 +523,13 @@ const FgStockInForm: React.FC = ({ */} - ); + + +); }; export default FgStockInForm;