@@ -0,0 +1,23 @@ | |||||
"use server"; | |||||
import { BASE_API_URL } from "@/config/api"; | |||||
// import { ServerFetchError, serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; | |||||
import { revalidateTag } from "next/cache"; | |||||
import { cache } from "react"; | |||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||||
import { QcItemResult } from "../settings/qcItem"; | |||||
import { RecordsRes } from "../utils"; | |||||
// import { BASE_API_URL } from "@/config/api"; | |||||
export interface LotLineInfo { | |||||
inventoryLotLineId: number, | |||||
lotNo: string, | |||||
remainingQty: number, | |||||
uom: string | |||||
} | |||||
export const fetchLotDetail = cache(async (stockInLineId: number) => { | |||||
return serverFetchJson<LotLineInfo>(`${BASE_API_URL}/inventoryLotLine/lot-detail/${stockInLineId}`, { | |||||
method: 'GET', | |||||
next: { tags: ["inventory"] }, | |||||
}); | |||||
}); |
@@ -9,6 +9,10 @@ import { RecordsRes } from "../utils"; | |||||
import { ConsoPickOrderResult, PickOrderLineWithSuggestedLot, PickOrderResult, PreReleasePickOrderSummary } from "."; | import { ConsoPickOrderResult, PickOrderLineWithSuggestedLot, PickOrderResult, PreReleasePickOrderSummary } from "."; | ||||
// import { BASE_API_URL } from "@/config/api"; | // import { BASE_API_URL } from "@/config/api"; | ||||
export interface ReleasePickOrderInputs { | |||||
consoCode: string | |||||
assignTo: number, | |||||
} | |||||
export const consolidatePickOrder = async (ids: number[]) => { | export const consolidatePickOrder = async (ids: number[]) => { | ||||
const pickOrder = await serverFetchJson<any>(`${BASE_API_URL}/pickOrder/conso`, { | const pickOrder = await serverFetchJson<any>(`${BASE_API_URL}/pickOrder/conso`, { | ||||
@@ -61,7 +65,7 @@ export const consolidatePickOrder_revert = async (ids: number[]) => { | |||||
} | } | ||||
}); | }); | ||||
export const fetchConsoPickOrderLineClient = cache(async (queryParams?: Record<string, any>) => { | |||||
export const fetchPickOrderLineClient = cache(async (queryParams?: Record<string, any>) => { | |||||
if (queryParams) { | if (queryParams) { | ||||
const queryString = new URLSearchParams(queryParams).toString(); | const queryString = new URLSearchParams(queryParams).toString(); | ||||
return serverFetchJson<RecordsRes<PickOrderLineWithSuggestedLot[]>>(`${BASE_API_URL}/pickOrder/get-pickorder-line-byPage?${queryString}`, { | return serverFetchJson<RecordsRes<PickOrderLineWithSuggestedLot[]>>(`${BASE_API_URL}/pickOrder/get-pickorder-line-byPage?${queryString}`, { | ||||
@@ -77,8 +81,21 @@ export const consolidatePickOrder_revert = async (ids: number[]) => { | |||||
}); | }); | ||||
export const fetchConsoDetail = cache(async (consoCode: string) => { | export const fetchConsoDetail = cache(async (consoCode: string) => { | ||||
return serverFetchJson<PreReleasePickOrderSummary>(`${BASE_API_URL}/pickOrder/releaseConso/${consoCode}`, { | |||||
return serverFetchJson<PreReleasePickOrderSummary>(`${BASE_API_URL}/pickOrder/pre-release-info/${consoCode}`, { | |||||
method: 'GET', | method: 'GET', | ||||
next: { tags: ["pickorder"] }, | next: { tags: ["pickorder"] }, | ||||
}); | }); | ||||
}); | |||||
}); | |||||
export const releasePickOrder = async (data: ReleasePickOrderInputs) => { | |||||
console.log(data) | |||||
console.log(JSON.stringify(data)) | |||||
const po = await serverFetchJson<any>(`${BASE_API_URL}/pickOrder/releaseConso`, { | |||||
method: "POST", | |||||
body: JSON.stringify(data), | |||||
headers: { "Content-Type": "application/json" }, | |||||
}); | |||||
revalidateTag("pickorder"); | |||||
return po | |||||
} |
@@ -66,9 +66,12 @@ export interface PreReleasePickOrderSummary { | |||||
} | } | ||||
export interface PickOrderLineWithSuggestedLot { | export interface PickOrderLineWithSuggestedLot { | ||||
id: number, | |||||
itemName: string, | itemName: string, | ||||
qty: number, | qty: number, | ||||
uom: string | |||||
status: string | status: string | ||||
warehouse: string | |||||
suggestedLotNo: string | suggestedLotNo: string | ||||
} | } | ||||
@@ -20,12 +20,23 @@ export interface PasswordInputs { | |||||
newPasswordCheck: string; | newPasswordCheck: string; | ||||
} | } | ||||
export interface NameList { | |||||
id: number | |||||
name: string | |||||
} | |||||
export const fetchUserDetails = cache(async (id: number) => { | export const fetchUserDetails = cache(async (id: number) => { | ||||
return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { | return serverFetchJson<UserDetail>(`${BASE_API_URL}/user/${id}`, { | ||||
next: { tags: ["user"] }, | next: { tags: ["user"] }, | ||||
}); | }); | ||||
}); | }); | ||||
export const fetchNameList = cache(async () => { | |||||
return serverFetchJson<NameList[]>(`${BASE_API_URL}/user/name-list`, { | |||||
next: { tags: ["user"] }, | |||||
}); | |||||
}); | |||||
export const editUser = async (id: number, data: UserInputs) => { | export const editUser = async (id: number, data: UserInputs) => { | ||||
const newUser = serverFetchWithNoContent(`${BASE_API_URL}/user/${id}`, { | const newUser = serverFetchWithNoContent(`${BASE_API_URL}/user/${id}`, { | ||||
method: "PUT", | method: "PUT", | ||||
@@ -67,6 +67,13 @@ export const stockInLineStatusMap: { [status: string]: number } = { | |||||
"rejected": 9, | "rejected": 9, | ||||
}; | }; | ||||
export const pickOrderStatusMap: { [status: string]: number } = { | |||||
"pending": 1, | |||||
"consolidated": 2, | |||||
"released": 3, | |||||
"completed": 4, | |||||
}; | |||||
export const calculateWeight = (qty: number, uom: Uom) => { | export const calculateWeight = (qty: number, uom: Uom) => { | ||||
return qty * (uom.unit2Qty || 1) * (uom.unit3Qty || 1) * (uom.unit4Qty || 1); | return qty * (uom.unit2Qty || 1) * (uom.unit3Qty || 1) * (uom.unit4Qty || 1); | ||||
} | } | ||||
@@ -19,9 +19,13 @@ import { PlayArrow } from "@mui/icons-material"; | |||||
import DoneIcon from "@mui/icons-material/Done"; | import DoneIcon from "@mui/icons-material/Done"; | ||||
import { GridRowSelectionModel } from "@mui/x-data-grid"; | import { GridRowSelectionModel } from "@mui/x-data-grid"; | ||||
import { useQcCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | import { useQcCodeScanner } from "../QrCodeScannerProvider/QrCodeScannerProvider"; | ||||
import { fetchConsoPickOrderLineClient } from "@/app/api/pickorder/actions"; | |||||
import { fetchPickOrderLineClient } from "@/app/api/pickorder/actions"; | |||||
import { PickOrderLineWithSuggestedLot } from "@/app/api/pickorder"; | import { PickOrderLineWithSuggestedLot } from "@/app/api/pickorder"; | ||||
import { Pageable } from "@/app/utils/fetchUtil"; | import { Pageable } from "@/app/utils/fetchUtil"; | ||||
import { QrCodeInfo } from "@/app/api/qrcode"; | |||||
import { QrCode } from "../QrCode"; | |||||
import { fetchLotDetail, LotLineInfo } from "@/app/api/inventory/actions"; | |||||
import { GridRowModesModel } from "@mui/x-data-grid"; | |||||
interface Props { | interface Props { | ||||
consoCode: string; | consoCode: string; | ||||
@@ -30,6 +34,7 @@ interface IsLoadingModel { | |||||
pickOrderLineTable: boolean; | pickOrderLineTable: boolean; | ||||
stockOutLineTable: boolean; | stockOutLineTable: boolean; | ||||
} | } | ||||
const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | ||||
const { t } = useTranslation("pickOrder"); | const { t } = useTranslation("pickOrder"); | ||||
const [selectedRow, setSelectRow] = useState<GridRowSelectionModel>(); | const [selectedRow, setSelectRow] = useState<GridRowSelectionModel>(); | ||||
@@ -37,18 +42,23 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
pickOrderLineTable: false, | pickOrderLineTable: false, | ||||
stockOutLineTable: false, | stockOutLineTable: false, | ||||
}); | }); | ||||
const [criteriaArgs, setCriteriaArgs] = useState<Pageable>({ | |||||
const [polCriteriaArgs, setPolCriteriaArgs] = useState<Pageable>({ | |||||
pageNum: 1, | |||||
pageSize: 10, | |||||
}); | |||||
const [solCriteriaArgs, setSolCriteriaArgs] = useState<Pageable>({ | |||||
pageNum: 1, | pageNum: 1, | ||||
pageSize: 10, | pageSize: 10, | ||||
}); | }); | ||||
const [polTotalCount, setPolTotalCount] = useState(0); | const [polTotalCount, setPolTotalCount] = useState(0); | ||||
const [solTotalCount, setSolTotalCount] = useState(0); | const [solTotalCount, setSolTotalCount] = useState(0); | ||||
const [rowModesModel, setRowModesModel] = useState<GridRowModesModel>({}); | |||||
const [suggestedList, setSuggestedList] = useState< | |||||
const [pickOrderLine, setPickOrderLine] = useState< | |||||
PickOrderLineWithSuggestedLot[] | PickOrderLineWithSuggestedLot[] | ||||
>([]); | >([]); | ||||
const sugggestedLotColumn = useMemo<GridColDef[]>( | |||||
const pickOrderLineColumns = useMemo<GridColDef[]>( | |||||
() => [ | () => [ | ||||
{ | { | ||||
field: "id", | field: "id", | ||||
@@ -70,16 +80,21 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
headerName: "uom", | headerName: "uom", | ||||
flex: 1, | flex: 1, | ||||
}, | }, | ||||
{ | |||||
field: "warehouse", | |||||
headerName: "location", | |||||
flex: 1, | |||||
}, | |||||
{ | { | ||||
field: "suggestedLotNo", | field: "suggestedLotNo", | ||||
headerName: "suggestedLotNo", | headerName: "suggestedLotNo", | ||||
flex: 1, | |||||
flex: 1.2, | |||||
}, | }, | ||||
], | ], | ||||
[] | [] | ||||
); | ); | ||||
const [actualList, setActualList] = useState([]); | |||||
const actualLotColumn = useMemo<GridColDef[]>( | |||||
const [stockOutLine, setStockOutLine] = useState([]); | |||||
const stockOutLineColumns = useMemo<GridColDef[]>( | |||||
() => [ | () => [ | ||||
{ | { | ||||
field: "code", | field: "code", | ||||
@@ -94,82 +109,43 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
const handleCompletePickOrder = useCallback(async () => {}, []); | const handleCompletePickOrder = useCallback(async () => {}, []); | ||||
const fetchSuggestedLotList = useCallback( | |||||
async (consoCode: string) => {}, | |||||
[] | |||||
); | |||||
useEffect(() => { | useEffect(() => { | ||||
console.log(selectedRow); | console.log(selectedRow); | ||||
}, [selectedRow]); | }, [selectedRow]); | ||||
const buttonData = useMemo(() => { | |||||
switch ("purchaseOrder.status".toLowerCase()) { | |||||
case "pending": | |||||
return { | |||||
buttonName: "start", | |||||
title: t("Do you want to start?"), | |||||
confirmButtonText: t("Start"), | |||||
successTitle: t("Start Success"), | |||||
errorTitle: t("Start Fail"), | |||||
buttonText: t("Start PO"), | |||||
buttonIcon: <PlayArrow />, | |||||
buttonColor: "success", | |||||
disabled: false, | |||||
onClick: handleStartPickOrder, | |||||
}; | |||||
case "receiving": | |||||
return { | |||||
buttonName: "complete", | |||||
title: t("Do you want to complete?"), | |||||
confirmButtonText: t("Complete"), | |||||
successTitle: t("Complete Success"), | |||||
errorTitle: t("Complete Fail"), | |||||
buttonText: t("Complete PO"), | |||||
buttonIcon: <DoneIcon />, | |||||
buttonColor: "info", | |||||
disabled: false, | |||||
onClick: handleCompletePickOrder, | |||||
}; | |||||
default: | |||||
return { | |||||
buttonName: "complete", | |||||
title: t("Do you want to complete?"), | |||||
confirmButtonText: t("Complete"), | |||||
successTitle: t("Complete Success"), | |||||
errorTitle: t("Complete Fail"), | |||||
buttonText: t("Complete PO"), | |||||
buttonIcon: <DoneIcon />, | |||||
buttonColor: "info", | |||||
disabled: true, | |||||
}; | |||||
// break; | |||||
} | |||||
}, [handleStartPickOrder, handleCompletePickOrder]); | |||||
const buttonData = useMemo( | |||||
() => ({ | |||||
buttonName: "complete", | |||||
title: t("Do you want to complete?"), | |||||
confirmButtonText: t("Complete"), | |||||
successTitle: t("Complete Success"), | |||||
errorTitle: t("Complete Fail"), | |||||
buttonText: t("Complete PO"), | |||||
buttonIcon: <DoneIcon />, | |||||
buttonColor: "info", | |||||
disabled: true, | |||||
}), | |||||
[] | |||||
); | |||||
const [isOpenScanner, setOpenScanner] = useState(false); | const [isOpenScanner, setOpenScanner] = useState(false); | ||||
const onOpenScanner = useCallback(() => { | const onOpenScanner = useCallback(() => { | ||||
setOpenScanner(true); | |||||
}, []); | |||||
const onCloseScanner = useCallback(() => { | |||||
setOpenScanner(false); | |||||
setOpenScanner((prev) => !prev); | |||||
}, []); | }, []); | ||||
const fetchConsoPickOrderLine = useCallback( | |||||
const fetchPickOrderLine = useCallback( | |||||
async (params: Record<string, any>) => { | async (params: Record<string, any>) => { | ||||
setIsLoadingModel((prev) => ({ | setIsLoadingModel((prev) => ({ | ||||
...prev, | ...prev, | ||||
pickOrderLineTable: true, | pickOrderLineTable: true, | ||||
})); | })); | ||||
const res = await fetchConsoPickOrderLineClient({ | |||||
const res = await fetchPickOrderLineClient({ | |||||
...params, | ...params, | ||||
consoCode: consoCode, | consoCode: consoCode, | ||||
}); | }); | ||||
if (res) { | if (res) { | ||||
console.log(res); | console.log(res); | ||||
setSuggestedList(res.records); | |||||
setPickOrderLine(res.records); | |||||
setPolTotalCount(res.total); | setPolTotalCount(res.total); | ||||
} else { | } else { | ||||
console.log("error"); | console.log("error"); | ||||
@@ -180,12 +156,28 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
pickOrderLineTable: false, | pickOrderLineTable: false, | ||||
})); | })); | ||||
}, | }, | ||||
[fetchConsoPickOrderLineClient, consoCode] | |||||
[fetchPickOrderLineClient, consoCode] | |||||
); | |||||
const fetchStockOutLine = useCallback( | |||||
async (params: Record<string, any>) => {}, | |||||
[] | |||||
); | ); | ||||
useEffect(() => { | useEffect(() => { | ||||
fetchConsoPickOrderLine(criteriaArgs); | |||||
}, [criteriaArgs]); | |||||
fetchPickOrderLine(polCriteriaArgs); | |||||
}, [polCriteriaArgs]); | |||||
useEffect(() => { | |||||
fetchStockOutLine(solCriteriaArgs); | |||||
}, [solCriteriaArgs]); | |||||
const getLotDetail = useCallback( | |||||
async (stockInLineId: number): Promise<LotLineInfo> => { | |||||
const res = await fetchLotDetail(stockInLineId); | |||||
return res; | |||||
}, | |||||
[fetchLotDetail] | |||||
); | |||||
const scanner = useQcCodeScanner(); | const scanner = useQcCodeScanner(); | ||||
useEffect(() => { | useEffect(() => { | ||||
@@ -196,19 +188,24 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
} | } | ||||
}, [isOpenScanner]); | }, [isOpenScanner]); | ||||
// useEffect(() => { | |||||
// if (scanner.values.length > 0 && !Boolean(itemDetail)) { | |||||
// console.log(scanner.values[0]); | |||||
// const data: QrCodeInfo = JSON.parse(scanner.values[0]); | |||||
// console.log(data); | |||||
// if (data.stockInLineId) { | |||||
// console.log("still got in"); | |||||
// console.log(data.stockInLineId); | |||||
// setStockInLineId(data.stockInLineId); | |||||
// } | |||||
// scanner.resetScan(); | |||||
// } | |||||
// }, [scanner.values]); | |||||
useEffect(() => { | |||||
if (scanner.values.length > 0) { | |||||
console.log(scanner.values[0]); | |||||
const data: QrCodeInfo = JSON.parse(scanner.values[0]); | |||||
console.log(data); | |||||
if (data.stockInLineId) { | |||||
console.log("still got in"); | |||||
console.log(data.stockInLineId); | |||||
// fetch | |||||
getLotDetail(data.stockInLineId).then((value) => {}); | |||||
} | |||||
scanner.resetScan(); | |||||
} | |||||
}, [scanner.values]); | |||||
const homemade_Qrcode = { | |||||
stockInLineId: 156, | |||||
}; | |||||
return ( | return ( | ||||
<> | <> | ||||
@@ -221,7 +218,7 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
</Grid> | </Grid> | ||||
<Grid item xs={8}> | <Grid item xs={8}> | ||||
<Button | <Button | ||||
onClick={buttonData.onClick} | |||||
// onClick={buttonData.onClick} | |||||
disabled={buttonData.disabled} | disabled={buttonData.disabled} | ||||
color={buttonData.buttonColor as ButtonProps["color"]} | color={buttonData.buttonColor as ButtonProps["color"]} | ||||
startIcon={buttonData.buttonIcon} | startIcon={buttonData.buttonIcon} | ||||
@@ -236,27 +233,45 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
justifyContent="end" | justifyContent="end" | ||||
alignItems="end" | alignItems="end" | ||||
> | > | ||||
<Button onClick={onOpenScanner}>{t("bind")}</Button> | |||||
<Button onClick={onOpenScanner}> | |||||
{isOpenScanner ? t("binding") : t("bind")} | |||||
</Button> | |||||
</Grid> | </Grid> | ||||
{/* homemade qrcode for testing purpose */} | |||||
{/* <Grid | |||||
item | |||||
xs={12} | |||||
style={{ display: "flex", justifyContent: "center" }} | |||||
> | |||||
<QrCode | |||||
content={homemade_Qrcode} | |||||
sx={{ width: 200, height: 200 }} | |||||
/> | |||||
</Grid> */} | |||||
</Grid> | </Grid> | ||||
<Grid container xs={12} justifyContent="space-between"> | <Grid container xs={12} justifyContent="space-between"> | ||||
{/* <Grid item xs={12} sx={{ height: 400 }}> | {/* <Grid item xs={12} sx={{ height: 400 }}> | ||||
<StyledDataGrid rows={suggestedList} columns={columns} /> | |||||
<StyledDataGrid rows={pickOrderLine} columns={columns} /> | |||||
</Grid> */} | </Grid> */} | ||||
<Grid item xs={12} sx={{ height: 400 }}> | <Grid item xs={12} sx={{ height: 400 }}> | ||||
{isLoadingModel.pickOrderLineTable ? ( | {isLoadingModel.pickOrderLineTable ? ( | ||||
<CircularProgress size={40} /> | <CircularProgress size={40} /> | ||||
) : ( | ) : ( | ||||
<StyledDataGrid | <StyledDataGrid | ||||
rows={suggestedList} | |||||
columns={sugggestedLotColumn} | |||||
rows={pickOrderLine} | |||||
columns={pickOrderLineColumns} | |||||
rowSelectionModel={selectedRow} | rowSelectionModel={selectedRow} | ||||
onRowSelectionModelChange={(newRowSelectionModel) => { | onRowSelectionModelChange={(newRowSelectionModel) => { | ||||
setSelectRow(newRowSelectionModel); | setSelectRow(newRowSelectionModel); | ||||
}} | }} | ||||
pageSizeOptions={[2, 10, 25, 50, 100]} | |||||
initialState={{ | |||||
pagination: { | |||||
paginationModel: { pageSize: 10, page: 0 }, | |||||
}, | |||||
}} | |||||
pageSizeOptions={[10, 25, 50, 100]} | |||||
onPaginationModelChange={async (model, details) => { | onPaginationModelChange={async (model, details) => { | ||||
setCriteriaArgs({ | |||||
setPolCriteriaArgs({ | |||||
pageNum: model.page + 1, | pageNum: model.page + 1, | ||||
pageSize: model.pageSize, | pageSize: model.pageSize, | ||||
}); | }); | ||||
@@ -266,7 +281,30 @@ const PickOrderDetail: React.FC<Props> = ({ consoCode }) => { | |||||
)} | )} | ||||
</Grid> | </Grid> | ||||
<Grid item xs={12} sx={{ height: 400 }}> | <Grid item xs={12} sx={{ height: 400 }}> | ||||
<StyledDataGrid rows={actualList} columns={actualLotColumn} /> | |||||
<StyledDataGrid | |||||
rows={stockOutLine} | |||||
columns={stockOutLineColumns} | |||||
rowModesModel={rowModesModel} | |||||
onRowModesModelChange={setRowModesModel} | |||||
disableColumnMenu | |||||
editMode="row" | |||||
// processRowUpdate={processRowUpdate} | |||||
// onProcessRowUpdateError={onProcessRowUpdateError} | |||||
initialState={{ | |||||
pagination: { | |||||
paginationModel: { pageSize: 10, page: 0 }, | |||||
}, | |||||
}} | |||||
pageSizeOptions={[10, 25, 50, 100]} | |||||
onPaginationModelChange={async (model, details) => { | |||||
setSolCriteriaArgs({ | |||||
pageNum: model.page + 1, | |||||
pageSize: model.pageSize, | |||||
}); | |||||
}} | |||||
rowCount={solTotalCount} | |||||
/> | |||||
</Grid> | </Grid> | ||||
</Grid> | </Grid> | ||||
</Stack> | </Stack> | ||||
@@ -1,10 +1,13 @@ | |||||
import { | import { | ||||
Autocomplete, | |||||
Box, | Box, | ||||
Button, | Button, | ||||
CircularProgress, | CircularProgress, | ||||
FormControl, | |||||
Grid, | Grid, | ||||
Modal, | Modal, | ||||
ModalProps, | ModalProps, | ||||
TextField, | |||||
Typography, | Typography, | ||||
} from "@mui/material"; | } from "@mui/material"; | ||||
import { GridToolbarContainer } from "@mui/x-data-grid"; | import { GridToolbarContainer } from "@mui/x-data-grid"; | ||||
@@ -21,7 +24,12 @@ import SearchResults, { | |||||
Column, | Column, | ||||
defaultPagingController, | defaultPagingController, | ||||
} from "../SearchResults/SearchResults"; | } from "../SearchResults/SearchResults"; | ||||
import { ByItemsSummary, ConsoPickOrderResult, PickOrderLine, PickOrderResult } from "@/app/api/pickorder"; | |||||
import { | |||||
ByItemsSummary, | |||||
ConsoPickOrderResult, | |||||
PickOrderLine, | |||||
PickOrderResult, | |||||
} from "@/app/api/pickorder"; | |||||
import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
import ConsolidatePickOrderItemSum from "./ConsolidatePickOrderItemSum"; | import ConsolidatePickOrderItemSum from "./ConsolidatePickOrderItemSum"; | ||||
import ConsolidatePickOrderSum from "./ConsolidatePickOrderSum"; | import ConsolidatePickOrderSum from "./ConsolidatePickOrderSum"; | ||||
@@ -29,8 +37,19 @@ import { GridInputRowSelectionModel } from "@mui/x-data-grid"; | |||||
import { | import { | ||||
fetchConsoDetail, | fetchConsoDetail, | ||||
fetchConsoPickOrderClient, | fetchConsoPickOrderClient, | ||||
releasePickOrder, | |||||
ReleasePickOrderInputs, | |||||
} from "@/app/api/pickorder/actions"; | } from "@/app/api/pickorder/actions"; | ||||
import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
import { fetchNameList, NameList } from "@/app/api/user/actions"; | |||||
import { useField } from "@mui/x-date-pickers/internals"; | |||||
import { | |||||
FormProvider, | |||||
SubmitErrorHandler, | |||||
SubmitHandler, | |||||
useForm, | |||||
} from "react-hook-form"; | |||||
import { pickOrderStatusMap } from "@/app/utils/formatUtil"; | |||||
interface Props { | interface Props { | ||||
filterArgs: Record<string, any>; | filterArgs: Record<string, any>; | ||||
@@ -47,6 +66,10 @@ const style = { | |||||
pb: 10, | pb: 10, | ||||
width: 1500, | width: 1500, | ||||
}; | }; | ||||
interface DisableButton { | |||||
releaseBtn: boolean; | |||||
removeBtn: boolean; | |||||
} | |||||
const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | ||||
const { t } = useTranslation("pickOrder"); | const { t } = useTranslation("pickOrder"); | ||||
@@ -60,9 +83,18 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
const [consoCode, setConsoCode] = useState<string | undefined>(); ///change back to undefined | const [consoCode, setConsoCode] = useState<string | undefined>(); ///change back to undefined | ||||
const [revertIds, setRevertIds] = useState<GridInputRowSelectionModel>([]); | const [revertIds, setRevertIds] = useState<GridInputRowSelectionModel>([]); | ||||
const [totalCount, setTotalCount] = useState<number>(); | const [totalCount, setTotalCount] = useState<number>(); | ||||
const [usernameList, setUsernameList] = useState<NameList[]>([]); | |||||
const [byPickOrderRows, setByPickOrderRows] = useState< | |||||
Omit<PickOrderResult, "items">[] | undefined | |||||
>(undefined); | |||||
const [byItemsRows, setByItemsRows] = useState<ByItemsSummary[] | undefined>( | |||||
undefined | |||||
); | |||||
const [disableRelease, setDisableRelease] = useState<boolean>(true); | |||||
const [byPickOrderRows, setByPickOrderRows] = useState<Omit<PickOrderResult, "items">[] | undefined>(undefined); | |||||
const [byItemsRows, setByItemsRows] = useState<ByItemsSummary[] | undefined>(undefined); | |||||
const formProps = useForm<ReleasePickOrderInputs>(); | |||||
const errors = formProps.formState.errors; | |||||
const openDetailModal = useCallback((consoCode: string) => { | const openDetailModal = useCallback((consoCode: string) => { | ||||
setConsoCode(consoCode); | setConsoCode(consoCode); | ||||
@@ -77,9 +109,14 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
const onDetailClick = useCallback( | const onDetailClick = useCallback( | ||||
(pickOrder: any) => { | (pickOrder: any) => { | ||||
console.log(pickOrder); | console.log(pickOrder); | ||||
openDetailModal(pickOrder.consoCode); | |||||
const status = pickOrder.status | |||||
if (pickOrderStatusMap[status] >= 2) { | |||||
router.push(`/pickorder/detail?consoCode=${pickOrder.consoCode}`); | |||||
} else { | |||||
openDetailModal(pickOrder.consoCode); | |||||
} | |||||
}, | }, | ||||
[openDetailModal] | |||||
[router, openDetailModal] | |||||
); | ); | ||||
const columns = useMemo<Column<ConsoPickOrderResult>[]>( | const columns = useMemo<Column<ConsoPickOrderResult>[]>( | ||||
() => [ | () => [ | ||||
@@ -93,6 +130,10 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
name: "consoCode", | name: "consoCode", | ||||
label: t("consoCode"), | label: t("consoCode"), | ||||
}, | }, | ||||
{ | |||||
name: "status", | |||||
label: t("status"), | |||||
}, | |||||
], | ], | ||||
[] | [] | ||||
); | ); | ||||
@@ -127,6 +168,40 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
fetchNewPageConsoPickOrder(pagingController, filterArgs); | fetchNewPageConsoPickOrder(pagingController, filterArgs); | ||||
}, [fetchNewPageConsoPickOrder, pagingController, filterArgs]); | }, [fetchNewPageConsoPickOrder, pagingController, filterArgs]); | ||||
const isReleasable = useCallback((itemList: ByItemsSummary[]): boolean => { | |||||
var isReleasable = true; | |||||
for (const item of itemList) { | |||||
isReleasable = item.requiredQty >= item.availableQty; | |||||
if (!isReleasable) return isReleasable; | |||||
} | |||||
return isReleasable; | |||||
}, []); | |||||
const fetchConso = useCallback( | |||||
async (consoCode: string) => { | |||||
const res = await fetchConsoDetail(consoCode); | |||||
const nameListRes = await fetchNameList(); | |||||
if (res) { | |||||
console.log(res); | |||||
setByPickOrderRows(res.pickOrders); | |||||
// for testing | |||||
// for (const item of res.items) { | |||||
// item.availableQty = 1000; | |||||
// } | |||||
setByItemsRows(res.items); | |||||
setDisableRelease(isReleasable(res.items)); | |||||
} else { | |||||
console.log("error"); | |||||
console.log(res); | |||||
} | |||||
if (nameListRes) { | |||||
console.log(nameListRes); | |||||
setUsernameList(nameListRes); | |||||
} | |||||
}, | |||||
[isReleasable] | |||||
); | |||||
const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>( | const closeHandler = useCallback<NonNullable<ModalProps["onClose"]>>( | ||||
(...args) => { | (...args) => { | ||||
closeDetailModal(); | closeDetailModal(); | ||||
@@ -135,32 +210,51 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
[closeDetailModal] | [closeDetailModal] | ||||
); | ); | ||||
const handleRelease = useCallback(() => { | |||||
console.log("release"); | |||||
router.push(`/pickorder/detail?consoCode=${consoCode}`); | |||||
}, [router, consoCode]); | |||||
const onChange = useCallback( | |||||
( | |||||
event: React.SyntheticEvent, | |||||
newValue: NameList | |||||
) => { | |||||
console.log(newValue); | |||||
formProps.setValue("assignTo", newValue.id); | |||||
}, | |||||
[] | |||||
); | |||||
const onSubmit = useCallback<SubmitHandler<ReleasePickOrderInputs & {}>>( | |||||
async (data, event) => { | |||||
console.log(data); | |||||
try { | |||||
const res = await releasePickOrder(data) | |||||
console.log(res) | |||||
if (res.status = 200) { | |||||
router.push(`/pickorder/detail?consoCode=${data.consoCode}`); | |||||
} else { | |||||
throw Error("hv error") | |||||
} | |||||
} catch (error) { | |||||
console.log(error) | |||||
} | |||||
}, | |||||
[releasePickOrder] | |||||
); | |||||
const onSubmitError = useCallback<SubmitErrorHandler<ReleasePickOrderInputs>>( | |||||
(errors) => {}, | |||||
[] | |||||
); | |||||
const handleConsolidate_revert = useCallback(() => { | const handleConsolidate_revert = useCallback(() => { | ||||
console.log(revertIds); | console.log(revertIds); | ||||
}, [revertIds]); | }, [revertIds]); | ||||
const fetchConso = useCallback(async (consoCode: string) => { | |||||
const res = await fetchConsoDetail(consoCode); | |||||
if (res) { | |||||
console.log(res); | |||||
setByPickOrderRows(res.pickOrders) | |||||
setByItemsRows(res.items) | |||||
} else { | |||||
console.log("error"); | |||||
console.log(res); | |||||
} | |||||
}, []); | |||||
useEffect(() => { | useEffect(() => { | ||||
if (consoCode) { | if (consoCode) { | ||||
fetchConso(consoCode); | fetchConso(consoCode); | ||||
formProps.setValue("consoCode", consoCode) | |||||
} | } | ||||
}, [consoCode]); | }, [consoCode]); | ||||
return ( | return ( | ||||
<> | <> | ||||
<Grid | <Grid | ||||
@@ -186,58 +280,89 @@ const ConsolidatedPickOrders: React.FC<Props> = ({ filterArgs }) => { | |||||
</Grid> | </Grid> | ||||
{consoCode != undefined ? ( | {consoCode != undefined ? ( | ||||
<Modal open={modalOpen} onClose={closeHandler}> | <Modal open={modalOpen} onClose={closeHandler}> | ||||
<Box sx={{ ...style, maxHeight: 800 }}> | |||||
<Typography mb={2} variant="h4"> | |||||
{consoCode} | |||||
</Typography> | |||||
<Box sx={{ | |||||
height: 400, | |||||
overflowY: "auto" | |||||
}}> | |||||
<FormProvider {...formProps}> | |||||
<Box | |||||
sx={{ ...style, maxHeight: 800 }} | |||||
component="form" | |||||
onSubmit={formProps.handleSubmit(onSubmit, onSubmitError)} | |||||
> | |||||
<Grid container> | <Grid container> | ||||
<Grid item xs={12} sx={{ mt: 2 }}> | |||||
<ConsolidatePickOrderSum | |||||
rows={byPickOrderRows} | |||||
setRows={setByPickOrderRows} | |||||
consoCode={consoCode} | |||||
revertIds={revertIds} | |||||
setRevertIds={setRevertIds} | |||||
/> | |||||
<Grid item xs={8}> | |||||
<Typography mb={2} variant="h4"> | |||||
{consoCode} | |||||
</Typography> | |||||
</Grid> | </Grid> | ||||
<Grid item xs={12}> | |||||
<ConsolidatePickOrderItemSum | |||||
rows={byItemsRows} | |||||
setRows={setByItemsRows} | |||||
/> | |||||
<Grid | |||||
item | |||||
xs={4} | |||||
display="flex" | |||||
justifyContent="end" | |||||
alignItems="end" | |||||
> | |||||
<FormControl fullWidth> | |||||
<Autocomplete | |||||
disableClearable | |||||
fullWidth | |||||
getOptionLabel={(option) => option.name} | |||||
options={usernameList} | |||||
onChange={onChange} | |||||
renderInput={(params) => <TextField {...params} />} | |||||
/> | |||||
</FormControl> | |||||
</Grid> | </Grid> | ||||
</Grid> | </Grid> | ||||
</Box> | |||||
<Grid container> | |||||
<Grid | |||||
item | |||||
xs={12} | |||||
display="flex" | |||||
justifyContent="end" | |||||
alignItems="end" | |||||
<Box | |||||
sx={{ | |||||
height: 400, | |||||
overflowY: "auto", | |||||
}} | |||||
> | > | ||||
<Button | |||||
disabled={(revertIds as number[]).length < 1} | |||||
variant="outlined" | |||||
onClick={handleConsolidate_revert} | |||||
sx={{ mr: 1 }} | |||||
> | |||||
{t("remove")} | |||||
</Button> | |||||
<Button | |||||
// disabled={selectedRows.length < 1} | |||||
variant="outlined" | |||||
onClick={handleRelease} | |||||
<Grid container> | |||||
<Grid item xs={12} sx={{ mt: 2 }}> | |||||
<ConsolidatePickOrderSum | |||||
rows={byPickOrderRows} | |||||
setRows={setByPickOrderRows} | |||||
consoCode={consoCode} | |||||
revertIds={revertIds} | |||||
setRevertIds={setRevertIds} | |||||
/> | |||||
</Grid> | |||||
<Grid item xs={12}> | |||||
<ConsolidatePickOrderItemSum | |||||
rows={byItemsRows} | |||||
setRows={setByItemsRows} | |||||
/> | |||||
</Grid> | |||||
</Grid> | |||||
</Box> | |||||
<Grid container> | |||||
<Grid | |||||
item | |||||
xs={12} | |||||
display="flex" | |||||
justifyContent="end" | |||||
alignItems="end" | |||||
> | > | ||||
{t("release")} | |||||
</Button> | |||||
<Button | |||||
disabled={(revertIds as number[]).length < 1} | |||||
variant="outlined" | |||||
onClick={handleConsolidate_revert} | |||||
sx={{ mr: 1 }} | |||||
> | |||||
{t("remove")} | |||||
</Button> | |||||
<Button | |||||
disabled={disableRelease} | |||||
variant="outlined" | |||||
// onClick={handleRelease} | |||||
type="submit" | |||||
> | |||||
{t("release")} | |||||
</Button> | |||||
</Grid> | |||||
</Grid> | </Grid> | ||||
</Grid> | |||||
</Box> | |||||
</Box> | |||||
</FormProvider> | |||||
</Modal> | </Modal> | ||||
) : undefined} | ) : undefined} | ||||
</> | </> | ||||