Browse Source

add qc category to item master, update inventory

master
cyril.tsui 1 week ago
parent
commit
d2789b064f
9 changed files with 109 additions and 35 deletions
  1. +12
    -0
      src/app/api/settings/qcCategory/index.ts
  2. +20
    -0
      src/app/api/shop/index.ts
  3. +4
    -1
      src/components/CreateItem/CreateItem.tsx
  4. +5
    -0
      src/components/CreateItem/CreateItemWrapper.tsx
  5. +36
    -4
      src/components/CreateItem/ProductDetails.tsx
  6. +14
    -14
      src/components/InventorySearch/InventoryLotLineTable.tsx
  7. +14
    -14
      src/components/InventorySearch/InventoryTable.tsx
  8. +3
    -2
      src/i18n/zh/inventory.json
  9. +1
    -0
      src/i18n/zh/items.json

+ 12
- 0
src/app/api/settings/qcCategory/index.ts View File

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


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

export const preloadQcCategory = () => { export const preloadQcCategory = () => {
fetchQcCategories(); fetchQcCategories();
}; };
@@ -18,3 +24,9 @@ export const fetchQcCategories = cache(async () => {
next: { tags: ["qcCategories"] }, 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 View File

@@ -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 View File

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


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


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


+ 5
- 0
src/components/CreateItem/CreateItemWrapper.tsx View File

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


const qcCategoryCombo = await fetchQcCategoryCombo();

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


+ 36
- 4
src/components/CreateItem/ProductDetails.tsx View File

@@ -1,5 +1,6 @@
"use client"; "use client";
import { import {
Autocomplete,
Box, Box,
Button, Button,
Card, Card,
@@ -10,11 +11,11 @@ import {
Typography, Typography,
} from "@mui/material"; } from "@mui/material";
import { Check, Close, EditNote } from "@mui/icons-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 { useTranslation } from "react-i18next";
import InputDataGrid from "../InputDataGrid"; 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 { GridColDef, GridRowModel } from "@mui/x-data-grid";
import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid";
import { TypeEnum } from "@/app/utils/typeEnum"; import { TypeEnum } from "@/app/utils/typeEnum";
@@ -22,6 +23,7 @@ import { NumberInputProps } from "./NumberInputProps";
import { CreateItemInputs } from "@/app/api/settings/item/actions"; import { CreateItemInputs } from "@/app/api/settings/item/actions";
import { RestartAlt } from "@mui/icons-material"; import { RestartAlt } from "@mui/icons-material";
import { ItemQc } from "@/app/api/settings/item"; import { ItemQc } from "@/app/api/settings/item";
import { QcCategoryCombo } from "@/app/api/settings/qcCategory";
type Props = { type Props = {
// isEditMode: boolean; // isEditMode: boolean;
// type: TypeEnum; // type: TypeEnum;
@@ -29,9 +31,10 @@ type Props = {
// type: TypeEnum; // type: TypeEnum;
defaultValues?: Partial<CreateItemInputs> | undefined; defaultValues?: Partial<CreateItemInputs> | undefined;
qcChecks?: ItemQc[]; qcChecks?: ItemQc[];
qcCategoryCombo: QcCategoryCombo[];
}; };


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

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

return ( return (
<Card sx={{ display: "block" }}> <Card sx={{ display: "block" }}>
<CardContent component={Stack} spacing={4}> <CardContent component={Stack} spacing={4}>
@@ -202,7 +210,31 @@ const ProductDetails: React.FC<Props> = ({ isEditMode }) => {
helperText={errors.maxQty?.message} helperText={errors.maxQty?.message}
/> />
</Grid> </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 <Stack
direction="row" direction="row"
justifyContent="flex-end" justifyContent="flex-end"


+ 14
- 14
src/components/InventorySearch/InventoryLotLineTable.tsx View File

@@ -82,23 +82,23 @@ const InventoryLotLineTable: React.FC<Props> = ({ inventoryLotLines, pagingContr
}, },
{ {
name: "uom", 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", align: "left",
headerAlign: "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", name: "expiryDate",
label: t("Expiry Date"), label: t("Expiry Date"),


+ 14
- 14
src/components/InventorySearch/InventoryTable.tsx View File

@@ -41,25 +41,25 @@ const InventoryTable: React.FC<Props> = ({ inventories, pagingController, setPag
}, },
{ {
name: "uomUdfudesc", 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", align: "left",
headerAlign: "left", headerAlign: "left",
}, },
// { // {
// name: "qtyPerSmallestUnit", // 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"), // label: t("Qty Per Smallest Unit"),
// align: "right", // align: "right",
// headerAlign: "right", // headerAlign: "right",


+ 3
- 2
src/i18n/zh/inventory.json View File

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

+ 1
- 0
src/i18n/zh/items.json View File

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


Loading…
Cancel
Save