소스 검색

UPDATE

production_process
MSI\derek 2 달 전
부모
커밋
6ee3a96bac
7개의 변경된 파일195개의 추가작업 그리고 121개의 파일을 삭제
  1. +15
    -0
      src/app/api/po/actions.ts
  2. +1
    -1
      src/components/PoDetail/PoDetail.tsx
  3. +14
    -14
      src/components/PoDetail/PoInputGrid.tsx
  4. +17
    -3
      src/components/PoDetail/PutawayForm.tsx
  5. +59
    -43
      src/components/PoDetail/QrModal.tsx
  6. +88
    -60
      src/components/PoSearch/PoSearch.tsx
  7. +1
    -0
      src/i18n/zh/purchaseOrder.json

+ 15
- 0
src/app/api/po/actions.ts 파일 보기

@@ -140,3 +140,18 @@ export const fetchPoInClient = cache(async (id: number) => {
}
});

export const testing = cache(async (queryParams?: Record<string, any>) => {
if (queryParams) {
const queryString = new URLSearchParams(queryParams).toString();
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/testing?${queryString}`, {
method: 'GET',
next: { tags: ["po"] },
});
} else {
return serverFetchJson<RecordsRes<PoResult[]>>(`${BASE_API_URL}/po/testing`, {
method: 'GET',
next: { tags: ["po"] },
});
}
});


+ 1
- 1
src/components/PoDetail/PoDetail.tsx 파일 보기

@@ -295,7 +295,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
color={buttonData.buttonColor as ButtonProps["color"]}
startIcon={buttonData.buttonIcon}
>
{t(buttonData.buttonText)}
{buttonData.buttonText}
</Button>
</Grid>
{/* {purchaseOrder.status.toLowerCase() === "pending" && (


+ 14
- 14
src/components/PoDetail/PoInputGrid.tsx 파일 보기

@@ -510,20 +510,20 @@ function PoInputGrid({
color="inherit"
key="edit"
/>,
<GridActionsCellItem
icon={<QrCodeIcon />}
label="putaway"
sx={{
color: "primary.main",
// marginRight: 1,
}}
disabled={stockInLineStatusMap[status] === 9 || stockInLineStatusMap[status] !== 8}
// set _isNew to false after posting
// or check status
onClick={handleQrCode(params.row.id, params)}
color="inherit"
key="edit"
/>,
// <GridActionsCellItem
// icon={<QrCodeIcon />}
// label="putaway"
// sx={{
// color: "primary.main",
// // marginRight: 1,
// }}
// disabled={stockInLineStatusMap[status] === 9 || stockInLineStatusMap[status] !== 8}
// // set _isNew to false after posting
// // or check status
// onClick={handleQrCode(params.row.id, params)}
// color="inherit"
// key="edit"
// />,
<GridActionsCellItem
icon={
stockInLineStatusMap[status] >= 1 ? (


+ 17
- 3
src/components/PoDetail/PutawayForm.tsx 파일 보기

@@ -237,6 +237,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {

useEffect(() => {
setValue("status", "completed");
setValue("warehouseId", options[0].value);
}, []);

useEffect(() => {
@@ -245,7 +246,16 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
clearErrors("warehouseId")
}
}, [warehouseId]);

const getWarningTextHardcode = useCallback((): string | undefined => {
const defaultWarehouseId = options[0].value
const currWarehouseId = watch("warehouseId")
if (defaultWarehouseId !== currWarehouseId) {
return t("not default warehosue")
}
return undefined
}, [options])
return (
<Grid container justifyContent="flex-start" alignItems="flex-start">
<Grid item xs={12}>
@@ -331,7 +341,7 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
disableClearable
disabled
fullWidth
defaultValue={options.find((o) => o.value === 1)} /// modify this later
defaultValue={options[0]} /// modify this later
// onChange={onChange}
getOptionLabel={(option) => option.label}
options={options}
@@ -396,6 +406,8 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
// value={warehouseId > 0
// ? options.find((o) => o.value === warehouseId)
// : undefined}
defaultValue={options[0]}
// defaultValue={options.find((o) => o.value === 1)}
value={currentValue}
onChange={onChange}
getOptionLabel={(option) => option.label}
@@ -406,7 +418,9 @@ const PutawayForm: React.FC<Props> = ({ itemDetail, warehouse, disabled }) => {
// label={"Select warehouse"}
disabled={disabled}
error={Boolean(errors.warehouseId?.message)}
helperText={errors.warehouseId?.message}
helperText={errors.warehouseId?.message ??
getWarningTextHardcode()
}
// helperText={warehouseHelperText}
/>
)}


+ 59
- 43
src/components/PoDetail/QrModal.tsx 파일 보기

@@ -1,6 +1,14 @@
"use client";

import { Box, Button, Grid, Modal, ModalProps, Stack, Typography } from "@mui/material";
import {
Box,
Button,
Grid,
Modal,
ModalProps,
Stack,
Typography,
} from "@mui/material";
import { useCallback, useEffect, useMemo, useState } from "react";
import ReactQrCodeScanner, {
ScannerConfig,
@@ -74,18 +82,18 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
);

// QR Code Scanner
const scanner = useQcCodeScanner()
const scanner = useQcCodeScanner();
useEffect(() => {
if (open && !scanner.isScanning) {
scanner.startScan()
scanner.startScan();
} else if (!open && scanner.isScanning) {
scanner.stopScan()
scanner.stopScan();
}
}, [open])
}, [open]);

useEffect(() => {
if (scanner.values.length > 0 && !Boolean(itemDetail)) {
console.log(scanner.values[0])
console.log(scanner.values[0]);
const data: QrCodeInfo = JSON.parse(scanner.values[0]);
console.log(data);
if (data.stockInLineId) {
@@ -93,28 +101,29 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
console.log(data.stockInLineId);
setStockInLineId(data.stockInLineId);
}
scanner.resetScan()
scanner.resetScan();
}
}, [scanner.values])
}, [scanner.values]);

const [itemDetail, setItemDetail] = useState<StockInLine>();
const [disabledSubmit, setDisabledSubmit] = useState(false);
const [unavailableText, setUnavailableText] = useState<string | undefined>(undefined)
const [unavailableText, setUnavailableText] = useState<string | undefined>(undefined);
const fetchStockInLine = useCallback(
async (stockInLineId: number) => {
setUnavailableText(undefined)
setUnavailableText(undefined);
const res = await fetchStockInLineInfo(stockInLineId);
if (res.status.toLowerCase() === "received") {
console.log(res.acceptedQty)
formProps.setValue("acceptedQty", res.acceptedQty)
setDisabledSubmit(false)
console.log(res.acceptedQty);
formProps.setValue("acceptedQty", res.acceptedQty);
setDisabledSubmit(false);
setItemDetail(res);
} else if (res.status.toLowerCase() === "completed") {
setDisabledSubmit(true)
setDisabledSubmit(true);
} else {
//
setUnavailableText("Item Not Available")
setDisabledSubmit(true)
setUnavailableText("Item Not Available");
setDisabledSubmit(true);
}
// return
},
@@ -156,13 +165,13 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
setServerError(t("An error has occurred. Please try again later."));
return false;
}
return;
// return;
const res = await updateStockInLine(args);
if (Boolean(res.id)) {
// update entries
console.log(res);
// add loading
// closeHandler({}, "backdropClick");
closeHandler({}, "backdropClick");
}
console.log(res);
// if (res)
@@ -185,32 +194,39 @@ const QrModal: React.FC<Props> = ({ open, onClose, warehouse }) => {
>
<Grid container xs={12}>
<Grid item xs={12}>
{
itemDetail != undefined ? (
unavailableText != undefined ? <Typography variant="h4" marginInlineEnd={2}>{unavailableText}</Typography>
: (
<>
<PutawayForm itemDetail={itemDetail} warehouse={warehouse} disabled={false} />
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
type="submit"
disabled={disabledSubmit}
>
{t("submit")}
</Button>
</Stack>
</>

)
{itemDetail != undefined ? (
unavailableText != undefined ? (
<Typography variant="h4" marginInlineEnd={2}>
{unavailableText}
</Typography>
) : (
<>
<PutawayForm
itemDetail={itemDetail}
warehouse={warehouse}
disabled={false}
/>
<Stack direction="row" justifyContent="flex-end" gap={1}>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
type="submit"
disabled={disabledSubmit}
>
{t("submit")}
</Button>
</Stack>
</>
)
: (
// <ReactQrCodeScanner scannerConfig={scannerConfig} />
<Typography variant="h4">{t("Will start binding procedure after scanning item qr code.")}</Typography>
)
}
) : (
// <ReactQrCodeScanner scannerConfig={scannerConfig} />
<Typography variant="h4">
{t(
"Will start binding procedure after scanning item qr code."
)}
</Typography>
)}
</Grid>
</Grid>
</Box>


+ 88
- 60
src/components/PoSearch/PoSearch.tsx 파일 보기

@@ -10,10 +10,14 @@ import { EditNote } from "@mui/icons-material";
import { Button, Grid, Tab, Tabs, TabsProps, Typography } from "@mui/material";
import QrModal from "../PoDetail/QrModal";
import { WarehouseResult } from "@/app/api/warehouse";
import NotificationIcon from '@mui/icons-material/NotificationImportant';
import NotificationIcon from "@mui/icons-material/NotificationImportant";
import { useSession } from "next-auth/react";
import { defaultPagingController } from "../SearchResults/SearchResults";
import { fetchPoListClient } from "@/app/api/po/actions";
import { fetchPoListClient, testing } from "@/app/api/po/actions";
import dayjs from "dayjs";
import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import arraySupport from "dayjs/plugin/arraySupport";
dayjs.extend(arraySupport);

type Props = {
po: PoResult[];
@@ -24,23 +28,39 @@ type SearchQuery = Partial<Omit<PoResult, "id">>;
type SearchParamNames = keyof SearchQuery;

// cal offset (pageSize)
// cal limit (pageSize)
const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }) => {
// cal limit (pageSize)
const PoSearch: React.FC<Props> = ({
po,
warehouse,
totalCount: initTotalCount,
}) => {
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po);
const [filterArgs, setFilterArgs] = useState<Record<string, any>>({});
const { t } = useTranslation("purchaseOrder");
const router = useRouter();
const [pagingController, setPagingController] = useState(defaultPagingController)
const [totalCount, setTotalCount] = useState(initTotalCount)
const [pagingController, setPagingController] = useState(
defaultPagingController
);
const [totalCount, setTotalCount] = useState(initTotalCount);
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => {
var searchCriteria: Criterion<SearchParamNames>[] = [
{ label: t("Code"), paramName: "code", type: "text" },
{ label: t("Status"), paramName: "status", type: "select", options: ["PENDING", "RECEIVING", "COMPLETED"] },
{ label: t("Escalated"), paramName: "escalated", type: "select", options: [t("Escalated"), t("NotEscalated")] },
{
label: t("Status"),
paramName: "status",
type: "select",
options: [t(`pending`), t(`receiving`), t(`completed`)],
},
{
label: t("Escalated"),
paramName: "escalated",
type: "select",
options: [t("Escalated"), t("NotEscalated")],
},
];
return searchCriteria;
}, [t, po]);


const onDetailClick = useCallback(
(po: PoResult) => {
router.push(`/po/edit?id=${po.id}`);
@@ -65,6 +85,11 @@ const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }
{
name: "orderDate",
label: t("OrderDate"),
renderCell: (params) => {
return dayjs(params.orderDate)
.add(-1, "month")
.format(OUTPUT_DATE_FORMAT);
},
},
{
name: "supplier",
@@ -73,13 +98,18 @@ const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }
{
name: "status",
label: t("Status"),
renderCell: (params) => {
return t(`${params.status.toLowerCase()}`);
},
},
{
name: "escalated",
label: t("Escalated"),
renderCell: (params) => {
return params.escalated ? <NotificationIcon color="warning"/> : undefined
}
return params.escalated ? (
<NotificationIcon color="warning" />
) : undefined;
},
},
// {
// name: "name",
@@ -108,17 +138,30 @@ const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }
setOpenScanner(false);
}, []);

const newPageFetch = useCallback(async (pagingController: Record<string, number>) => {
const res = await fetchPoListClient(pagingController)
if (res) {
setFilteredPo(res.records)
setTotalCount(res.total)
}
}, [fetchPoListClient, pagingController])
const newPageFetch = useCallback(
async (
pagingController: Record<string, number>,
filterArgs: Record<string, number>
) => {
console.log(pagingController);
const params = {
...pagingController,
...filterArgs,
};
// const res = await fetchPoListClient(params);
const res = await testing(params);
if (res) {
console.log(res.records);
setFilteredPo(res.records);
setTotalCount(res.total);
}
},
[fetchPoListClient, pagingController]
);

useEffect(() => {
newPageFetch(pagingController)
}, [newPageFetch, pagingController])
newPageFetch(pagingController, filterArgs);
}, [newPageFetch, pagingController, filterArgs]);
return (
<>
<Grid container>
@@ -127,47 +170,32 @@ const PoSearch: React.FC<Props> = ({ po, warehouse, totalCount: initTotalCount }
{t("Purchase Order")}
</Typography>
</Grid>
<Grid
item
xs={4}
display="flex"
justifyContent="end"
alignItems="end"
>
<QrModal
open={isOpenScanner}
onClose={onCloseScanner}
warehouse={warehouse}
/>
<Button onClick={onOpenScanner}>bind</Button>
</Grid>
</Grid>
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilteredPo((prev) =>
prev.filter((p) => {
return (
p.code.toLowerCase().includes(query.code.toLowerCase()) &&
(query.status === "All" || p.status === query.status) &&
(query.escalated === "All" || p.escalated === (query.escalated === t("Escalated")))
)
})
);
}}
onReset={onReset}
<Grid item xs={4} display="flex" justifyContent="end" alignItems="end">
<QrModal
open={isOpenScanner}
onClose={onCloseScanner}
warehouse={warehouse}
/>
<SearchResults<PoResult>
items={filteredPo}
columns={columns}
pagingController={pagingController}
setPagingController={setPagingController}
totalCount={totalCount}
isAutoPaging={false}
/>
</>

<Button onClick={onOpenScanner}>bind</Button>
</Grid>
</Grid>
<>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
setFilterArgs({ ...query });
}}
onReset={onReset}
/>
<SearchResults<PoResult>
items={filteredPo}
columns={columns}
pagingController={pagingController}
setPagingController={setPagingController}
totalCount={totalCount}
isAutoPaging={false}
/>
</>
</>
);
};


+ 1
- 0
src/i18n/zh/purchaseOrder.json 파일 보기

@@ -6,6 +6,7 @@
"Supplier": "供應商",
"Status": "狀態",
"Escalated": "已上報",
"NotEscalated": "無上報",

"Do you want to start?": "確定開始嗎?",
"Start": "開始",


불러오는 중...
취소
저장