瀏覽代碼

Merge commit 'da4f29f41ba5ddf7d5f65436b14f45f6387b6d97'

# Conflicts:
#	src/components/PoDetail/PoDetail.tsx
master
CANCERYS\kw093 1 周之前
父節點
當前提交
87c7e7fb00
共有 20 個文件被更改,包括 376 次插入91 次删除
  1. +4
    -0
      src/app/(main)/settings/items/edit/page.tsx
  2. +7
    -0
      src/app/api/dashboard/index.ts
  3. +1
    -0
      src/app/api/settings/item/actions.ts
  4. +2
    -0
      src/app/api/settings/item/index.ts
  5. +12
    -0
      src/app/api/settings/qcCategory/index.ts
  6. +20
    -0
      src/app/api/shop/index.ts
  7. +4
    -1
      src/components/CreateItem/CreateItem.tsx
  8. +5
    -0
      src/components/CreateItem/CreateItemWrapper.tsx
  9. +36
    -4
      src/components/CreateItem/ProductDetails.tsx
  10. +14
    -2
      src/components/DashboardPage/DashboardPage.tsx
  11. +7
    -1
      src/components/DashboardPage/DashboardWrapper.tsx
  12. +93
    -0
      src/components/DashboardPage/QC/SupervisorQcApproval.tsx
  13. +14
    -14
      src/components/InventorySearch/InventoryLotLineTable.tsx
  14. +14
    -14
      src/components/InventorySearch/InventoryTable.tsx
  15. +105
    -28
      src/components/PoDetail/PoDetail.tsx
  16. +30
    -23
      src/components/PoDetail/PoInputGrid.tsx
  17. +1
    -1
      src/components/SearchResults/SearchResults.tsx
  18. +3
    -1
      src/i18n/zh/dashboard.json
  19. +3
    -2
      src/i18n/zh/inventory.json
  20. +1
    -0
      src/i18n/zh/items.json

+ 4
- 0
src/app/(main)/settings/items/edit/page.tsx 查看文件

