@@ -1,4 +1,4 @@ | |||||
import StockInForm from "./StockInForm"; | |||||
import StockInFormOld from "./StockInFormOld"; | |||||
import EscalationLog from "./EscalationLog"; | import EscalationLog from "./EscalationLog"; | ||||
import EscalationComponent from "./EscalationComponent"; | import EscalationComponent from "./EscalationComponent"; | ||||
import React from "react"; | import React from "react"; | ||||
@@ -14,7 +14,7 @@ interface Props { | |||||
const EscalationTab:React.FC<Props> = ({itemDetail, disabled}) => { | const EscalationTab:React.FC<Props> = ({itemDetail, disabled}) => { | ||||
return <> | return <> | ||||
<StockInForm itemDetail={itemDetail} disabled={disabled}/> | |||||
<StockInFormOld itemDetail={itemDetail} disabled={disabled}/> | |||||
<EscalationLog/> | <EscalationLog/> | ||||
<EscalationComponent/> | <EscalationComponent/> | ||||
</> | </> | ||||
@@ -60,7 +60,7 @@ import PoQcStockInModal from "./PoQcStockInModal"; | |||||
import DoDisturbIcon from "@mui/icons-material/DoDisturb"; | import DoDisturbIcon from "@mui/icons-material/DoDisturb"; | ||||
import { useSession } from "next-auth/react"; | import { useSession } from "next-auth/react"; | ||||
// import { SessionWithTokens } from "src/config/authConfig"; | // import { SessionWithTokens } from "src/config/authConfig"; | ||||
import PoQcStockInModalVer2 from "./QcStockInModalVer2"; | |||||
import QcStockInModal from "./QcStockInModal"; | |||||
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
import { PrinterCombo } from "@/app/api/settings/printer"; | import { PrinterCombo } from "@/app/api/settings/printer"; | ||||
import { EscalationResult } from "@/app/api/escalation"; | import { EscalationResult } from "@/app/api/escalation"; | ||||
@@ -939,7 +939,7 @@ const closeNewModal = useCallback(() => { | |||||
/> | /> | ||||
{modalInfo !== undefined && ( | {modalInfo !== undefined && ( | ||||
<> | <> | ||||
<PoQcStockInModalVer2 | |||||
<QcStockInModal | |||||
// setRows={setRows} | // setRows={setRows} | ||||
setEntries={setEntries} | setEntries={setEntries} | ||||
setStockInLine={setStockInLine} | setStockInLine={setStockInLine} | ||||
@@ -27,7 +27,7 @@ import { PurchaseOrderLine, StockInLine } from "@/app/api/po"; | |||||
import { useSearchParams } from "next/navigation"; | import { useSearchParams } from "next/navigation"; | ||||
import { StockInLineRow } from "./PoInputGrid"; | import { StockInLineRow } from "./PoInputGrid"; | ||||
import EscalationForm from "./EscalationForm"; | import EscalationForm from "./EscalationForm"; | ||||
import StockInForm from "./StockInForm"; | |||||
import StockInFormOld from "./StockInFormOld"; | |||||
import PutAwayForm from "./PutAwayForm"; | import PutAwayForm from "./PutAwayForm"; | ||||
import { | import { | ||||
INPUT_DATE_FORMAT, | INPUT_DATE_FORMAT, | ||||
@@ -431,7 +431,7 @@ const PoQcStockInModal: React.FC<Props> = ({ | |||||
/> | /> | ||||
)} | )} | ||||
{itemDetail !== undefined && type === "stockIn" && ( | {itemDetail !== undefined && type === "stockIn" && ( | ||||
<StockInForm | |||||
<StockInFormOld | |||||
itemDetail={itemDetail} | itemDetail={itemDetail} | ||||
disabled={!renderSubmitButton} | disabled={!renderSubmitButton} | ||||
/> | /> | ||||
@@ -48,7 +48,6 @@ import { NEXT_PUBLIC_API_URL } from "@/config/api"; | |||||
import axiosInstance from "@/app/(main)/axios/axiosInstance"; | import axiosInstance from "@/app/(main)/axios/axiosInstance"; | ||||
import EscalationComponent from "./EscalationComponent"; | import EscalationComponent from "./EscalationComponent"; | ||||
import QcDataGrid from "./QCDatagrid"; | import QcDataGrid from "./QCDatagrid"; | ||||
import StockInFormVer2 from "./StockInFormVer2"; | |||||
import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate"; | import { dummyEscalationHistory, dummyQCData } from "./dummyQcTemplate"; | ||||
import { ModalFormInput } from "@/app/api/po/actions"; | import { ModalFormInput } from "@/app/api/po/actions"; | ||||
import { escape, min } from "lodash"; | import { escape, min } from "lodash"; | ||||
@@ -0,0 +1,610 @@ | |||||
"use client"; | |||||
import { StockInLine } from "@/app/api/po"; | |||||
import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine, PurchaseQCInput, printQrCodeForSil, PrintQrCodeForSilRequest } from "@/app/api/po/actions"; | |||||
import { QcItemWithChecks, QcData } from "@/app/api/qc"; | |||||
import { | |||||
Autocomplete, | |||||
Box, | |||||
Button, | |||||
Grid, | |||||
Modal, | |||||
ModalProps, | |||||
Stack, | |||||
TextField, | |||||
Typography, | |||||
} from "@mui/material"; | |||||
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useState } from "react"; | |||||
import { FormProvider, SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; | |||||
import { StockInLineRow } from "./PoInputGrid"; | |||||
import { useTranslation } from "react-i18next"; | |||||
import StockInForm from "./StockInForm"; | |||||
import QcComponent from "./QcComponent"; | |||||
import { dummyPutAwayLine, dummyQCData } from "./dummyQcTemplate"; | |||||
import PutAwayForm from "./PutAwayForm"; | |||||
import { GridRowModes, GridRowSelectionModel, useGridApiRef } from "@mui/x-data-grid"; | |||||
import {submitDialogWithWarning} from "../Swal/CustomAlerts"; | |||||
import { INPUT_DATE_FORMAT, arrayToDateString, dayjsToInputDateString } from "@/app/utils/formatUtil"; | |||||
import dayjs from "dayjs"; | |||||
import { fetchPoQrcode } from "@/app/api/pdf/actions"; | |||||
import { downloadFile } from "@/app/utils/commonUtil"; | |||||
import { PrinterCombo } from "@/app/api/settings/printer"; | |||||
import { EscalationResult } from "@/app/api/escalation"; | |||||
import { SessionWithTokens } from "@/config/authConfig"; | |||||
import { GridRowModesModel } from "@mui/x-data-grid"; | |||||
import { isEmpty } from "lodash"; | |||||
import { EscalationCombo } from "@/app/api/user"; | |||||
import { truncateSync } from "fs"; | |||||
const style = { | |||||
position: "absolute", | |||||
top: "50%", | |||||
left: "50%", | |||||
transform: "translate(-50%, -50%)", | |||||
bgcolor: "background.paper", | |||||
pt: 5, | |||||
px: 5, | |||||
pb: 10, | |||||
display: "block", | |||||
width: { xs: "90%", sm: "90%", md: "90%" }, | |||||
// height: { xs: "60%", sm: "60%", md: "60%" }, | |||||
}; | |||||
interface CommonProps extends Omit<ModalProps, "children"> { | |||||
// setRows: Dispatch<SetStateAction<PurchaseOrderLine[]>>; | |||||
setEntries?: Dispatch<SetStateAction<StockInLineRow[]>>; | |||||
setStockInLine?: Dispatch<SetStateAction<StockInLine[]>>; | |||||
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; | |||||
setItemDetail: Dispatch< | |||||
SetStateAction< | |||||
| (StockInLine & { | |||||
warehouseId?: number; | |||||
}) | |||||
| undefined | |||||
> | |||||
>; | |||||
session: SessionWithTokens | null; | |||||
qc?: QcItemWithChecks[]; | |||||
warehouse?: any[]; | |||||
// type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; | |||||
handleMailTemplateForStockInLine: (stockInLineId: number) => void; | |||||
printerCombo: PrinterCombo[]; | |||||
onClose: () => void; | |||||
} | |||||
interface Props extends CommonProps { | |||||
itemDetail: StockInLine & { qcResult?: PurchaseQcResult[] } & { escResult?: EscalationResult[] }; | |||||
} | |||||
const PoQcStockInModalVer2: React.FC<Props> = ({ | |||||
// type, | |||||
// setRows, | |||||
setEntries, | |||||
setStockInLine, | |||||
open, | |||||
onClose, | |||||
itemDetail, | |||||
setItemDetail, | |||||
session, | |||||
qc, | |||||
warehouse, | |||||
handleMailTemplateForStockInLine, | |||||
printerCombo, | |||||
}) => { | |||||
const { | |||||
t, | |||||
i18n: { language }, | |||||
} = useTranslation("purchaseOrder"); | |||||
// Select Printer | |||||
const [selectedPrinter, setSelectedPrinter] = useState(printerCombo[0]); | |||||
const defaultNewValue = useMemo(() => { | |||||
return ( | |||||
{ | |||||
...itemDetail, | |||||
status: itemDetail.status ?? "pending", | |||||
dnDate: arrayToDateString(itemDetail.dnDate, "input")?? dayjsToInputDateString(dayjs()), | |||||
// putAwayLines: dummyPutAwayLine, | |||||
// putAwayLines: itemDetail.putAwayLines.map((line) => (return {...line, printQty: 1})) ?? [], | |||||
putAwayLines: itemDetail.putAwayLines?.map((line) => ({...line, printQty: 1, _isNew: false, _disableDelete: true})) ?? [], | |||||
// qcResult: (itemDetail.qcResult && itemDetail.qcResult?.length > 0) ? itemDetail.qcResult : [],//[...dummyQCData], | |||||
escResult: (itemDetail.escResult && itemDetail.escResult?.length > 0) ? itemDetail.escResult : [], | |||||
productionDate: itemDetail.productionDate ? arrayToDateString(itemDetail.productionDate, "input") : undefined, | |||||
expiryDate: itemDetail.expiryDate ? arrayToDateString(itemDetail.expiryDate, "input") : undefined, | |||||
receiptDate: itemDetail.receiptDate ? arrayToDateString(itemDetail.receiptDate, "input") | |||||
: dayjs().add(0, "month").format(INPUT_DATE_FORMAT), | |||||
acceptQty: itemDetail.demandQty?? itemDetail.acceptedQty, | |||||
warehouseId: itemDetail.defaultWarehouseId ?? 1, | |||||
} | |||||
) | |||||
},[itemDetail]) | |||||
const [qcItems, setQcItems] = useState(dummyQCData) | |||||
const formProps = useForm<ModalFormInput>({ | |||||
defaultValues: { | |||||
...defaultNewValue, | |||||
}, | |||||
}); | |||||
const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>( | |||||
() => { | |||||
onClose?.(); | |||||
// reset(); | |||||
}, | |||||
[onClose], | |||||
); | |||||
const isPutaway = () => { | |||||
if (itemDetail) { | |||||
const status = itemDetail.status; | |||||
return status == "received"; | |||||
} else return false; | |||||
}; | |||||
const [viewOnly, setViewOnly] = useState(false); | |||||
useEffect(() => { | |||||
if (itemDetail && itemDetail.status) { | |||||
const isViewOnly = itemDetail.status.toLowerCase() == "completed" | |||||
|| itemDetail.status.toLowerCase() == "partially_completed" // TODO update DB | |||||
|| itemDetail.status.toLowerCase() == "rejected" | |||||
|| (itemDetail.status.toLowerCase() == "escalated" && session?.id != itemDetail.handlerId) | |||||
setViewOnly(isViewOnly) | |||||
} | |||||
console.log("Modal ItemDetail updated:", itemDetail); | |||||
}, [itemDetail]); | |||||
useEffect(() => { | |||||
formProps.reset({ | |||||
...defaultNewValue | |||||
}) | |||||
setQcItems(dummyQCData); | |||||
setOpenPutaway(isPutaway); | |||||
}, [open]) | |||||
const [openPutaway, setOpenPutaway] = useState(false); | |||||
const onOpenPutaway = useCallback(() => { | |||||
setOpenPutaway(true); | |||||
}, []); | |||||
const onClosePutaway = useCallback(() => { | |||||
setOpenPutaway(false); | |||||
}, []); | |||||
// Stock In submission handler | |||||
const onSubmitStockIn = useCallback<SubmitHandler<ModalFormInput>>( | |||||
async (data, event) => { | |||||
console.log("Stock In Submission:", event!.nativeEvent); | |||||
// Extract only stock-in related fields | |||||
const stockInData = { | |||||
// quantity: data.quantity, | |||||
// receiptDate: data.receiptDate, | |||||
// batchNumber: data.batchNumber, | |||||
// expiryDate: data.expiryDate, | |||||
// warehouseId: data.warehouseId, | |||||
// location: data.location, | |||||
// unitCost: data.unitCost, | |||||
data: data, | |||||
// Add other stock-in specific fields from your form | |||||
}; | |||||
console.log("Stock In Data:", stockInData); | |||||
// Handle stock-in submission logic here | |||||
// e.g., call API, update state, etc. | |||||
}, | |||||
[], | |||||
); | |||||
// QC submission handler | |||||
const onSubmitErrorQc = useCallback<SubmitErrorHandler<ModalFormInput>>( | |||||
async (data, event) => { | |||||
console.log("Error", data); | |||||
}, [] | |||||
); | |||||
// QC submission handler | |||||
const onSubmitQc = useCallback<SubmitHandler<ModalFormInput>>( | |||||
async (data, event) => { | |||||
console.log("QC Submission:", event!.nativeEvent); | |||||
// TODO: Move validation into QC page | |||||
// if (errors.length > 0) { | |||||
// alert(`未完成品檢: ${errors.map((err) => err[1].message)}`); | |||||
// return; | |||||
// } | |||||
// Get QC data from the shared form context | |||||
const qcAccept = data.qcDecision == 1; | |||||
// const qcAccept = data.qcAccept; | |||||
let acceptQty = Number(data.acceptQty); | |||||
const qcResults = data.qcResult?.filter((qc) => qc.escalationLogId === undefined) || []; // Remove old QC data | |||||
// const qcResults = data.qcResult as PurchaseQcResult[]; // qcItems; | |||||
// const qcResults = viewOnly? data.qcResult as PurchaseQcResult[] : qcItems; | |||||
// Validate QC data | |||||
const validationErrors : string[] = []; | |||||
// Check if failed items have failed quantity | |||||
const failedItemsWithoutQty = qcResults.filter(item => | |||||
item.qcPassed === false && (!item.failQty || item.failQty <= 0) | |||||
); | |||||
if (failedItemsWithoutQty.length > 0) { | |||||
validationErrors.push(`${t("Failed items must have failed quantity")}`); | |||||
// validationErrors.push(`${t("Failed items must have failed quantity")}: ${failedItemsWithoutQty.map(item => item.code).join(', ')}`); | |||||
} | |||||
// Check if QC accept decision is made | |||||
if (data.qcDecision === undefined) { | |||||
// if (qcAccept === undefined) { | |||||
validationErrors.push(t("QC decision is required")); | |||||
} | |||||
// Check if accept quantity is valid | |||||
if (data.qcDecision == 2) { | |||||
acceptQty = 0; | |||||
} else { | |||||
if (acceptQty === undefined || acceptQty <= 0) { | |||||
validationErrors.push("Accept quantity must be greater than 0"); | |||||
} | |||||
} | |||||
// Check if dates are input | |||||
if (data.productionDate === undefined || data.productionDate == null) { | |||||
alert("請輸入生產日期!"); | |||||
return; | |||||
} | |||||
if (data.expiryDate === undefined || data.expiryDate == null) { | |||||
alert("請輸入到期日!"); | |||||
return; | |||||
} | |||||
if (!qcResults.every((qc) => qc.qcPassed) && qcAccept && itemDetail.status != "escalated") { //TODO: fix it please! | |||||
validationErrors.push("有不合格檢查項目,無法收貨!"); | |||||
// submitDialogWithWarning(() => postStockInLineWithQc(qcData), t, {title:"有不合格檢查項目,確認接受收貨?", | |||||
// confirmButtonText: t("confirm putaway"), html: ""}); | |||||
// return; | |||||
} | |||||
// Check if all QC items have results | |||||
const itemsWithoutResult = qcResults.filter(item => item.qcPassed === undefined); | |||||
if (itemsWithoutResult.length > 0 && itemDetail.status != "escalated") { //TODO: fix it please! | |||||
validationErrors.push(`${t("QC items without result")}`); | |||||
// validationErrors.push(`${t("QC items without result")}: ${itemsWithoutResult.map(item => item.code).join(', ')}`); | |||||
} | |||||
if (validationErrors.length > 0) { | |||||
console.error("QC Validation failed:", validationErrors); | |||||
alert(`未完成品檢: ${validationErrors}`); | |||||
return; | |||||
} | |||||
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"), | |||||
qcAccept: qcAccept? qcAccept : false, | |||||
acceptQty: acceptQty? acceptQty : 0, | |||||
// qcResult: itemDetail.status != "escalated" ? qcResults.map(item => ({ | |||||
qcResult: qcResults.map(item => ({ | |||||
// id: item.id, | |||||
qcItemId: item.qcItemId, | |||||
// code: item.code, | |||||
// qcDescription: item.qcDescription, | |||||
qcPassed: item.qcPassed? item.qcPassed : false, | |||||
failQty: (item.failQty && !item.qcPassed) ? item.failQty : 0, | |||||
// failedQty: (typeof item.failedQty === "number" && !item.isPassed) ? item.failedQty : 0, | |||||
remarks: item.remarks || '', | |||||
})), | |||||
}; | |||||
// const qcData = data; | |||||
console.log("QC Data for submission:", qcData); | |||||
if (data.qcDecision == 3) { // Escalate | |||||
if (data.escalationLog?.handlerId == undefined) { alert("請選擇上報負責同事!"); return; } | |||||
else if (data.escalationLog?.handlerId < 1) { alert("上報負責同事資料有誤"); return; } | |||||
const escalationLog = { | |||||
type : "qc", | |||||
status : "pending", // TODO: update with supervisor decision | |||||
reason : data.escalationLog?.reason, | |||||
recordDate : dayjsToInputDateString(dayjs()), | |||||
handlerId : data.escalationLog?.handlerId, | |||||
} | |||||
console.log("Escalation Data for submission", escalationLog); | |||||
await postStockInLine({...qcData, escalationLog}); | |||||
} else { | |||||
await postStockInLine(qcData); | |||||
} | |||||
if (qcData.qcAccept) { | |||||
// submitDialogWithWarning(onOpenPutaway, t, {title:"Save success, confirm to proceed?", | |||||
// confirmButtonText: t("confirm putaway"), html: ""}); | |||||
onOpenPutaway(); | |||||
} else { | |||||
closeHandler({}, "backdropClick"); | |||||
} | |||||
return ; | |||||
}, | |||||
[onOpenPutaway, qcItems, formProps.formState.errors], | |||||
); | |||||
const postStockInLine = useCallback(async (args: ModalFormInput) => { | |||||
const submitData = { | |||||
...itemDetail, ...args | |||||
} as StockInLineEntry & ModalFormInput; | |||||
console.log("Submitting", submitData); | |||||
const res = await updateStockInLine(submitData); | |||||
return res; | |||||
},[itemDetail]) | |||||
// Email supplier handler | |||||
const onSubmitEmailSupplier = useCallback<SubmitHandler<ModalFormInput>>( | |||||
async (data, event) => { | |||||
console.log("Email Supplier Submission:", event!.nativeEvent); | |||||
// Extract only email supplier related fields | |||||
const emailData = { | |||||
// supplierEmail: data.supplierEmail, | |||||
// issueDescription: data.issueDescription, | |||||
// qcComments: data.qcComments, | |||||
// defectNotes: data.defectNotes, | |||||
// attachments: data.attachments, | |||||
// escalationReason: data.escalationReason, | |||||
data: data, | |||||
// Add other email-specific fields | |||||
}; | |||||
console.log("Email Supplier Data:", emailData); | |||||
// Handle email supplier logic here | |||||
// e.g., send email to supplier, log escalation, etc. | |||||
}, | |||||
[], | |||||
); | |||||
// Put away model | |||||
const [pafRowModesModel, setPafRowModesModel] = useState<GridRowModesModel>({}) | |||||
const [pafRowSelectionModel, setPafRowSelectionModel] = useState<GridRowSelectionModel>([]) | |||||
const pafSubmitDisable = useMemo(() => { | |||||
// console.log("%c mode: ", "background:#90EE90; color:red", Object.entries(pafRowModesModel)) | |||||
// console.log("%c mode: ", "background:pink; color:#87CEEB", Object.entries(pafRowModesModel)) | |||||
return Object.entries(pafRowModesModel).length > 0 || Object.entries(pafRowModesModel).some(([key, value], index) => value.mode === GridRowModes.Edit) | |||||
}, [pafRowModesModel]) | |||||
// Putaway submission handler | |||||
const onSubmitPutaway = useCallback<SubmitHandler<ModalFormInput>>( | |||||
async (data, event) => { | |||||
// console.log("Putaway Submission:", event!.nativeEvent); | |||||
// console.log(data.putAwayLines) | |||||
// console.log(data.putAwayLines?.filter((line) => line._isNew !== false)) | |||||
// Extract only putaway related fields | |||||
const putawayData = { | |||||
// putawayLine: data.putawayLine, | |||||
// putawayLocation: data.putawayLocation, | |||||
// binLocation: data.binLocation, | |||||
// putawayQuantity: data.putawayQuantity, | |||||
// putawayNotes: data.putawayNotes, | |||||
acceptQty: Number(data.acceptQty?? (itemDetail.demandQty?? (itemDetail.acceptedQty))), //TODO improve | |||||
warehouseId: data.warehouseId, | |||||
status: data.status, //TODO Fix it! | |||||
// ...data, | |||||
dnDate : data.dnDate? arrayToDateString(data.dnDate, "input") : dayjsToInputDateString(dayjs()), | |||||
productionDate : arrayToDateString(data.productionDate, "input"), | |||||
expiryDate : arrayToDateString(data.expiryDate, "input"), | |||||
receiptDate : arrayToDateString(data.receiptDate, "input"), | |||||
// for putaway data | |||||
inventoryLotLines: data.putAwayLines?.filter((line) => line._isNew !== false) | |||||
// Add other putaway specific fields | |||||
} as ModalFormInput; | |||||
console.log("Putaway Data:", putawayData); | |||||
console.log("DEBUG",data.putAwayLines); | |||||
if (data.putAwayLines!!.filter((line) => line._isNew !== false).length <= 0) { | |||||
alert("請新增上架資料!"); | |||||
return; | |||||
} | |||||
if (data.putAwayLines!!.filter((line) => /[^0-9]/.test(String(line.qty))).length > 0) { //TODO Improve | |||||
alert("上架數量不正確!"); | |||||
return; | |||||
} | |||||
if (data.putAwayLines!!.reduce((acc, cur) => acc + Number(cur.qty), 0) > putawayData.acceptQty!!) { | |||||
alert(`上架數量不能大於 ${putawayData.acceptQty}!`); | |||||
return; | |||||
} | |||||
// Handle putaway submission logic here | |||||
const res = await postStockInLine(putawayData); | |||||
console.log("result ", res); | |||||
// Close modal after successful putaway | |||||
closeHandler({}, "backdropClick"); | |||||
}, | |||||
[closeHandler], | |||||
); | |||||
// Print handler | |||||
const [isPrinting, setIsPrinting] = useState(false) | |||||
const handlePrint = useCallback(async () => { | |||||
// console.log("Print putaway documents"); | |||||
console.log("%c data", "background: white; color: red", formProps.watch("putAwayLines")); | |||||
// Handle print logic here | |||||
// window.print(); | |||||
// const postData = { stockInLineIds: [itemDetail.id]}; | |||||
// const response = await fetchPoQrcode(postData); | |||||
// if (response) { | |||||
// downloadFile(new Uint8Array(response.blobValue), response.filename) | |||||
// } | |||||
try { | |||||
setIsPrinting(() => true) | |||||
if ((formProps.watch("putAwayLines") ?? []).filter((line) => /[^0-9]/.test(String(line.printQty))).length > 0) { //TODO Improve | |||||
alert("列印數量不正確!"); | |||||
return; | |||||
} | |||||
// console.log(pafRowSelectionModel) | |||||
const printList = formProps.watch("putAwayLines")?.filter((line) => ((pafRowSelectionModel ?? []).some((model) => model === line.id))) ?? [] | |||||
const printQty = printList.reduce((acc, cur) => acc + cur.printQty, 0) | |||||
// console.log(printQty) | |||||
const data: PrintQrCodeForSilRequest = { | |||||
stockInLineId: itemDetail.id, | |||||
printerId: selectedPrinter.id, | |||||
printQty: printQty | |||||
} | |||||
const response = await printQrCodeForSil(data); | |||||
if (response) { | |||||
console.log(response) | |||||
} | |||||
} finally { | |||||
setIsPrinting(() => false) | |||||
} | |||||
}, [itemDetail.id, pafRowSelectionModel]); | |||||
const acceptQty = formProps.watch("acceptedQty") | |||||
const checkQcIsPassed = useCallback((qcItems: PurchaseQcResult[]) => { | |||||
const isPassed = qcItems.every((qc) => qc.qcPassed); | |||||
console.log(isPassed) | |||||
if (isPassed) { | |||||
formProps.setValue("passingQty", acceptQty) | |||||
} else { | |||||
formProps.setValue("passingQty", 0) | |||||
} | |||||
return isPassed | |||||
}, [acceptQty, formProps]) | |||||
// useEffect(() => { | |||||
// // maybe check if submitted before | |||||
// console.log("Modal QC Items updated:", qcItems); | |||||
// // checkQcIsPassed(qcItems) | |||||
// }, [qcItems, checkQcIsPassed]) | |||||
return ( | |||||
<> | |||||
<FormProvider {...formProps}> | |||||
<Modal open={open} onClose={closeHandler}> | |||||
<Box | |||||
sx={{ | |||||
...style, | |||||
padding: 2, | |||||
maxHeight: "90vh", | |||||
overflowY: "auto", | |||||
marginLeft: 3, | |||||
marginRight: 3, | |||||
}} | |||||
> | |||||
{openPutaway ? ( | |||||
<Box | |||||
component="form" | |||||
onSubmit={formProps.handleSubmit(onSubmitPutaway)} | |||||
> | |||||
<PutAwayForm | |||||
itemDetail={itemDetail} | |||||
warehouse={warehouse!} | |||||
disabled={viewOnly} | |||||
setRowModesModel={setPafRowModesModel} | |||||
setRowSelectionModel={setPafRowSelectionModel} | |||||
/> | |||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
<Autocomplete | |||||
disableClearable | |||||
options={printerCombo} | |||||
defaultValue={selectedPrinter} | |||||
onChange={(event, value) => { | |||||
setSelectedPrinter(value) | |||||
}} | |||||
renderInput={(params) => ( | |||||
<TextField | |||||
{...params} | |||||
variant="outlined" | |||||
label={t("Printer")} | |||||
sx={{ width: 300}} | |||||
/> | |||||
)} | |||||
/> | |||||
<Button | |||||
id="printButton" | |||||
type="button" | |||||
variant="contained" | |||||
color="primary" | |||||
sx={{ mt: 1 }} | |||||
onClick={handlePrint} | |||||
disabled={isPrinting || printerCombo.length <= 0 || pafSubmitDisable} | |||||
> | |||||
{isPrinting ? t("Printing") : t("print")} | |||||
</Button> | |||||
<Button | |||||
id="putawaySubmit" | |||||
type="submit" | |||||
variant="contained" | |||||
color="primary" | |||||
sx={{ mt: 1 }} | |||||
onClick={formProps.handleSubmit(onSubmitPutaway)} | |||||
disabled={pafSubmitDisable} | |||||
> | |||||
{t("confirm putaway")} | |||||
</Button> | |||||
</Stack> | |||||
</Box> | |||||
) : ( | |||||
<> | |||||
<Grid | |||||
container | |||||
justifyContent="flex-start" | |||||
alignItems="flex-start" | |||||
> | |||||
<Grid item xs={12}> | |||||
<Typography variant="h6" display="block" marginBlockEnd={1}> | |||||
{t("qc processing")} | |||||
</Typography> | |||||
</Grid> | |||||
<Grid item xs={12}> | |||||
<StockInForm itemDetail={itemDetail} disabled={viewOnly} /> | |||||
</Grid> | |||||
</Grid> | |||||
{/* <Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
<Button | |||||
id="stockInSubmit" | |||||
type="button" | |||||
variant="contained" | |||||
color="primary" | |||||
onClick={formProps.handleSubmit(onSubmitStockIn)} | |||||
> | |||||
{t("submitStockIn")} | |||||
</Button> | |||||
</Stack> */} | |||||
<Grid | |||||
container | |||||
justifyContent="flex-start" | |||||
alignItems="flex-start" | |||||
> | |||||
<QcComponent | |||||
// qc={qc!} | |||||
itemDetail={itemDetail} | |||||
disabled={viewOnly} | |||||
// qcItems={qcItems} | |||||
// setQcItems={setQcItems} | |||||
/> | |||||
</Grid> | |||||
<Stack direction="row" justifyContent="flex-end" gap={1}> | |||||
{!viewOnly && (<Button | |||||
id="qcSubmit" | |||||
type="button" | |||||
variant="contained" | |||||
color="primary" | |||||
sx={{ mt: 1 }} | |||||
onClick={formProps.handleSubmit(onSubmitQc, onSubmitErrorQc)} | |||||
> | |||||
{t("confirm qc result")} | |||||
</Button>)} | |||||
</Stack> | |||||
</> | |||||
)} | |||||
</Box> | |||||
</Modal> | |||||
</FormProvider> | |||||
</> | |||||
); | |||||
}; | |||||
export default PoQcStockInModalVer2; |
@@ -44,6 +44,7 @@ interface Props { | |||||
itemDetail: StockInLine; | itemDetail: StockInLine; | ||||
// qc: QcItemWithChecks[]; | // qc: QcItemWithChecks[]; | ||||
disabled: boolean; | disabled: boolean; | ||||
putawayMode?: boolean; | |||||
} | } | ||||
type EntryError = | type EntryError = | ||||
| { | | { | ||||
@@ -57,6 +58,7 @@ const StockInForm: React.FC<Props> = ({ | |||||
// qc, | // qc, | ||||
itemDetail, | itemDetail, | ||||
disabled, | disabled, | ||||
putawayMode = false, | |||||
}) => { | }) => { | ||||
const { | const { | ||||
t, | t, | ||||
@@ -75,36 +77,51 @@ const StockInForm: React.FC<Props> = ({ | |||||
setError, | setError, | ||||
clearErrors, | clearErrors, | ||||
} = useFormContext<StockInInput>(); | } = useFormContext<StockInInput>(); | ||||
console.log(itemDetail); | |||||
// console.log(itemDetail); | |||||
useEffect(() => { | useEffect(() => { | ||||
console.log("triggered"); | |||||
// receiptDate default tdy | |||||
setValue("receiptDate", dayjs().add(0, "month").format(INPUT_DATE_FORMAT)); | |||||
setValue("status", "received"); | |||||
// console.log("triggered"); | |||||
// // receiptDate default tdy | |||||
// setValue("receiptDate", dayjs().add(0, "month").format(INPUT_DATE_FORMAT)); | |||||
// setValue("status", "received"); | |||||
}, [setValue]); | }, [setValue]); | ||||
useEffect(() => { | useEffect(() => { | ||||
console.log(errors); | console.log(errors); | ||||
}, [errors]); | }, [errors]); | ||||
const productionDate = watch("productionDate"); | const productionDate = watch("productionDate"); | ||||
const expiryDate = watch("expiryDate"); | const expiryDate = watch("expiryDate"); | ||||
const uom = watch("uom"); | |||||
//// TODO : Add Checking //// | |||||
// Check if dates are input | |||||
// if (data.productionDate === undefined || data.productionDate == null) { | |||||
// validationErrors.push("請輸入生產日期!"); | |||||
// } | |||||
// if (data.expiryDate === undefined || data.expiryDate == null) { | |||||
// validationErrors.push("請輸入到期日!"); | |||||
// } | |||||
useEffect(() => { | useEffect(() => { | ||||
console.log(productionDate); | |||||
console.log(expiryDate); | |||||
// console.log(uom); | |||||
// console.log(productionDate); | |||||
// console.log(expiryDate); | |||||
if (expiryDate) clearErrors(); | if (expiryDate) clearErrors(); | ||||
if (productionDate) clearErrors(); | if (productionDate) clearErrors(); | ||||
}, [productionDate, expiryDate, clearErrors]); | }, [productionDate, expiryDate, clearErrors]); | ||||
useEffect(() => { | |||||
console.log("%c StockInForm itemDetail update: ", "color: brown", itemDetail); | |||||
}, [itemDetail]); | |||||
return ( | return ( | ||||
<Grid container justifyContent="flex-start" alignItems="flex-start"> | <Grid container justifyContent="flex-start" alignItems="flex-start"> | ||||
<Grid item xs={12}> | |||||
{/* <Grid item xs={12}> | |||||
<Typography variant="h6" display="block" marginBlockEnd={1}> | <Typography variant="h6" display="block" marginBlockEnd={1}> | ||||
{t("Stock In Detail")} | {t("Stock In Detail")} | ||||
</Typography> | </Typography> | ||||
</Grid> | |||||
</Grid> */} | |||||
<Grid | <Grid | ||||
container | container | ||||
justifyContent="flex-start" | justifyContent="flex-start" | ||||
@@ -126,89 +143,91 @@ const StockInForm: React.FC<Props> = ({ | |||||
</Grid> | </Grid> | ||||
<Grid item xs={6}> | <Grid item xs={6}> | ||||
<TextField | <TextField | ||||
label={t("invoiceNo")} | |||||
label={t("itemName")} | |||||
fullWidth | fullWidth | ||||
{...register("invoiceNo", { | |||||
{...register("itemName", { | |||||
// required: "productLotNo required!", | // required: "productLotNo required!", | ||||
})} | })} | ||||
disabled={disabled} | |||||
disabled={true} | |||||
// error={Boolean(errors.productLotNo)} | // error={Boolean(errors.productLotNo)} | ||||
// helperText={errors.productLotNo?.message} | // helperText={errors.productLotNo?.message} | ||||
/> | /> | ||||
</Grid> | </Grid> | ||||
<Grid item xs={4}> | |||||
<Grid item xs={6}> | |||||
<TextField | <TextField | ||||
label={t("productLotNo")} | |||||
label={t("PO No.")} | |||||
fullWidth | fullWidth | ||||
{...register("productLotNo", { | |||||
{...register("poCode", { | |||||
// required: "productLotNo required!", | // required: "productLotNo required!", | ||||
})} | })} | ||||
disabled={disabled} | |||||
error={Boolean(errors.productLotNo)} | |||||
helperText={errors.productLotNo?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={4}> | |||||
<Controller | |||||
control={control} | |||||
name="receiptDate" | |||||
rules={{ required: true }} | |||||
render={({ field }) => { | |||||
return ( | |||||
<LocalizationProvider | |||||
dateAdapter={AdapterDayjs} | |||||
adapterLocale={`${language}-hk`} | |||||
> | |||||
<DatePicker | |||||
{...field} | |||||
sx={{ width: "100%" }} | |||||
label={t("receiptDate")} | |||||
value={dayjs(watch("receiptDate"))} | |||||
disabled={disabled} | |||||
onChange={(date) => { | |||||
if (!date) return; | |||||
// setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); | |||||
field.onChange(date); | |||||
}} | |||||
inputRef={field.ref} | |||||
slotProps={{ | |||||
textField: { | |||||
// required: true, | |||||
error: Boolean(errors.receiptDate?.message), | |||||
helperText: errors.receiptDate?.message, | |||||
}, | |||||
}} | |||||
/> | |||||
</LocalizationProvider> | |||||
); | |||||
}} | |||||
disabled={true} | |||||
// error={Boolean(errors.productLotNo)} | |||||
// helperText={errors.productLotNo?.message} | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
<Grid item xs={4}> | |||||
{putawayMode || ( | |||||
<> | |||||
<Grid item xs={6}> | |||||
<Controller | |||||
control={control} | |||||
name="receiptDate" | |||||
rules={{ required: true }} | |||||
render={({ field }) => { | |||||
return ( | |||||
<LocalizationProvider | |||||
dateAdapter={AdapterDayjs} | |||||
adapterLocale={`${language}-hk`} | |||||
> | |||||
<DatePicker | |||||
{...field} | |||||
sx={{ width: "100%" }} | |||||
label={t("receiptDate")} | |||||
value={dayjs(watch("receiptDate"))} | |||||
disabled={true} | |||||
onChange={(date) => { | |||||
if (!date) return; | |||||
// setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); | |||||
field.onChange(date); | |||||
}} | |||||
inputRef={field.ref} | |||||
slotProps={{ | |||||
textField: { | |||||
// required: true, | |||||
error: Boolean(errors.receiptDate?.message), | |||||
helperText: errors.receiptDate?.message, | |||||
}, | |||||
}} | |||||
/> | |||||
</LocalizationProvider> | |||||
); | |||||
}} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("Supplier")} | |||||
fullWidth | |||||
{...register("supplier", { | |||||
// required: "productLotNo required!", | |||||
})} | |||||
disabled={true} | |||||
/> | |||||
</Grid> | |||||
</> | |||||
)} | |||||
<Grid item xs={6}> | |||||
<TextField | <TextField | ||||
label={t("acceptedQty")} | |||||
label={t("productLotNo")} | |||||
fullWidth | fullWidth | ||||
{...register("acceptedQty", { | |||||
required: "acceptedQty required!", | |||||
{...register("productLotNo", { | |||||
// required: "productLotNo required!", | |||||
})} | })} | ||||
disabled={disabled} | disabled={disabled} | ||||
error={Boolean(errors.acceptedQty)} | |||||
helperText={errors.acceptedQty?.message} | |||||
error={Boolean(errors.productLotNo)} | |||||
helperText={errors.productLotNo?.message} | |||||
/> | /> | ||||
</Grid> | </Grid> | ||||
{/* <Grid item xs={4}> | |||||
<TextField | |||||
label={t("acceptedWeight")} | |||||
fullWidth | |||||
// {...register("acceptedWeight", { | |||||
// required: "acceptedWeight required!", | |||||
// })} | |||||
disabled={disabled} | |||||
error={Boolean(errors.acceptedWeight)} | |||||
helperText={errors.acceptedWeight?.message} | |||||
/> | |||||
</Grid> */} | |||||
<Grid item xs={4}> | |||||
<Grid item xs={6}> | |||||
<Controller | <Controller | ||||
control={control} | control={control} | ||||
name="productionDate" | name="productionDate" | ||||
@@ -247,7 +266,19 @@ const StockInForm: React.FC<Props> = ({ | |||||
}} | }} | ||||
/> | /> | ||||
</Grid> | </Grid> | ||||
<Grid item xs={4}> | |||||
{putawayMode || ( | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("qty")} | |||||
fullWidth | |||||
{...register("qty", { | |||||
required: "qty required!", | |||||
})} | |||||
disabled={true} | |||||
/> | |||||
</Grid> | |||||
)} | |||||
<Grid item xs={6}> | |||||
<Controller | <Controller | ||||
control={control} | control={control} | ||||
name="expiryDate" | name="expiryDate" | ||||
@@ -265,7 +296,6 @@ const StockInForm: React.FC<Props> = ({ | |||||
value={expiryDate ? dayjs(expiryDate) : undefined} | value={expiryDate ? dayjs(expiryDate) : undefined} | ||||
disabled={disabled} | disabled={disabled} | ||||
onChange={(date) => { | onChange={(date) => { | ||||
console.log(date); | |||||
if (!date) return; | if (!date) return; | ||||
console.log(date.format(INPUT_DATE_FORMAT)); | console.log(date.format(INPUT_DATE_FORMAT)); | ||||
setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); | setValue("expiryDate", date.format(INPUT_DATE_FORMAT)); | ||||
@@ -285,6 +315,55 @@ const StockInForm: React.FC<Props> = ({ | |||||
}} | }} | ||||
/> | /> | ||||
</Grid> | </Grid> | ||||
{putawayMode || ( | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("receivedQty")} | |||||
fullWidth | |||||
{...register("receivedQty", { | |||||
required: "receivedQty required!", | |||||
})} | |||||
disabled={true} | |||||
/> | |||||
</Grid> | |||||
)} | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("uom")} | |||||
fullWidth | |||||
{...register("uom.code", { | |||||
required: "uom required!", | |||||
})} | |||||
// value={uom?.code} | |||||
disabled={true} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("acceptedQty")} | |||||
fullWidth | |||||
disabled={true} | |||||
{...register("acceptedQty", { | |||||
required: "acceptedQty required!", | |||||
})} | |||||
// disabled={true} | |||||
// disabled={disabled} | |||||
// error={Boolean(errors.acceptedQty)} | |||||
// helperText={errors.acceptedQty?.message} | |||||
/> | |||||
</Grid> | |||||
{/* <Grid item xs={4}> | |||||
<TextField | |||||
label={t("acceptedWeight")} | |||||
fullWidth | |||||
// {...register("acceptedWeight", { | |||||
// required: "acceptedWeight required!", | |||||
// })} | |||||
disabled={disabled} | |||||
error={Boolean(errors.acceptedWeight)} | |||||
helperText={errors.acceptedWeight?.message} | |||||
/> | |||||
</Grid> */} | |||||
</Grid> | </Grid> | ||||
<Grid | <Grid | ||||
container | container | ||||
@@ -0,0 +1,309 @@ | |||||
"use client"; | |||||
import { | |||||
PurchaseQcResult, | |||||
PurchaseQCInput, | |||||
StockInInput, | |||||
} from "@/app/api/po/actions"; | |||||
import { | |||||
Box, | |||||
Card, | |||||
CardContent, | |||||
Grid, | |||||
Stack, | |||||
TextField, | |||||
Tooltip, | |||||
Typography, | |||||
} 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 { | |||||
GridColDef, | |||||
GridRowIdGetter, | |||||
GridRowModel, | |||||
useGridApiContext, | |||||
GridRenderCellParams, | |||||
GridRenderEditCellParams, | |||||
useGridApiRef, | |||||
} from "@mui/x-data-grid"; | |||||
import InputDataGrid from "../InputDataGrid"; | |||||
import { TableRow } from "../InputDataGrid/InputDataGrid"; | |||||
import TwoLineCell from "./TwoLineCell"; | |||||
import QcSelect from "./QcSelect"; | |||||
import { QcItemWithChecks } from "@/app/api/qc"; | |||||
import { GridEditInputCell } from "@mui/x-data-grid"; | |||||
import { StockInLine } from "@/app/api/po"; | |||||
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; | |||||
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | |||||
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; | |||||
import dayjs from "dayjs"; | |||||
// change PurchaseQcResult to stock in entry props | |||||
interface Props { | |||||
itemDetail: StockInLine; | |||||
// qc: QcItemWithChecks[]; | |||||
disabled: boolean; | |||||
} | |||||
type EntryError = | |||||
| { | |||||
[field in keyof StockInInput]?: string; | |||||
} | |||||
| undefined; | |||||
// type PoQcRow = TableRow<Partial<PurchaseQcResult>, EntryError>; | |||||
const StockInFormOld: React.FC<Props> = ({ | |||||
// qc, | |||||
itemDetail, | |||||
disabled, | |||||
}) => { | |||||
const { | |||||
t, | |||||
i18n: { language }, | |||||
} = useTranslation("purchaseOrder"); | |||||
const apiRef = useGridApiRef(); | |||||
const { | |||||
register, | |||||
formState: { errors, defaultValues, touchedFields }, | |||||
watch, | |||||
control, | |||||
setValue, | |||||
getValues, | |||||
reset, | |||||
resetField, | |||||
setError, | |||||
clearErrors, | |||||
} = useFormContext<StockInInput>(); | |||||
console.log(itemDetail); | |||||
useEffect(() => { | |||||
console.log("triggered"); | |||||
// receiptDate default tdy | |||||
setValue("receiptDate", dayjs().add(0, "month").format(INPUT_DATE_FORMAT)); | |||||
setValue("status", "received"); | |||||
}, [setValue]); | |||||
useEffect(() => { | |||||
console.log(errors); | |||||
}, [errors]); | |||||
const productionDate = watch("productionDate"); | |||||
const expiryDate = watch("expiryDate"); | |||||
useEffect(() => { | |||||
console.log(productionDate); | |||||
console.log(expiryDate); | |||||
if (expiryDate) clearErrors(); | |||||
if (productionDate) clearErrors(); | |||||
}, [productionDate, expiryDate, clearErrors]); | |||||
return ( | |||||
<Grid container justifyContent="flex-start" alignItems="flex-start"> | |||||
<Grid item xs={12}> | |||||
<Typography variant="h6" display="block" marginBlockEnd={1}> | |||||
{t("Stock In Detail")} | |||||
</Typography> | |||||
</Grid> | |||||
<Grid | |||||
container | |||||
justifyContent="flex-start" | |||||
alignItems="flex-start" | |||||
spacing={2} | |||||
sx={{ mt: 0.5 }} | |||||
> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("dnNo")} | |||||
fullWidth | |||||
{...register("dnNo", { | |||||
// required: "productLotNo required!", | |||||
})} | |||||
disabled={disabled} | |||||
// error={Boolean(errors.productLotNo)} | |||||
// helperText={errors.productLotNo?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={6}> | |||||
<TextField | |||||
label={t("invoiceNo")} | |||||
fullWidth | |||||
{...register("invoiceNo", { | |||||
// required: "productLotNo required!", | |||||
})} | |||||
disabled={disabled} | |||||
// error={Boolean(errors.productLotNo)} | |||||
// helperText={errors.productLotNo?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={4}> | |||||
<TextField | |||||
label={t("productLotNo")} | |||||
fullWidth | |||||
{...register("productLotNo", { | |||||
// required: "productLotNo required!", | |||||
})} | |||||
disabled={disabled} | |||||
error={Boolean(errors.productLotNo)} | |||||
helperText={errors.productLotNo?.message} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={4}> | |||||
<Controller | |||||
control={control} | |||||
name="receiptDate" | |||||
rules={{ required: true }} | |||||
render={({ field }) => { | |||||
return ( | |||||
<LocalizationProvider | |||||
dateAdapter={AdapterDayjs} | |||||
adapterLocale={`${language}-hk`} | |||||
> | |||||
<DatePicker | |||||
{...field} | |||||
sx={{ width: "100%" }} | |||||
label={t("receiptDate")} | |||||
value={dayjs(watch("receiptDate"))} | |||||
disabled={disabled} | |||||
onChange={(date) => { | |||||
if (!date) return; | |||||
// setValue("receiptDate", date.format(INPUT_DATE_FORMAT)); | |||||
field.onChange(date); | |||||
}} | |||||
inputRef={field.ref} | |||||
slotProps={{ | |||||
textField: { | |||||
// required: true, | |||||
error: Boolean(errors.receiptDate?.message), | |||||
helperText: errors.receiptDate?.message, | |||||
}, | |||||
}} | |||||
/> | |||||
</LocalizationProvider> | |||||
); | |||||
}} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={4}> | |||||
<TextField | |||||
label={t("acceptedQty")} | |||||
fullWidth | |||||
{...register("acceptedQty", { | |||||
required: "acceptedQty required!", | |||||
})} | |||||
disabled={disabled} | |||||
error={Boolean(errors.acceptedQty)} | |||||
helperText={errors.acceptedQty?.message} | |||||
/> | |||||
</Grid> | |||||
{/* <Grid item xs={4}> | |||||
<TextField | |||||
label={t("acceptedWeight")} | |||||
fullWidth | |||||
// {...register("acceptedWeight", { | |||||
// required: "acceptedWeight required!", | |||||
// })} | |||||
disabled={disabled} | |||||
error={Boolean(errors.acceptedWeight)} | |||||
helperText={errors.acceptedWeight?.message} | |||||
/> | |||||
</Grid> */} | |||||
<Grid item xs={4}> | |||||
<Controller | |||||
control={control} | |||||
name="productionDate" | |||||
// rules={{ required: !Boolean(expiryDate) }} | |||||
render={({ field }) => { | |||||
return ( | |||||
<LocalizationProvider | |||||
dateAdapter={AdapterDayjs} | |||||
adapterLocale={`${language}-hk`} | |||||
> | |||||
<DatePicker | |||||
{...field} | |||||
sx={{ width: "100%" }} | |||||
label={t("productionDate")} | |||||
value={productionDate ? dayjs(productionDate) : undefined} | |||||
disabled={disabled} | |||||
onChange={(date) => { | |||||
if (!date) return; | |||||
setValue( | |||||
"productionDate", | |||||
date.format(INPUT_DATE_FORMAT), | |||||
); | |||||
// field.onChange(date); | |||||
}} | |||||
inputRef={field.ref} | |||||
slotProps={{ | |||||
textField: { | |||||
// required: true, | |||||
error: Boolean(errors.productionDate?.message), | |||||
helperText: errors.productionDate?.message, | |||||
}, | |||||
}} | |||||
/> | |||||
</LocalizationProvider> | |||||
); | |||||
}} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={4}> | |||||
<Controller | |||||
control={control} | |||||
name="expiryDate" | |||||
// rules={{ required: !Boolean(productionDate) }} | |||||
render={({ field }) => { | |||||
return ( | |||||
<LocalizationProvider | |||||
dateAdapter={AdapterDayjs} | |||||
adapterLocale={`${language}-hk`} | |||||
> | |||||
<DatePicker | |||||
{...field} | |||||
sx={{ width: "100%" }} | |||||
label={t("expiryDate")} | |||||
value={expiryDate ? dayjs(expiryDate) : undefined} | |||||
disabled={disabled} | |||||
onChange={(date) => { | |||||
console.log(date); | |||||
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, | |||||
}, | |||||
}} | |||||
/> | |||||
</LocalizationProvider> | |||||
); | |||||
}} | |||||
/> | |||||
</Grid> | |||||
</Grid> | |||||
<Grid | |||||
container | |||||
justifyContent="flex-start" | |||||
alignItems="flex-start" | |||||
spacing={2} | |||||
sx={{ mt: 0.5 }} | |||||
> | |||||
{/* <Grid item xs={12}> | |||||
<InputDataGrid<PurchaseQCInput, PurchaseQcResult, EntryError> | |||||
apiRef={apiRef} | |||||
checkboxSelection={false} | |||||
_formKey={"qcCheck"} | |||||
columns={columns} | |||||
validateRow={validationTest} | |||||
/> | |||||
</Grid> */} | |||||
</Grid> | |||||
</Grid> | |||||
); | |||||
}; | |||||
export default StockInFormOld; |