From 37ed4d31aa288d7d2efd1dd1ff642d3d235b59e3 Mon Sep 17 00:00:00 2001 From: "cyril.tsui" Date: Wed, 27 Aug 2025 20:41:28 +0800 Subject: [PATCH] update putaway --- src/app/(main)/po/edit/page.tsx | 2 + src/app/api/po/actions.ts | 34 ++++-- src/app/api/po/index.ts | 2 + src/app/api/settings/printer/index.ts | 21 ++++ src/app/api/warehouse/index.ts | 12 +++ .../InputDataGrid/InputDataGrid.tsx | 23 ++-- .../PickOrderSearch/PutawayForm.tsx | 14 +-- .../PickOrderSearch/dummyQcTemplate.tsx | 4 +- .../PickOrderSearch/pickorderModelVer2.tsx | 2 +- src/components/PoDetail/PoDetail.tsx | 5 +- src/components/PoDetail/PoDetailWrapper.tsx | 7 +- src/components/PoDetail/PoInputGrid.tsx | 8 +- src/components/PoDetail/PoQcStockInModal.tsx | 4 +- src/components/PoDetail/PutawayForm.tsx | 61 +++++++++-- .../PoDetail/QcStockInModalVer2.tsx | 100 ++++++++++++++---- src/components/PoDetail/QrModal.tsx | 4 +- src/components/PoDetail/dummyQcTemplate.tsx | 6 +- src/i18n/zh/purchaseOrder.json | 4 +- 18 files changed, 244 insertions(+), 69 deletions(-) create mode 100644 src/app/api/settings/printer/index.ts diff --git a/src/app/(main)/po/edit/page.tsx b/src/app/(main)/po/edit/page.tsx index c9b0b72..d2fcbfd 100644 --- a/src/app/(main)/po/edit/page.tsx +++ b/src/app/(main)/po/edit/page.tsx @@ -1,3 +1,4 @@ +import { fetchPrinterCombo } from "@/app/api/settings/printer"; import { fetchEscalationCombo } from "@/app/api/user"; import { SearchParams } from "@/app/utils/fetchUtil"; import { TypeEnum } from "@/app/utils/typeEnum"; @@ -25,6 +26,7 @@ const PoEdit: React.FC = async ({ searchParams }) => { } fetchEscalationCombo() + fetchPrinterCombo() return ( <> diff --git a/src/app/api/po/actions.ts b/src/app/api/po/actions.ts index 5956b2b..c91d50b 100644 --- a/src/app/api/po/actions.ts +++ b/src/app/api/po/actions.ts @@ -6,10 +6,11 @@ import { revalidateTag } from "next/cache"; import { cache } from "react"; import { PoResult, StockInLine } from "."; //import { serverFetchJson } from "@/app/utils/fetchUtil"; -import { serverFetchJson } from "../../utils/fetchUtil"; +import { serverFetchJson, serverFetchWithNoContent } from "../../utils/fetchUtil"; import { QcItemResult } from "../settings/qcItem"; import { RecordsRes } from "../utils"; import { Uom } from "../settings/uom"; +import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; // import { BASE_API_URL } from "@/config/api"; export interface PostStockInLineResponse { @@ -81,26 +82,34 @@ export interface EscalationInput { acceptedQty?: number; // this is the qty to be escalated // escalationQty: number } -export interface PutawayLine { +export interface PutAwayLine { id?: number qty: number warehouseId: number; warehouse: string; - printQty: number + printQty: number; + _isNew?: boolean; + printQty?: number; } -export interface PutawayInput { +export interface PutAwayInput { status: string; acceptedQty: number; warehouseId: number; - putawayLine: PutawayLine[] + putAwayLines: PutAwayLine[] } export type ModalFormInput = Partial< - PurchaseQCInput & StockInInput & PutawayInput + PurchaseQCInput & StockInInput & PutAwayInput > & { escalationLog? : Partial }; +export interface PrintQrCodeForSilRequest { + stockInLineId: number; + printerId: number; + printQty?: number; +} + export const testFetch = cache(async (id: number) => { return serverFetchJson(`${BASE_API_URL}/po/detail/${id}`, { next: { tags: ["po"] }, @@ -217,3 +226,16 @@ export const testing = cache(async (queryParams?: Record) => { ); } }); + +export const printQrCodeForSil = cache(async(data: PrintQrCodeForSilRequest) => { + const params = convertObjToURLSearchParams(data) + return serverFetchWithNoContent(`${BASE_API_URL}/stockInLine/printQrCode?${params}`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + next: { + tags: ["printQrCodeForSil"], + }, + }, + ) +}) diff --git a/src/app/api/po/index.ts b/src/app/api/po/index.ts index e56aff8..6e1c3a2 100644 --- a/src/app/api/po/index.ts +++ b/src/app/api/po/index.ts @@ -6,6 +6,7 @@ import { serverFetchJson } from "../../utils/fetchUtil"; import { BASE_API_URL } from "../../../config/api"; import { Uom } from "../settings/uom"; import { RecordsRes } from "../utils"; +import { PutAwayLine } from "./actions"; export interface PoResult { id: number; @@ -82,6 +83,7 @@ export interface StockInLine { dnDate?: number[]; stockQty?: number; handlerId?: number; + putAwayLines?: PutAwayLine[]; } export const fetchPoList = cache(async (queryParams?: Record) => { diff --git a/src/app/api/settings/printer/index.ts b/src/app/api/settings/printer/index.ts new file mode 100644 index 0000000..e443ccd --- /dev/null +++ b/src/app/api/settings/printer/index.ts @@ -0,0 +1,21 @@ +import { serverFetchJson } from '@/app/utils/fetchUtil'; +import { BASE_API_URL } from '@/config/api'; +import { cache } from "react"; +import "server-only"; + +export interface PrinterCombo { + id: number; + value: number; + label?: string; + code?: string; + name?: string; + description?: string; + ip?: string; + port?: number; +} + +export const fetchPrinterCombo = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/printers/combo`, { + next: { tags: ["qcItems"] }, + }) +}) \ No newline at end of file diff --git a/src/app/api/warehouse/index.ts b/src/app/api/warehouse/index.ts index db86d8f..ce560fe 100644 --- a/src/app/api/warehouse/index.ts +++ b/src/app/api/warehouse/index.ts @@ -10,8 +10,20 @@ export interface WarehouseResult { description: string; } +export interface WarehouseCombo { + id: number; + value: number; + label: string; +} + export const fetchWarehouseList = cache(async () => { return serverFetchJson(`${BASE_API_URL}/warehouse`, { next: { tags: ["warehouse"] }, }); }); + +export const fetchWarehouseCombo = cache(async () => { + return serverFetchJson(`${BASE_API_URL}/warehouse/combo`, { + next: { tags: ["warehouseCombo"] }, + }); +}); diff --git a/src/components/InputDataGrid/InputDataGrid.tsx b/src/components/InputDataGrid/InputDataGrid.tsx index b4e9062..622d7e2 100644 --- a/src/components/InputDataGrid/InputDataGrid.tsx +++ b/src/components/InputDataGrid/InputDataGrid.tsx @@ -74,6 +74,7 @@ export interface InputDataGridProps { validateRow: (newRow: GridRowModel>) => E; needAdd?: boolean; showRemoveBtn?: boolean; + addRowDefaultValue?: Partial; } export interface SelectionInputDataGridProps { @@ -85,6 +86,7 @@ export interface SelectionInputDataGridProps { validateRow: (newRow: GridRowModel>) => E; needAdd?: boolean; showRemoveBtn?: boolean; + addRowDefaultValue?: Partial; } export type Props = @@ -112,6 +114,7 @@ function InputDataGrid({ validateRow, needAdd, showRemoveBtn = true, + addRowDefaultValue = {}, }: Props) { const { t, @@ -126,13 +129,13 @@ function InputDataGrid({ [], ); const list: TableRow[] = getValues(formKey); - console.log(list) + // console.log(list) const [rows, setRows] = useState[]>(() => { const list: TableRow[] = getValues(formKey); - console.log(list) + // console.log(list) return list && list.length > 0 ? list : []; }); - console.log(rows) + // console.log(rows) // const originalRows = list && list.length > 0 ? list : []; const originalRows = useMemo(() => ( list && list.length > 0 ? list : [] @@ -145,7 +148,7 @@ function InputDataGrid({ const rowModel: GridRowSelectionModel = getValues( `${formKey}_active`, ) as GridRowSelectionModel; - console.log(rowModel); + // console.log(rowModel); return rowModel; }); @@ -162,7 +165,7 @@ function InputDataGrid({ (updateError: ProcessRowUpdateError) => { const errors = updateError.errors; const row = updateError.row; - console.log(errors); + // console.log(errors); apiRef.current.updateRows([{ ...row, _error: errors }]); }, [apiRef], @@ -176,7 +179,7 @@ function InputDataGrid({ ///////////////// // validation here const errors = validateRow(newRow); - console.log(newRow); + // console.log(newRow); if (errors) { throw new ProcessRowUpdateError( originalRow, @@ -189,7 +192,6 @@ function InputDataGrid({ const rowToSave = { ...updatedRow, } as TableRow; /// test - console.log(rowToSave); setRows((rw) => rw.map((r) => (getRowId(r) === getRowId(originalRow) ? rowToSave : r)), ); @@ -198,8 +200,8 @@ function InputDataGrid({ [validateRow, getRowId], ); - const addRow = useCallback(() => { - const newEntry = { id: Date.now(), _isNew: true } as TableRow; + const addRow = useCallback((addRowDefaultValue: Partial) => { + const newEntry = { ...addRowDefaultValue, id: Date.now(), _isNew: true } as TableRow; setRows((prev) => [...prev, newEntry]); setRowModesModel((model) => ({ ...model, @@ -290,7 +292,6 @@ function InputDataGrid({ // sync useForm useEffect(() => { // console.log(formKey) - // console.log(rows) setValue(formKey, rows); }, [formKey, rows, setValue]); @@ -300,7 +301,7 @@ function InputDataGrid({ disableRipple variant="outlined" startIcon={} - onClick={addRow} + onClick={() => addRow(addRowDefaultValue)} size="small" > 新增 diff --git a/src/components/PickOrderSearch/PutawayForm.tsx b/src/components/PickOrderSearch/PutawayForm.tsx index 75459a7..aea7779 100644 --- a/src/components/PickOrderSearch/PutawayForm.tsx +++ b/src/components/PickOrderSearch/PutawayForm.tsx @@ -1,6 +1,6 @@ "use client"; -import { PurchaseQcResult, PutawayInput, PutawayLine } from "@/app/api/po/actions"; +import { PurchaseQcResult, PutAwayInput, PutAwayLine } from "@/app/api/po/actions"; import { Autocomplete, Box, @@ -61,11 +61,11 @@ interface Props { } type EntryError = | { - [field in keyof PutawayLine]?: string; + [field in keyof PutAwayLine]?: string; } | undefined; -type PutawayRow = TableRow, EntryError>; +type PutawayRow = TableRow, EntryError>; const style = { position: "absolute", @@ -93,7 +93,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { resetField, setError, clearErrors, - } = useFormContext(); + } = useFormContext(); console.log(itemDetail); // const [recordQty, setRecordQty] = useState(0); const [warehouseId, setWarehouseId] = useState(itemDetail.defaultWarehouseId); @@ -143,7 +143,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { }, [], ); - console.log(watch("putawayLine")) + console.log(watch("putAwayLines")) // const accQty = watch("acceptedQty"); // const validateForm = useCallback(() => { // console.log(accQty); @@ -492,10 +492,10 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { style={{ display: "flex", justifyContent: "center" }} > {/* */} - + apiRef={apiRef} checkboxSelection={false} - _formKey={"putawayLine"} + _formKey={"putAwayLines"} columns={columns} validateRow={validation} needAdd={true} diff --git a/src/components/PickOrderSearch/dummyQcTemplate.tsx b/src/components/PickOrderSearch/dummyQcTemplate.tsx index 8f9ab89..fa5ff5d 100644 --- a/src/components/PickOrderSearch/dummyQcTemplate.tsx +++ b/src/components/PickOrderSearch/dummyQcTemplate.tsx @@ -1,4 +1,4 @@ -import { PutawayLine } from "@/app/api/po/actions" +import { PutAwayLine } from "@/app/api/po/actions" export interface QcData { id: number, @@ -67,7 +67,7 @@ export const dummyEscalationHistory: EscalationData[] = [ }, ] -export const dummyPutawayLine: PutawayLine[] = [ +export const dummyPutawayLine: PutAwayLine[] = [ { id: 1, qty: 100, diff --git a/src/components/PickOrderSearch/pickorderModelVer2.tsx b/src/components/PickOrderSearch/pickorderModelVer2.tsx index b95a819..1294f1d 100644 --- a/src/components/PickOrderSearch/pickorderModelVer2.tsx +++ b/src/components/PickOrderSearch/pickorderModelVer2.tsx @@ -80,7 +80,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) const formProps = useForm({ defaultValues: { ...itemDetail, - putawayLine: dummyPutawayLine, + putAwayLine: dummyPutawayLine, // receiptDate: itemDetail.receiptDate || dayjs().add(-1, "month").format(INPUT_DATE_FORMAT), // warehouseId: itemDetail.defaultWarehouseId || 0 }, diff --git a/src/components/PoDetail/PoDetail.tsx b/src/components/PoDetail/PoDetail.tsx index fdf737d..e02d92a 100644 --- a/src/components/PoDetail/PoDetail.tsx +++ b/src/components/PoDetail/PoDetail.tsx @@ -79,6 +79,7 @@ import { DatePicker, LocalizationProvider, zhHK } from "@mui/x-date-pickers"; import { debounce } from "lodash"; import LoadingComponent from "../General/LoadingComponent"; import { getMailTemplateForStockInLine } from "@/app/api/mailTemplate/actions"; +import { PrinterCombo } from "@/app/api/settings/printer"; //import { useRouter } from "next/navigation"; @@ -86,6 +87,7 @@ type Props = { po: PoResult; qc: QcItemWithChecks[]; warehouse: WarehouseResult[]; + printerCombo: PrinterCombo[]; }; type EntryError = @@ -188,7 +190,7 @@ interface PolInputResult { dnQty: number, } -const PoDetail: React.FC = ({ po, qc, warehouse }) => { +const PoDetail: React.FC = ({ po, qc, warehouse, printerCombo }) => { const cameras = useContext(CameraContext); // console.log(cameras); const { t } = useTranslation("purchaseOrder"); @@ -858,6 +860,7 @@ const PoDetail: React.FC = ({ po, qc, warehouse }) => { warehouse={warehouse} fetchPoDetail={fetchPoDetail} handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} + printerCombo={printerCombo} /> diff --git a/src/components/PoDetail/PoDetailWrapper.tsx b/src/components/PoDetail/PoDetailWrapper.tsx index 3cc27c6..5f48943 100644 --- a/src/components/PoDetail/PoDetailWrapper.tsx +++ b/src/components/PoDetail/PoDetailWrapper.tsx @@ -11,6 +11,7 @@ import { QcItemWithChecks } from "@/app/api/qc"; import { fetchWarehouseList } from "@/app/api/warehouse"; import { fetchQcItemCheck } from "@/app/api/qc/actions"; import { fetchEscalationCombo } from "@/app/api/user"; +import { fetchPrinterCombo } from "@/app/api/settings/printer"; interface SubComponents { Loading: typeof PoDetailLoading; @@ -25,16 +26,18 @@ const PoDetailWrapper: React.FC & SubComponents = async ({ id }) => { poWithStockInLine, warehouse, qc, - escalationCombo + escalationCombo, + printerCombo, ] = await Promise.all([ fetchPoWithStockInLines(id), fetchWarehouseList(), fetchQcItemCheck(), fetchEscalationCombo(), + fetchPrinterCombo() ]); // const poWithStockInLine = await fetchPoWithStockInLines(id) - return ; + return ; }; PoDetailWrapper.Loading = PoDetailLoading; diff --git a/src/components/PoDetail/PoInputGrid.tsx b/src/components/PoDetail/PoInputGrid.tsx index 2e739ca..80072c4 100644 --- a/src/components/PoDetail/PoInputGrid.tsx +++ b/src/components/PoDetail/PoInputGrid.tsx @@ -62,6 +62,7 @@ import { useSession } from "next-auth/react"; // import { SessionWithTokens } from "src/config/authConfig"; import PoQcStockInModalVer2 from "./QcStockInModalVer2"; import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; +import { PrinterCombo } from "@/app/api/settings/printer"; import { EscalationResult } from "@/app/api/escalation"; import { fetchEscalationLogsByStockInLines } from "@/app/api/escalation/actions"; import { SessionWithTokens } from "@/config/authConfig"; @@ -80,6 +81,7 @@ interface Props { warehouse: WarehouseResult[]; fetchPoDetail: (poId: string) => void; handleMailTemplateForStockInLine: (stockInLineId: number) => void; + printerCombo: PrinterCombo[]; } export type StockInLineEntryError = { @@ -119,7 +121,8 @@ function PoInputGrid({ stockInLine, warehouse, fetchPoDetail, - handleMailTemplateForStockInLine + handleMailTemplateForStockInLine, + printerCombo }: Props) { console.log(itemDetail); const { t } = useTranslation("purchaseOrder"); @@ -301,7 +304,7 @@ const closeNewModal = useCallback(() => { const handleNewQC = useCallback( (id: GridRowId, params: any) => async() => { // console.log(id) - // console.log(params) + console.log("params", params.row) // setBtnIsLoading(true); setRowModesModel((prev) => ({ ...prev, @@ -939,6 +942,7 @@ const closeNewModal = useCallback(() => { onClose={closeNewModal} itemDetail={modalInfo} handleMailTemplateForStockInLine={handleMailTemplateForStockInLine} + printerCombo={printerCombo} /> ) diff --git a/src/components/PoDetail/PoQcStockInModal.tsx b/src/components/PoDetail/PoQcStockInModal.tsx index 0702ca4..6abb07c 100644 --- a/src/components/PoDetail/PoQcStockInModal.tsx +++ b/src/components/PoDetail/PoQcStockInModal.tsx @@ -28,7 +28,7 @@ import { useSearchParams } from "next/navigation"; import { StockInLineRow } from "./PoInputGrid"; import EscalationForm from "./EscalationForm"; import StockInForm from "./StockInForm"; -import PutawayForm from "./PutawayForm"; +import PutAwayForm from "./PutAwayForm"; import { INPUT_DATE_FORMAT, stockInLineStatusMap, @@ -437,7 +437,7 @@ const PoQcStockInModal: React.FC = ({ /> )} {itemDetail !== undefined && type === "putaway" && ( - , EntryError>; +type PutAwayRow = TableRow, EntryError>; const style = { position: "absolute", @@ -79,7 +81,7 @@ const style = { width: "auto", }; -const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { +const PutAwayForm: React.FC = ({ itemDetail, warehouse, disabled, printerCombo }) => { const { t } = useTranslation("purchaseOrder"); const apiRef = useGridApiRef(); const { @@ -93,7 +95,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { resetField, setError, clearErrors, - } = useFormContext(); + } = useFormContext(); console.log(itemDetail); // const [recordQty, setRecordQty] = useState(0); const [warehouseId, setWarehouseId] = useState(itemDetail.defaultWarehouseId); @@ -143,7 +145,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { }, [], ); - console.log(watch("putawayLine")) + console.log(watch("putAwayLines")) // const accQty = watch("acceptedQty"); // const validateForm = useCallback(() => { // console.log(accQty); @@ -274,6 +276,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { field: "qty", headerName: t("qty"), flex: 1, + editable: true, // renderCell(params) { // return <>100 // }, @@ -282,6 +285,33 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { field: "warehouse", headerName: t("warehouse"), flex: 1, + editable: true, + renderEditCell: (params) => { + const index = params.api.getRowIndexRelativeToVisibleRows(params.row.id) + // console.log(index) + // console.log(watch(`putAwayLines.${index}.warehouse`)) + return o.value === itemDetail.defaultWarehouseId)} + // value={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} + defaultValue={options.find((o) => o.value === watch(`putAwayLines.${index}.warehouseId`))} + onChange={(event, value) => { + params.api.setEditCellValue({ id: params.id, field: params.field, value: options.find((o) => o.value === value.value)?.label ?? ""}) + params.api.setEditCellValue({ id: params.id, field: "warehouseId", value: value.value}) + // setValue(`putAwayLines.${index}.warehouseId`, value.value) + // setValue(`putAwayLines.${index}.warehouse`, options.find((o) => o.value === value.value)?.label ?? "") + }} + renderInput={(params) => ( + + )} + /> + } // renderCell(params) { // return <>{filteredWarehouse[0].name} // }, @@ -290,6 +320,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { field: "printQty", headerName: t("printQty"), flex: 1, + editable: true, // renderCell(params) { // return <>100 // }, @@ -297,7 +328,7 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { ], []) const validation = useCallback( - (newRow: GridRowModel): EntryError => { + (newRow: GridRowModel): EntryError => { const error: EntryError = {}; const { qty, warehouseId, printQty } = newRow; @@ -306,6 +337,13 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { [], ); + const addRowDefaultValue = useMemo(() => { + const defaultMaxQty = watch("acceptedQty") - watch("putAwayLines").reduce((acc, cur) => acc + cur.qty, 0) + const defaultWarehouseId = itemDetail.defaultWarehouseId ?? 1 + const defaultWarehouse = options.find((o) => o.value === defaultWarehouseId)?.label + return {qty: defaultMaxQty, warehouseId: defaultWarehouseId, warehouse: defaultWarehouse, printQty: 1 } as Partial + }, []) + return ( @@ -493,14 +531,15 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { style={{ display: "flex", justifyContent: "center" }} > {/* */} - + apiRef={apiRef} checkboxSelection={false} - _formKey={"putawayLine"} + _formKey={"putAwayLines"} columns={columns} validateRow={validation} needAdd={true} showRemoveBtn={false} + addRowDefaultValue={addRowDefaultValue} /> @@ -525,4 +564,4 @@ const PutawayForm: React.FC = ({ itemDetail, warehouse, disabled }) => { ); }; -export default PutawayForm; +export default PutAwayForm; diff --git a/src/components/PoDetail/QcStockInModalVer2.tsx b/src/components/PoDetail/QcStockInModalVer2.tsx index 18c7568..52fddb8 100644 --- a/src/components/PoDetail/QcStockInModalVer2.tsx +++ b/src/components/PoDetail/QcStockInModalVer2.tsx @@ -1,14 +1,16 @@ "use client"; import { StockInLine } from "@/app/api/po"; -import { ModalFormInput, PurchaseQcResult, StockInLineEntry, updateStockInLine, PurchaseQCInput } from "@/app/api/po/actions"; +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"; @@ -20,10 +22,16 @@ import StockInFormVer2 from "./StockInFormVer2"; import PutawayForm from "./PutawayForm"; import QcComponent from "./QcComponent"; import { dummyPutawayLine, dummyQCData } from "./dummyQcTemplate"; +import QcFormVer2 from "./QcFormVer2"; +import PutAwayForm from "./PutAwayForm"; +import { dummyPutAwayLine, dummyQCData } from "./dummyQcTemplate"; import { useGridApiRef } from "@mui/x-data-grid"; import {submitDialogWithWarning} from "../Swal/CustomAlerts"; -import { arrayToDateString, arrayToInputDateString, dayjsToInputDateString, INPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; +import { INPUT_DATE_FORMAT, arrayToDateString, arrayToInputDateString, 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 { watch } from "fs"; import { EscalationResult } from "@/app/api/escalation"; import { SessionWithTokens } from "@/config/authConfig"; @@ -60,6 +68,7 @@ interface CommonProps extends Omit { warehouse?: any[]; // type: "qc" | "stockIn" | "escalation" | "putaway" | "reject"; handleMailTemplateForStockInLine: (stockInLineId: number) => void; + printerCombo: PrinterCombo[]; onClose: () => void; } interface Props extends CommonProps { @@ -78,19 +87,25 @@ const PoQcStockInModalVer2: React.FC = ({ 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: arrayToInputDateString(itemDetail.dnDate)?? dayjsToInputDateString(dayjs()), - putawayLine: dummyPutawayLine, + // putAwayLines: dummyPutAwayLine, + // putAwayLines: itemDetail.putAwayLines.map((line) => (return {...line, printQty: 1})) ?? [], + putAwayLines: itemDetail.putAwayLines?.map((line) => ({...line, printQty: 1})) ?? [], qcResult: (itemDetail.qcResult && itemDetail.qcResult?.length > 0) ? itemDetail.qcResult : [],//[...dummyQCData], escResult: (itemDetail.escResult && itemDetail.escResult?.length > 0) ? itemDetail.escResult : [], receiptDate: itemDetail.receiptDate ?? dayjs().add(0, "month").format(INPUT_DATE_FORMAT), @@ -123,6 +138,17 @@ const [qcItems, setQcItems] = useState(dummyQCData) } else return false; }; + useEffect(() => { + formProps.reset({ + ...itemDetail, + dnDate: dayjsToInputDateString(dayjs()), + // putAwayLines: dummyPutAwayLine, + putAwayLines: itemDetail.putAwayLines?.map((line) => ({...line, printQty: 1})) ?? [], + }) + setOpenPutaway(isPutaway); + + }, [open, itemDetail]) + const [viewOnly, setViewOnly] = useState(false); useEffect(() => { if (itemDetail && itemDetail.status) { @@ -248,7 +274,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) if (validationErrors.length > 0) { console.error("QC Validation failed:", validationErrors); - alert(`未完成品檢: ${validationErrors}`); + alert(`未完成品檢: ${validationErrors}`); return; } @@ -275,7 +301,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) // const qcData = data; console.log("QC Data for submission:", qcData); - if (data.qcDecision == 3) { // Escalate const escalationLog = { type : "qc", @@ -286,12 +311,10 @@ const [qcItems, setQcItems] = useState(dummyQCData) } console.log("ESCALATION RESULT", 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: ""}); @@ -312,7 +335,6 @@ const [qcItems, setQcItems] = useState(dummyQCData) console.log("Submitting", submitData); const res = await updateStockInLine(submitData); - console.log("Result ", res); return res; },[itemDetail]) @@ -357,13 +379,16 @@ const [qcItems, setQcItems] = useState(dummyQCData) expiryDate : arrayToInputDateString(data.expiryDate), receiptDate : arrayToInputDateString(data.receiptDate), + // for putaway data + inventoryLotLines: data.putAwayLines?.filter((line) => Boolean(line._isNew)) + // Add other putaway specific fields } as ModalFormInput; console.log("Putaway Data:", putawayData); // Handle putaway submission logic here const res = await postStockInLine(putawayData); - console.log("Result ", res); + console.log("result ", res); // Close modal after successful putaway closeHandler({}, "backdropClick"); @@ -371,11 +396,32 @@ const [qcItems, setQcItems] = useState(dummyQCData) [closeHandler], ); // Print handler - const onPrint = useCallback(() => { - console.log("Print putaway documents"); + 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(); - }, []); + // window.print(); + // const postData = { stockInLineIds: [itemDetail.id]}; + // const response = await fetchPoQrcode(postData); + // if (response) { + // downloadFile(new Uint8Array(response.blobValue), response.filename) + // } + try { + setIsPrinting(() => true) + const data: PrintQrCodeForSilRequest = { + stockInLineId: itemDetail.id, + printerId: selectedPrinter.id, + printQty: formProps.watch("putAwayLines")?.reduce((acc, cur) => acc + cur.printQty, 0) + } + const response = await printQrCodeForSil(data); + if (response) { + console.log(response) + } + } finally { + setIsPrinting(() => false) + } + }, [itemDetail.id]); const acceptQty = formProps.watch("acceptedQty") @@ -395,7 +441,7 @@ const [qcItems, setQcItems] = useState(dummyQCData) console.log(qcItems) // checkQcIsPassed(qcItems) }, [qcItems, checkQcIsPassed]) - + return ( <> @@ -410,26 +456,44 @@ const [qcItems, setQcItems] = useState(dummyQCData) marginRight: 3, }} > - {openPutaway ? ( + {openPutaway ? ( - + { + setSelectedPrinter(value) + }} + renderInput={(params) => ( + + )} + />