@@ -1,3 +1,4 @@
import { fetchQcCategoryCombo } from "@/app/api/settings/qcCategory";
import { SearchParams } from "@/app/utils/fetchUtil";
import { TypeEnum } from "@/app/utils/typeEnum";
import CreateProductMaterial from "@/components/CreateItem";
@@ -17,6 +18,9 @@ const productSetting: React.FC<Props> = async ({ searchParams }) => {
if (!id) {
notFound();
}

fetchQcCategoryCombo()

return (
<>
{/* <Typography variant="h4">{t("Create Material")}</Typography> */}


+ 7
- 0
src/app/api/dashboard/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 { IQCItems } from "@/components/DashboardPage/QC/SupervisorQcApproval";

export interface PoResult {
id: number;
@@ -81,3 +82,9 @@ export const fetchPoWithStockInLines = cache(async (id: number) => {
next: { tags: ["po"] },
});
});

export const fetchIqcLogByUser = cache(async () => {
return serverFetchJson<IQCItems[]>(`${BASE_API_URL}/supervisionApprovalLog/stock-in`, {
next: { tags: ["qcLog"] },
});
});

+ 1
- 0
src/app/api/settings/item/actions.ts 查看文件

@@ -35,6 +35,7 @@ export type CreateItemInputs = {
type: string;
qcChecks: QcChecksInputs[];
qcChecks_active: number[];
qcCategoryId: number | undefined;
};

export const saveItem = async (data: CreateItemInputs) => {


+ 2
- 0
src/app/api/settings/item/index.ts 查看文件

@@ -4,6 +4,7 @@ import "server-only";
// import { BASE_API_URL } from "@/config/api";
import { serverFetchJson } from "../../../utils/fetchUtil";
import { BASE_API_URL } from "../../../../config/api";
import { QcCategoryResult } from "../qcCategory";

// import { TypeInputs, UomInputs, WeightUnitInputs } from "./actions";

@@ -37,6 +38,7 @@ export type ItemsResult = {
action?: any;
fgName?: string;
excludeDate?: string;
qcCategory?: QcCategoryResult;
};

export type Result = {


+ 12
- 0
src/app/api/settings/qcCategory/index.ts 查看文件

@@ -9,6 +9,12 @@ export interface QcCategoryResult {
name: string;
}

export interface QcCategoryCombo {
id: number;
value: number;
label: string;
}

export const preloadQcCategory = () => {
fetchQcCategories();
};
@@ -18,3 +24,9 @@ export const fetchQcCategories = cache(async () => {
next: { tags: ["qcCategories"] },
});
});

export const fetchQcCategoryCombo = cache(async () => {
return serverFetchJson<QcCategoryCombo[]>(`${BASE_API_URL}/qcCategories/combo`, {
next: { tags: ["qcCategoryCombo"] },
});
});

+ 20
- 0
src/app/api/shop/index.ts 查看文件

@@ -0,0 +1,20 @@
"server only"
import { BASE_API_URL } from '@/config/api';
import { serverFetchJson } from '@/app/utils/fetchUtil';
import { cache } from "react";

export interface ShopCombo {
id: number;
value: number; // id
label: string;
}

export const fetchSupplierCombo = cache(async() => {
return serverFetchJson<ShopCombo[]>(`${BASE_API_URL}/shop/combo/supplier`, {
method: "GET",
headers: { "Content-Type": "application/json"},
next: {
tags: ["supplierCombo"]
}
})
})

+ 4
- 1
src/components/CreateItem/CreateItem.tsx 查看文件

@@ -29,12 +29,14 @@ import QcDetails from "./QcDetails";
import { ItemQc } from "@/app/api/settings/item";
import { saveItemQcChecks } from "@/app/api/settings/qcCheck/actions";
import { useGridApiRef } from "@mui/x-data-grid";
import { QcCategoryCombo } from "@/app/api/settings/qcCategory";

type Props = {
isEditMode: boolean;
// type: TypeEnum;
defaultValues: Partial<CreateItemInputs> | undefined;
qcChecks: ItemQc[];
qcCategoryCombo: QcCategoryCombo[]
};

const CreateItem: React.FC<Props> = ({
@@ -42,6 +44,7 @@ const CreateItem: React.FC<Props> = ({
// type,
defaultValues,
qcChecks,
qcCategoryCombo,
}) => {
// console.log(type)
const apiRef = useGridApiRef();
@@ -192,7 +195,7 @@ const CreateItem: React.FC<Props> = ({
{serverError}
</Typography>
)}
{tabIndex === 0 && <ProductDetails isEditMode={isEditMode} />}
{tabIndex === 0 && <ProductDetails isEditMode={isEditMode} qcCategoryCombo={qcCategoryCombo}/>}
{tabIndex === 1 && <QcDetails apiRef={apiRef} />}
{/* {type === TypeEnum.MATERIAL && <MaterialDetails />} */}
{/* {type === TypeEnum.BYPRODUCT && <ByProductDetails />} */}


+ 5
- 0
src/components/CreateItem/CreateItemWrapper.tsx 查看文件

@@ -5,6 +5,7 @@ import { CreateItemInputs } from "@/app/api/settings/item/actions";
import { notFound } from "next/navigation";
import { fetchItem } from "@/app/api/settings/item";
import { fetchQcItems } from "@/app/api/settings/qcItem";
import { fetchQcCategoryCombo } from "@/app/api/settings/qcCategory";
interface SubComponents {
Loading: typeof CreateItemLoading;
}
@@ -37,14 +38,18 @@ const CreateItemWrapper: React.FC<Props> & SubComponents = async ({ id }) => {
maxQty: item?.maxQty,
qcChecks: qcChecks,
qcChecks_active: activeRows,
qcCategoryId: item.qcCategory?.id
};
}

const qcCategoryCombo = await fetchQcCategoryCombo();

return (
<CreateItem
isEditMode={Boolean(id)}
defaultValues={defaultValues}
qcChecks={qcChecks || []}
qcCategoryCombo={qcCategoryCombo}
/>
);
};


+ 36
- 4
src/components/CreateItem/ProductDetails.tsx 查看文件

@@ -1,5 +1,6 @@
"use client";
import {
Autocomplete,
Box,
Button,
Card,
@@ -10,11 +11,11 @@ import {
Typography,
} from "@mui/material";
import { Check, Close, EditNote } from "@mui/icons-material";
import { useFormContext } from "react-hook-form";
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import InputDataGrid from "../InputDataGrid";

import { useCallback, useMemo, useState } from "react";
import { SyntheticEvent, useCallback, useMemo, useState } from "react";
import { GridColDef, GridRowModel } from "@mui/x-data-grid";
import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
import { TypeEnum } from "@/app/utils/typeEnum";
@@ -22,6 +23,7 @@ import { NumberInputProps } from "./NumberInputProps";
import { CreateItemInputs } from "@/app/api/settings/item/actions";
import { RestartAlt } from "@mui/icons-material";
import { ItemQc } from "@/app/api/settings/item";
import { QcCategoryCombo } from "@/app/api/settings/qcCategory";
type Props = {
// isEditMode: boolean;
// type: TypeEnum;
@@ -29,9 +31,10 @@ type Props = {
// type: TypeEnum;
defaultValues?: Partial<CreateItemInputs> | undefined;
qcChecks?: ItemQc[];
qcCategoryCombo: QcCategoryCombo[];
};

const ProductDetails: React.FC<Props> = ({ isEditMode }) => {
const ProductDetails: React.FC<Props> = ({ isEditMode, qcCategoryCombo }) => {
const {
t,
i18n: { language },
@@ -104,6 +107,11 @@ const ProductDetails: React.FC<Props> = ({ isEditMode }) => {
// router.replace(`/settings/product`);
console.log("cancel");
};

const handleAutoCompleteChange = useCallback((event: SyntheticEvent<Element, Event>, value: QcCategoryCombo, onChange: (...event: any[]) => void) => {
onChange(value.id)
}, [])

return (
<Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}>
@@ -202,7 +210,31 @@ const ProductDetails: React.FC<Props> = ({ isEditMode }) => {
helperText={errors.maxQty?.message}
/>
</Grid>
<Grid item xs={0}>
<Grid item xs={6}>
<Controller
control={control}
name="qcCategoryId"
render={({ field }) => (
<Autocomplete
disableClearable
options={qcCategoryCombo}
defaultValue={qcCategoryCombo.find(qc => qc.id === field.value)}
onChange={(event, value) => {
handleAutoCompleteChange(event, value, field.onChange)
}}
onBlur={field.onBlur}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label={t("Qc Category")}
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={12}>
<Stack
direction="row"
justifyContent="flex-end"


+ 14
- 2
src/components/DashboardPage/DashboardPage.tsx 查看文件

@@ -14,15 +14,27 @@ import ApplicationCompletionChart from "./chart/ApplicationCompletionChart";
import OrderCompletionChart from "./chart/OrderCompletionChart";
import DashboardBox from "./Dashboardbox";
import CollapsibleCard from "./CollapsibleCard";
type Props = {};
import SupervisorQcApproval, { IQCItems } from "./QC/SupervisorQcApproval";
type Props = {
iqc: IQCItems[]
};

const DashboardPage: React.FC<Props> = ({}) => {
const DashboardPage: React.FC<Props> = ({
iqc
}) => {
const { t } = useTranslation("dashboard");
const router = useRouter();

return (
<ThemeProvider theme={theme}>
<Grid container spacing={2}>
<Grid item xs={12}>
<CollapsibleCard title={t("stock in escalation list")}>
<CardContent>
<SupervisorQcApproval items={iqc || []}/>
</CardContent>
</CollapsibleCard>
</Grid>
<Grid item xs={12}>
<CollapsibleCard title={t("Progress chart")}>
<CardContent>


+ 7
- 1
src/components/DashboardPage/DashboardWrapper.tsx 查看文件

@@ -4,6 +4,7 @@ import DashboardPage from "./DashboardPage";
import { Typography } from "@mui/material";
import { I18nProvider, getServerI18n } from "@/i18n";
import DashboardLoading from "./DashboardLoading";
import { fetchIqcLogByUser } from "@/app/api/dashboard";

// export type SessionWithAbilities = {
// abilities: string[]
@@ -22,11 +23,16 @@ const DashboardWrapper: React.FC<Props> & SubComponents = async ({
}) => {
const { t } = await getServerI18n("dashboard");
// const session: SessionWithAbilities = await getServerSession(authOptions)

const [iqcLog] = await Promise.all([
fetchIqcLogByUser()
])
console.log(iqcLog)
return (
<>
<Typography variant="h4">{t("Dashboard")}</Typography>
<DashboardPage
iqc={iqcLog}
// abilities={session ? session?.abilities : []}
/>
</>


+ 93
- 0
src/components/DashboardPage/QC/SupervisorQcApproval.tsx 查看文件

@@ -0,0 +1,93 @@
"use client"

import { Box, Card, CardActionArea, CardContent, CardHeader, Grid, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography } from "@mui/material";
import { useRouter } from "next/navigation";
import { useCallback, useState } from "react";
import { usePathname } from "next/navigation";
import { useTranslation } from "react-i18next";

export type IQCItems = {
id: number;
poId: number;
polId: number;
stockInLineId: number;
poCode: string
itemName: string
escalationLevel: string
reason: string
};

type Props = {
items: IQCItems[];
};

const SupervisorQcApproval: React.FC<Props> = ({
items
}) => {
const { t } = useTranslation("dashboard");
const CARD_HEADER = t("stock in escalation list")

const pathname = usePathname();
const router = useRouter();
const [selectedId, setSelectedId] = useState<number | null>(null);

const navigateTo = useCallback(
(item: IQCItems) => {
setSelectedId(item.id);
console.log(pathname)
router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`);
},
[router, pathname]
);

const handleKeyDown = useCallback(
(e: React.KeyboardEvent, item: IQCItems) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
navigateTo(item);
}
},
[navigateTo]
);

return (
<TableContainer component={Paper}>
<Table aria-label="Two column navigable table" size="small">
<TableHead>
<TableRow>
<TableCell>{t("purchase order code")}</TableCell>
<TableCell>{t("item name")}</TableCell>
<TableCell>{t("escalation level")}</TableCell>
<TableCell>{t("reason")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((item) => {
const selected = selectedId === item.id;
return (
<TableRow
key={item.id}
hover
selected={selected}
onClick={() => navigateTo(item)}
// onKeyDown={(e) => handleKeyDown(e, item)}
tabIndex={0}
sx={{ cursor: 'pointer' }}
// aria-label={`${item.name}, ${item.detail}`}
>
<TableCell component="th" scope="row">
{item.poCode}
</TableCell>
<TableCell>{item.itemName}</TableCell>
<TableCell>{item.escalationLevel}</TableCell>
<TableCell>{item.reason}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
);
};

export default SupervisorQcApproval;

+ 14
- 14
src/components/InventorySearch/InventoryLotLineTable.tsx 查看文件

@@ -82,23 +82,23 @@ const InventoryLotLineTable: React.FC<Props> = ({ inventoryLotLines, pagingContr
},
{
name: "uom",
label: t("Sales UoM"),
align: "left",
headerAlign: "left",
},
{
name: "qtyPerSmallestUnit",
label: t("Available Qty Per Smallest Unit"),
align: "right",
headerAlign: "right",
type: "integer",
},
{
name: "baseUom",
label: t("Base UoM"),
label: t("Stock UoM"),
align: "left",
headerAlign: "left",
},
// {
// name: "qtyPerSmallestUnit",
// label: t("Available Qty Per Smallest Unit"),
// align: "right",
// headerAlign: "right",
// type: "integer",
// },
// {
// name: "baseUom",
// label: t("Base UoM"),
// align: "left",
// headerAlign: "left",
// },
{
name: "expiryDate",
label: t("Expiry Date"),


+ 14
- 14
src/components/InventorySearch/InventoryTable.tsx 查看文件

@@ -41,25 +41,25 @@ const InventoryTable: React.FC<Props> = ({ inventories, pagingController, setPag
},
{
name: "uomUdfudesc",
label: t("Sales UoM"),
align: "left",
headerAlign: "left",
},
{
name: "qtyPerSmallestUnit",
label: t("Available Qty Per Smallest Unit"),
align: "right",
headerAlign: "right",
type: "integer",
},
{
name: "baseUom",
label: t("Base UoM"),
label: t("Stock UoM"),
align: "left",
headerAlign: "left",
},
// {
// name: "qtyPerSmallestUnit",
// label: t("Available Qty Per Smallest Unit"),
// align: "right",
// headerAlign: "right",
// type: "integer",
// },
// {
// name: "baseUom",
// label: t("Base UoM"),
// align: "left",
// headerAlign: "left",
// },
// {
// name: "qtyPerSmallestUnit",
// label: t("Qty Per Smallest Unit"),
// align: "right",
// headerAlign: "right",


+ 105
- 28
src/components/PoDetail/PoDetail.tsx 查看文件

@@ -66,11 +66,9 @@ import DoneIcon from "@mui/icons-material/Done";
import { getCustomWidth } from "@/app/utils/commonUtil";
import PoInfoCard from "./PoInfoCard";
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil";



import { fetchPoListClient } from "@/app/api/po/actions";
import { List, ListItem, ListItemButton, ListItemText, Divider } from "@mui/material";
import { createStockInLine } from "@/app/api/dashboard/actions";
//import { useRouter } from "next/navigation";


@@ -181,20 +179,13 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
purchaseOrder.pol || [],
);
const pathname = usePathname()
const router = useRouter();
const searchParams = useSearchParams();
const [row, setRow] = useState(rows[0]);
const [stockInLine, setStockInLine] = useState(rows[0].stockInLine);
const [stockInLine, setStockInLine] = useState<StockInLine[]>(rows[0].stockInLine);
const [processedQty, setProcessedQty] = useState(rows[0].processed);

// const [currPoStatus, setCurrPoStatus] = useState(purchaseOrder.status);





//const router = useRouter();
const router = useRouter();
const [poList, setPoList] = useState<PoResult[]>([]);
const [selectedPoId, setSelectedPoId] = useState(po.id);
const currentPoId = searchParams.get('id');
@@ -297,14 +288,18 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
setRows(purchaseOrder.pol || []);
}, [purchaseOrder]);

// useEffect(() => {
// setStockInLine([])
// }, []);

function Row(props: { row: PurchaseOrderLine }) {
const { row } = props;
const [firstReceiveQty, setFirstReceiveQty] = useState<number>()
// const [firstReceiveQty, setFirstReceiveQty] = useState<number>()
const [secondReceiveQty, setSecondReceiveQty] = useState<number>()
const [open, setOpen] = useState(false);
// const [open, setOpen] = useState(false);
const [processedQty, setProcessedQty] = useState(row.processed);
const [currStatus, setCurrStatus] = useState(row.status);
const [stockInLine, setStockInLine] = useState(row.stockInLine);
// const [stockInLine, setStockInLine] = useState(row.stockInLine);
const totalWeight = useMemo(
() => calculateWeight(row.qty, row.uom),
[row.qty, row.uom],
@@ -314,6 +309,13 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
[row.uom],
);

useEffect(() => {
const polId = searchParams.get("polId") != null ? parseInt(searchParams.get("polId")!) : null
if (polId) {
setStockInLine(rows.find((r) => r.id == polId)!.stockInLine)
}
}, []);

useEffect(() => {
if (processedQty === row.qty) {
setCurrStatus("completed".toUpperCase());
@@ -330,9 +332,72 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
setStockInLine(row.stockInLine);
setProcessedQty(row.processed);
};
const changeStockInLines = useCallback(
(id: number) => {
console.log(id)
//rows = purchaseOrderLine
console.log(rows)
const target = rows.find((r) => r.id === id)
const stockInLine = target!.stockInLine
console.log(stockInLine)
setStockInLine(stockInLine)
setRow(target!)
// console.log(pathname)
// router.replace(`/po/edit?id=${item.poId}&polId=${item.polId}&stockInLineId=${item.stockInLineId}`);
},
[rows]
);

const handleStart = useCallback(
() => {
setTimeout(async () => {
// post stock in line
const oldId = row.id;
const postData = {
itemId: row.itemId,
itemNo: row.itemNo,
itemName: row.itemName,
purchaseOrderId: row.purchaseOrderId,
purchaseOrderLineId: row.id,
acceptedQty: secondReceiveQty || 0,
// acceptedQty: row.acceptedQty,
};
if (secondReceiveQty === 0) return
const res = await createStockInLine(postData);
console.log(res);
}, 200);
},
[],
);

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const raw = e.target.value;

// Allow empty input
if (raw.trim() === '') {
setSecondReceiveQty(undefined);
return;
}

// Keep digits only
const cleaned = raw.replace(/[^\d]/g, '');
if (cleaned === '') {
// If the user typed only non-digits, keep previous value
return;
}

// Parse and clamp to non-negative integer
const next = Math.max(0, Math.floor(Number(cleaned)));
setSecondReceiveQty(next);
};
return (
<>
<TableRow sx={{ "& > *": { borderBottom: "unset" }, color: "black" }}>
<TableRow
sx={{ "& > *": { borderBottom: "unset" },
color: "black"
}}
onClick={() => changeStockInLines(row.id)}
>
{/* <TableCell>
<IconButton
disabled={purchaseOrder.status.toLowerCase() === "pending"}
@@ -355,9 +420,9 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
<TableCell align="right">{integerFormatter.format(row.qty)}</TableCell>
<TableCell align="right">{integerFormatter.format(processedQty)}</TableCell>
<TableCell align="left">{row.uom?.code}</TableCell>
<TableCell align="right">
{/* <TableCell align="right">
{decimalFormatter.format(totalWeight)} {weightUnit}
</TableCell>
</TableCell> */}
{/* <TableCell align="left">{weightUnit}</TableCell> */}
<TableCell align="right">{decimalFormatter.format(row.price)}</TableCell>
{/* <TableCell align="left">{row.expiryDate}</TableCell> */}
@@ -371,7 +436,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
type="text" // Use type="text" to allow validation in the change handler
variant="outlined"
value={secondReceiveQty}
// onChange={handleChange}
onChange={handleChange}
InputProps={{
inputProps: {
min: 0, // Optional: set a minimum value
@@ -381,7 +446,12 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
/>
</TableCell>
<TableCell align="center">
<Button variant="contained">
<Button
variant="contained"
onClick={() =>
handleStart()
}
>
提交
</Button>
</TableCell>
@@ -503,7 +573,6 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
const renderFieldCondition = useCallback((field: "firstInQty" | "secondInQty"): boolean => {
switch (field) {
case FIRST_IN_FIELD:

return true;
case SECOND_IN_FIELD:
return true;
@@ -512,6 +581,14 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
}
}, []);

useEffect(() => {
const params = searchParams.get("polId")
if (params) {
const polId = parseInt(params)

}
}, [searchParams])

return (
<>
<Stack spacing={2}>
@@ -546,12 +623,12 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
type="text"
variant="outlined"
fullWidth
InputProps={{
inputProps: {
min: 0,
step: 1
}
}}
// InputProps={{
// inputProps: {
// min: 0,
// step: 1
// }
// }}
/>
<TextField
label={t("dnDate")}
@@ -589,7 +666,7 @@ const PoDetail: React.FC<Props> = ({ po, qc, warehouse }) => {
<TableCell align="right">{t("qty")}</TableCell>
<TableCell align="right">{t("processed")}</TableCell>
<TableCell align="left">{t("uom")}</TableCell>
<TableCell align="right">{t("total weight")}</TableCell>
{/* <TableCell align="right">{t("total weight")}</TableCell> */}
<TableCell align="right">{`${t("price")} (HKD)`}</TableCell>
<TableCell align="left" sx={{ width: '75px' }}>{t("status")}</TableCell>
{renderFieldCondition(FIRST_IN_FIELD) ? <TableCell align="right">{t("receivedQty")}</TableCell> : undefined}


+ 30
- 23
src/components/PoDetail/PoInputGrid.tsx 查看文件

@@ -121,6 +121,9 @@ function PoInputGrid({
);
console.log(stockInLine);
const [entries, setEntries] = useState<StockInLineRow[]>(stockInLine || []);
useEffect(() => {
setEntries(stockInLine)
}, [stockInLine])
const [modalInfo, setModalInfo] = useState<
StockInLine & { qcResult?: PurchaseQcResult[] }
>();
@@ -278,16 +281,11 @@ const closeNewModal = useCallback(() => {
setNewOpen(true);
}, []);

// Open modal if `stockInLineId` exists in the URL
useEffect(() => {
if (stockInLineId && !newOpen) {
openNewModal();
}
}, [stockInLineId, newOpen, openNewModal]);

// Button handler to update the URL and open the modal
const handleNewQC = useCallback(
(id: GridRowId, params: any) => async () => {
console.log(id)
console.log(params)
setBtnIsLoading(true);
setRowModesModel((prev) => ({
...prev,
@@ -304,12 +302,21 @@ const closeNewModal = useCallback(() => {
const newParams = new URLSearchParams(searchParams.toString());
newParams.set("stockInLineId", id.toString()); // Ensure `set` to avoid duplicates
router.replace(`${pathname}?${newParams.toString()}`);
console.log("hello")
openNewModal()
setBtnIsLoading(false);
}, 200);
},
[fetchQcDefaultValue, searchParams, router, pathname]
[fetchQcDefaultValue, openNewModal, pathname, router, searchParams]
);

// Open modal if `stockInLineId` exists in the URL
useEffect(() => {
if (stockInLineId) {
console.log("heeloo")
console.log(stockInLineId)
handleNewQC(stockInLineId, apiRef.current.getRow(stockInLineId));
}
}, [stockInLineId, newOpen, handleNewQC, apiRef]);
const handleEscalation = useCallback(
(id: GridRowId, params: any) => () => {
// setBtnIsLoading(true);
@@ -476,20 +483,20 @@ const closeNewModal = useCallback(() => {
return params.row.uom.code;
},
},
{
field: "weight",
headerName: t("weight"),
width: 120,
// flex: 0.5,
renderCell: (params) => {
const weight = calculateWeight(
params.row.acceptedQty,
params.row.uom,
);
const weightUnit = returnWeightUnit(params.row.uom);
return `${decimalFormatter.format(weight)} ${weightUnit}`;
},
},
// {
// field: "weight",
// headerName: t("weight"),
// width: 120,
// // flex: 0.5,
// renderCell: (params) => {
// const weight = calculateWeight(
// params.row.acceptedQty,
// params.row.uom,
// );
// const weightUnit = returnWeightUnit(params.row.uom);
// return `${decimalFormatter.format(weight)} ${weightUnit}`;
// },
// },
{
field: "status",
headerName: t("status"),


+ 1
- 1
src/components/SearchResults/SearchResults.tsx 查看文件

@@ -281,7 +281,7 @@ function SearchResults<T extends ResultWithId>({
setCheckboxIds(newSelected);
}
},
[checkboxIds],
[checkboxIds, setCheckboxIds],
);

const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {


+ 3
- 1
src/i18n/zh/dashboard.json 查看文件

@@ -29,5 +29,7 @@
"Pending application": "待處理提料申請",
"pending inspection material": "待品檢物料",
"inspected material": "已品檢物料",
"total material": "物料總數"
"total material": "物料總數",

"stock in escalation list": "收貨已上報列表"
}

+ 3
- 2
src/i18n/zh/inventory.json 查看文件

@@ -8,12 +8,13 @@
"UoM": "單位",
"mat": "物料",
"fg": "成品",
"Available Qty": "可用數量 (銷售單位)",
"Available Qty": "可用數量 (倉存單位)",
"Sales UoM": "銷售單位",
"Stock UoM": "倉存單位",
"Available Qty Per Smallest Unit": "可用數量 (基本單位)",
"Base UoM": "基本單位",
"Lot No": "批號",
"Expiry Date": "到期日",
"No items are selected yet.": "未選擇項目",
"Item selected": "已選擇項目"
}
}

+ 1
- 0
src/i18n/zh/items.json 查看文件

@@ -10,6 +10,7 @@
"Product / Material": "產品 / 材料",
"Product / Material Details": "產品 / 材料詳情",
"Qc items": "QC 項目",
"Qc Category": "質檢模板",
"Name": "名稱",
"name": "名稱",
"description": "描述",


Loading…
取消
儲存