浏览代码

update stock in form & expiry date modal

master
kelvinsuen 2 个月前
父节点
当前提交
f68407eb78
共有 7 个文件被更改,包括 573 次插入108 次删除
  1. +1
    -1
      src/app/(main)/po/page.tsx
  2. +299
    -0
      src/components/StockIn/CalculateExpiryDateModal.tsx
  3. +25
    -18
      src/components/StockIn/FgStockInForm.tsx
  4. +153
    -0
      src/components/StockIn/ShelfLifeInput.tsx
  5. +86
    -87
      src/components/StockIn/StockInForm.tsx
  6. +1
    -1
      src/i18n/zh/items.json
  7. +8
    -1
      src/i18n/zh/purchaseOrder.json

+ 1
- 1
src/app/(main)/po/page.tsx 查看文件

@@ -17,7 +17,7 @@ const PurchaseOrder: React.FC = async () => {
// preloadClaims();
return (
<>
<I18nProvider namespaces={["purchaseOrder", "common"]}>
<I18nProvider namespaces={["purchaseOrder", "common", "items"]}>
<Stack
direction="row"
justifyContent="space-between"


+ 299
- 0
src/components/StockIn/CalculateExpiryDateModal.tsx 查看文件

@@ -0,0 +1,299 @@

import { OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { Check, SwapHoriz, Add } from "@mui/icons-material";
import { Box, Button, Card, Grid, Modal, Stack, TextField, Typography } from "@mui/material";
import { DatePicker, DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import dayjs, { Dayjs } from "dayjs";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { msg } from "../Swal/CustomAlerts";
import ShelfLifeInput from "./ShelfLifeInput";

interface Props {
open: boolean;
onClose: () => void;
onSubmit: (result: Dayjs) => void;
textfieldSx?: any;
}

type EntryError =
{
productionDate: string,
expiryDate: string,
shelfLife: string,
}

const CalculateExpiryDateModal: React.FC<Props> = ({
open,
onClose,
onSubmit,
textfieldSx,
}) => {
const { t, i18n: { language }, } = useTranslation("purchaseOrder");

const [productionDate, setProductionDate] = useState<Dayjs>();
const [shelfLife, setShelfLife] = useState<number>();
const [expiryDate, setExpiryDate] = useState<Dayjs>();
const [errors, setErrors] = useState<EntryError>({ productionDate: "", expiryDate: "", shelfLife: "" });

const onModalClose = useCallback(() => {
setProductionDate(undefined);
setExpiryDate(undefined);
setShelfLife(undefined);
onClose();
}, [])

const handleSubmit = useCallback(() => {
if (expiryDate) {
onSubmit(expiryDate);
}
onModalClose();
}, [onModalClose, expiryDate])

const hasError = useMemo(() => {
return Object.values(errors).some(err => err.length > 0);
}, [errors])

// Validation
useEffect(() => {
let err = { productionDate: "", expiryDate: "", shelfLife: "" };

// Check Expiry Date
if (expiryDate !== undefined) {
// Check Validity (If allow input for Expiry Date)
// if (!expiryDate.isValid()) { err = ({...err, expiryDate: t("Invalid Date")}); } else
// Check date logic
if (shelfLife === undefined && productionDate && expiryDate.isBefore(productionDate)) {
err = ({...err, expiryDate: t("Expiry Date cannot be earlier than Production Date")});
}
}

// Check Production Date
if (productionDate !== undefined) {
// Check Validity
if (!productionDate.isValid()) { err = ({...err, productionDate: t("Invalid Date")}); }
// Check date logic
else if (shelfLife === undefined && expiryDate && productionDate.isAfter(expiryDate)) {
err = ({...err, productionDate: t("Production Date must be earlier than Expiry Date")});
}
}

// Check Shelf Life
// if (shelfLife === undefined) {
// err = ({...err, shelfLife: t("Shelf Life must be greater than 0")});
// }
setErrors(err);
}, [expiryDate, productionDate, shelfLife]);

const calculateDates = useCallback((value: Dayjs | number | null = null,
valueType: "productionDate" | "shelfLife" | "expiryDate" | undefined = undefined) => {

let pd = productionDate;
let ed = expiryDate;
let sl = shelfLife;

if (value !== null && value !== undefined) {
if (dayjs.isDayjs(value)) {
if (valueType == "expiryDate") {
ed = value;
} else {
pd = value;
}
} else if (!isNaN(value)) {
sl = value;
} else {
console.log("%c Invalid input value for calculation", "color:red", value);
return;
}
} else {
if (valueType !== undefined) {
ed = undefined; // Clear Expiry Date if fields are cleared
switch (valueType) {
case "productionDate": pd = undefined; break;
case "shelfLife": sl = undefined; break;
// case "expiryDate": ed = undefined; break;
default: console.log("%c Invalid value type for calculation", "color:red", valueType); return;
}
}
}

if (pd && ed && sl !== undefined) { // If all values are set
if (valueType == "expiryDate") { // If updating Expiry Date -> Change Production Date
const result = ed.add(sl * -1, "day");
setProductionDate(result);
} else { // If not updating Expiry Date -> Change Expiry Date
const result = pd.add(sl, "day");
setExpiryDate(result);
}

} else if (pd && sl !== undefined) { // Set Expiry Date
const result = pd.add(sl, "day");
if (result.isValid()) { setExpiryDate(result); }
} else if (sl !== undefined && ed) { // Set Production Date
const result = ed.add(sl * -1, "day");
if (result.isValid()) { setProductionDate(result); }
} else if (pd && ed) { // Set Shelf Life
const result = ed.diff(pd, "day");
if (!isNaN(result) && result > 0) { setShelfLife(result); }
} else {
setExpiryDate(undefined);
}
}, [productionDate, shelfLife, expiryDate]);

return (
<Modal
open={open}
onClose={onModalClose}
>
<Card
style={{
flex: 10,
marginBottom: "20px",
width: "80%",
// height: "80%",
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
}}
>
<Box
sx={{
display: "block",
"flex-direction": "column",
padding: "20px",
height: "100%", //'30rem',
width: "100%",
"& .actions": {
color: "text.secondary",
},
"& .header": {
},
"& .textPrimary": {
color: "text.primary",
},
}}
>
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<Stack sx={{mb: 1}}>
<Typography variant="h4" component="h2" sx={{ fontWeight: 'bold', mb: 2 }}>
{t("Fill in Expiry Date")}
</Typography>
</Stack>
<Stack>
<Grid
container
justifyContent="flex-start"
alignItems="flex-start"
spacing={2}
>
<Grid item xs={2.5}>
<DatePicker
sx={textfieldSx}
label={t("productionDate")}
value={productionDate ? dayjs(productionDate) : null}
format={OUTPUT_DATE_FORMAT}
onChange={(date) => {
if (!date) {
setProductionDate(undefined);
} else {
setProductionDate(date);
}
calculateDates(date, "productionDate");
}}
slotProps={{
textField: {
error: errors.productionDate.length > 0,
helperText: errors.productionDate,
},
}}
/>
</Grid>
<Grid item xs={0.5} sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100%',
}}>
<Add sx={{
fontSize: '60px', color:'secondary.main',
transform: 'translate(10%, 15%)',
}}/>
</Grid>
<Grid item xs={4}>
<ShelfLifeInput
sx={textfieldSx}
value={shelfLife}
label={t("shelfLife")}
onChange={(value) => {
const val = value == 0 ? undefined : value;
setShelfLife(val);
calculateDates(val, "shelfLife");
}}
/>
</Grid>

<Grid item xs={1} sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100%',
}}>
<SwapHoriz sx={{fontSize: '80px', color:'secondary.main'}}/>
</Grid>
<Grid item xs={4}>
<DatePicker
sx={textfieldSx}
label={t("expiryDate")}
format={OUTPUT_DATE_FORMAT}
value={expiryDate ? dayjs(expiryDate) : null}
onChange={(date) => {
if (!date) {
setExpiryDate(undefined);
} else {
setExpiryDate(date);
calculateDates(date, "expiryDate");
}
}}
slotProps={{
textField: {
error: errors.expiryDate.length > 0,
helperText: errors.expiryDate,
},
}}
disabled={true}
/>
</Grid>
</Grid>
</Stack>
<Stack
direction="row"
justifyContent="flex-end"
spacing={2}
sx={{ mt: 2 }}
>
<Button
name="submit"
variant="contained"
startIcon={<Check />}
sx={{fontSize: '24px'}}
disabled={expiryDate === undefined || hasError}
onClick={handleSubmit}
>
{t("confirm expiry date")}
</Button>
</Stack>
</LocalizationProvider>
</Box>
</Card>
</Modal>
)
}

export default CalculateExpiryDateModal;

+ 25
- 18
src/components/StockIn/FgStockInForm.tsx 查看文件

@@ -33,7 +33,7 @@ import { GridEditInputCell } from "@mui/x-data-grid";
import { StockInLine } from "@/app/api/stockIn";
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import dayjs from "dayjs";
// change PurchaseQcResult to stock in entry props
interface Props {
@@ -60,14 +60,14 @@ const textfieldSx = {
height: "100%",
boxSizing: "border-box",
padding: "0.75rem",
fontSize: 24,
fontSize: 30,
},
"& .MuiInputLabel-root": {
fontSize: 24,
transform: "translate(14px, 1.5rem) scale(1)",
fontSize: 30,
transform: "translate(14px, 1.2rem) scale(1)",
"&.MuiInputLabel-shrink": {
fontSize: 18,
transform: "translate(14px, -9px) scale(1)",
fontSize: 24,
transform: "translate(14px, -0.5rem) scale(1)",
},
// [theme.breakpoints.down("sm")]: {
// fontSize: "1rem",
@@ -200,6 +200,7 @@ const FgStockInForm: React.FC<Props> = ({
sx={textfieldSx}
label={t("receiptDate")}
value={dayjs(watch("receiptDate"))}
format={OUTPUT_DATE_FORMAT}
disabled={true}
onChange={(date) => {
if (!date) return;
@@ -317,6 +318,7 @@ const FgStockInForm: React.FC<Props> = ({
sx={textfieldSx}
label={t("expiryDate")}
value={expiryDate ? dayjs(expiryDate) : undefined}
format={OUTPUT_DATE_FORMAT}
disabled={disabled}
onChange={(date) => {
if (!date) return;
@@ -375,20 +377,29 @@ const FgStockInForm: React.FC<Props> = ({
disabled={true}
/>
</Grid>
<Grid item xs={6}>
{putawayMode ? (
{putawayMode ? (<>
<Grid item xs={3}>
<TextField
label={t("processedQty")}
fullWidth
sx={textfieldSx}
disabled={true}
value={itemDetail.putAwayLines?.reduce((sum, p) => sum + p.qty, 0) ?? 0}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
</Grid>
<Grid item xs={3}>
<TextField
label={t("acceptedQty")}
fullWidth
sx={textfieldSx}
disabled={true}
{...register("acceptedQty", {
required: "acceptedQty required!",
})}
/>
</Grid></>
) : (
<Grid item xs={6}>
<TextField
label={t("acceptedQty")}
fullWidth
@@ -397,13 +408,9 @@ const FgStockInForm: React.FC<Props> = ({
{...register("acceptedQty", {
required: "acceptedQty required!",
})}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
)}
</Grid>
</Grid>
)}
{/* <Grid item xs={4}>
<TextField
label={t("acceptedWeight")}


+ 153
- 0
src/components/StockIn/ShelfLifeInput.tsx 查看文件

@@ -0,0 +1,153 @@
'use client';

import { useState, useEffect, useMemo } from 'react';
import { Box, TextField, FormHelperText, styled } from '@mui/material';
import { useTranslation } from "react-i18next";

interface ShelfLifeInputProps {
value?: number; // Total days
onChange?: (value: number) => void;
label?: string;
sx?: any;
}

const ShelfLifeContainer = styled(Box)(({ theme }) => ({
display: 'flex',
gap: theme.spacing(1),
alignItems: 'flex-start',
width: '100%',
'& .MuiTextField-root': {
flex: 1,
'& input': {
textAlign: 'center',
},
},
}));

const daysToDuration = (totalDays: number) => {
const years = Math.floor(totalDays / 365);
const remainingDaysAfterYears = totalDays % 365;
const months = Math.floor(remainingDaysAfterYears / 30); // **This is Approximate months (Not according to locale)
const days = remainingDaysAfterYears % 30;
return { years, months, days };
};

const durationToDays = (years: number, months: number, days: number) => {
return years * 365 + months * 30 + days;
};

// Format duration to readable string with proper roll-over (Assuming 30 days per month)
const formatDuration = (years: number, months: number, days: number) => {
let adjustedYears = years;
let adjustedMonths = months;
let adjustedDays = days;

// Roll over days to months
if (days >= 30) {
adjustedMonths += Math.floor(days / 30);
adjustedDays = days % 30;
}

// Roll over months to years
if (adjustedMonths >= 12) {
adjustedYears += Math.floor(adjustedMonths / 12);
adjustedMonths = adjustedMonths % 12;
}

const parts: string[] = [];
if (adjustedYears > 0) parts.push(`${adjustedYears} 年`);
if (adjustedMonths > 0) parts.push(`${adjustedMonths} 個月 ${adjustedDays > 0 ? ' + ' : ''}`);
if (adjustedDays > 0) parts.push(`${adjustedDays} 日`);
return parts.length > 0 ? parts.join(' ') : '0 日';
};

const ShelfLifeInput: React.FC<ShelfLifeInputProps> = ({ value = 0, onChange = () => {}, label = 'Shelf Life', sx }) => {
const { t } = useTranslation("purchaseOrder");
const { years, months, days } = daysToDuration(value);
const [duration, setDuration] = useState({
years: years || 0,
months: months || 0,
days: days || 0,
});

const totalDays = useMemo(() => {
return durationToDays(duration.years, duration.months, duration.days);
}, [duration]);

useEffect(() => {
onChange(totalDays);
}, [totalDays]);

// Set value when value prop changes
useEffect(() => {
if (value != totalDays) {
setDuration(daysToDuration(value));
}
}, [value]);

// Handle input changes
const handleChange = (field: 'years' | 'months' | 'days') => (
event: React.ChangeEvent<HTMLInputElement>
) => {
const input = event.target.value;
// Allow only non-negative integers
if (input === '' || (/^\d+$/.test(input) && parseInt(input) >= 0)) {
setDuration((prev) => ({
...prev,
[field]: input === '' ? 0 : parseInt(input),
}));
}
};

return (
<Box sx={{ width: '100%', paddingLeft: '1rem' }}>
<ShelfLifeContainer>
<TextField
label="年"
value={duration.years}
onChange={handleChange('years')}
sx={sx}
type="text"
inputProps={{
inputMode: 'numeric',
pattern: '[0-9]*',
}}
size="small"
/>
<TextField
label="月"
value={duration.months}
onChange={handleChange('months')}
type="text"
sx={sx}
inputProps={{
inputMode: 'numeric',
pattern: '[0-9]*',
}}
size="small"
/>
<TextField
label="日"
value={duration.days}
onChange={handleChange('days')}
sx={sx}
type="text"
inputProps={{
inputMode: 'numeric',
pattern: '[0-9]*',
}}
size="small"
/>
</ShelfLifeContainer>
<FormHelperText sx={{ fontSize: '2rem', mt: 1 }}>
{label}: <span style={{ color: totalDays < 1 ? 'red':'inherit' }}>
{/* {formatDuration(duration.years, duration.months, duration.days)} */}
{totalDays} 日
</span>
</FormHelperText>
</Box>
);
};

export default ShelfLifeInput;

+ 86
- 87
src/components/StockIn/StockInForm.tsx 查看文件

@@ -5,9 +5,11 @@ import {
} from "@/app/api/stockIn/actions";
import {
Box,
Button,
Card,
CardContent,
Grid,
InputAdornment,
Stack,
TextField,
Tooltip,
@@ -16,25 +18,16 @@ import {
import { Controller, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import StyledDataGrid from "../StyledDataGrid";
import { useCallback, useEffect, useMemo } from "react";
import { useCallback, useEffect, useState, useMemo } from "react";
import {
GridColDef,
GridRowIdGetter,
GridRowModel,
useGridApiContext,
GridRenderCellParams,
GridRenderEditCellParams,
useGridApiRef,
} from "@mui/x-data-grid";
import InputDataGrid from "../InputDataGrid";
import { TableRow } from "../InputDataGrid/InputDataGrid";
import { QcItemWithChecks } from "@/app/api/qc";
import { GridEditInputCell } from "@mui/x-data-grid";
import { StockInLine } from "@/app/api/stockIn";
import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { INPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import { dayjsToDateString, INPUT_DATE_FORMAT, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil";
import dayjs from "dayjs";
import CalculateExpiryDateModal from "./CalculateExpiryDateModal";
// change PurchaseQcResult to stock in entry props
interface Props {
itemDetail: StockInLine;
@@ -60,14 +53,14 @@ const textfieldSx = {
height: "100%",
boxSizing: "border-box",
padding: "0.75rem",
fontSize: 24,
fontSize: 30,
},
"& .MuiInputLabel-root": {
fontSize: 24,
transform: "translate(14px, 1.5rem) scale(1)",
fontSize: 30,
transform: "translate(14px, 1.2rem) scale(1)",
"&.MuiInputLabel-shrink": {
fontSize: 18,
transform: "translate(14px, -9px) scale(1)",
fontSize: 24,
transform: "translate(14px, -0.5rem) scale(1)",
},
// [theme.breakpoints.down("sm")]: {
// fontSize: "1rem",
@@ -119,11 +112,11 @@ const StockInForm: React.FC<Props> = ({
const expiryDate = watch("expiryDate");
const uom = watch("uom");

const [openModal, setOpenModal] = useState<boolean>(false);
const [openExpDatePicker, setOpenExpDatePicker] = useState<boolean>(false);

//// TODO : Add Checking ////
// Check if dates are input
// if (data.productionDate === undefined || data.productionDate == null) {
// validationErrors.push("請輸入生產日期!");
// }
// if (data.expiryDate === undefined || data.expiryDate == null) {
// validationErrors.push("請輸入到期日!");
// }
@@ -133,14 +126,29 @@ const StockInForm: React.FC<Props> = ({
// console.log(productionDate);
// console.log(expiryDate);
if (expiryDate) clearErrors();
if (productionDate) clearErrors();
}, [productionDate, expiryDate, clearErrors]);

useEffect(() => {
console.log("%c StockInForm itemDetail update: ", "color: brown", itemDetail);
}, [itemDetail]);

const handleOpenModal = useCallback(() => {
setOpenModal(true);
}, []);

const handleOnModalClose = useCallback(() => {
setOpenExpDatePicker(false);
setOpenModal(false);
}, []);

const handleReturnExpiryDate = useCallback((result: dayjs.Dayjs) => {
if (result) {
setValue("expiryDate", dayjsToDateString(result));
}
}, []);

return (
<>
<Grid container justifyContent="flex-start" alignItems="flex-start">
{/* <Grid item xs={12}>
<Typography variant="h6" display="block" marginBlockEnd={1}>
@@ -211,6 +219,7 @@ const StockInForm: React.FC<Props> = ({
sx={textfieldSx}
label={t("receiptDate")}
value={dayjs(watch("receiptDate"))}
format={OUTPUT_DATE_FORMAT}
disabled={true}
onChange={(date) => {
if (!date) return;
@@ -270,58 +279,6 @@ const StockInForm: React.FC<Props> = ({
helperText={errors.productLotNo?.message}
/>)}
</Grid>
{putawayMode || (<>
<Grid item xs={6}>
<Controller
control={control}
name="productionDate"
// rules={{ required: !Boolean(expiryDate) }}
render={({ field }) => {
return (
<LocalizationProvider
dateAdapter={AdapterDayjs}
adapterLocale={`${language}-hk`}
>
<DatePicker
{...field}
sx={textfieldSx}
label={t("productionDate")}
value={productionDate ? dayjs(productionDate) : undefined}
disabled={disabled}
onChange={(date) => {
if (!date) return;
setValue(
"productionDate",
date.format(INPUT_DATE_FORMAT),
);
// field.onChange(date);
}}
inputRef={field.ref}
slotProps={{
textField: {
// required: true,
error: Boolean(errors.productionDate?.message),
helperText: errors.productionDate?.message,
},
}}
/>
</LocalizationProvider>
);
}}
/>
</Grid>
<Grid item xs={6}>
<TextField
label={t("qty")}
fullWidth
{...register("qty", {
required: "qty required!",
})}
sx={textfieldSx}
disabled={true}
/>
</Grid></>
)}
<Grid item xs={6}>
<Controller
control={control}
@@ -338,6 +295,7 @@ const StockInForm: React.FC<Props> = ({
sx={textfieldSx}
label={t("expiryDate")}
value={expiryDate ? dayjs(expiryDate) : undefined}
format={OUTPUT_DATE_FORMAT}
disabled={disabled}
onChange={(date) => {
if (!date) return;
@@ -346,11 +304,30 @@ const StockInForm: React.FC<Props> = ({
// field.onChange(date);
}}
inputRef={field.ref}
open={openExpDatePicker && !openModal}
onOpen={() => setOpenExpDatePicker(true)}
onClose={() => setOpenExpDatePicker(false)}
slotProps={{
textField: {
InputProps: {
...(!disabled && {endAdornment: (
<InputAdornment position='end'>
<Button
type="button"
variant="contained"
color="primary"
sx={{ fontSize: '24px' }}
onClick={handleOpenModal}
>
{t("Calculate Expiry Date")}
</Button>
</InputAdornment>
),})
},
// required: true,
error: Boolean(errors.expiryDate?.message),
helperText: errors.expiryDate?.message,
onClick: () => setOpenExpDatePicker(true),
},
}}
/>
@@ -359,31 +336,45 @@ const StockInForm: React.FC<Props> = ({
}}
/>
</Grid>
<Grid item xs={6}>
{putawayMode ? (
{putawayMode || (<>
<Grid item xs={3}>
<TextField
label={t("acceptedQty")}
label={t("receivedQty")}
fullWidth
{...register("receivedQty", {
required: "receivedQty required!",
})}
sx={textfieldSx}
disabled={true}
value={itemDetail.acceptedQty}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
) : (
</Grid>
<Grid item xs={3}>
<TextField
label={t("receivedQty")}
label={t("qty")}
fullWidth
{...register("receivedQty", {
required: "receivedQty required!",
{...register("qty", {
required: "qty required!",
})}
sx={textfieldSx}
disabled={true}
/>
)}
</Grid>
</Grid></>
)}
{putawayMode && (
<Grid item xs={6}>
<TextField
label={t("acceptedQty")}
fullWidth
sx={textfieldSx}
disabled={true}
value={itemDetail.acceptedQty}
// disabled={true}
// disabled={disabled}
// error={Boolean(errors.acceptedQty)}
// helperText={errors.acceptedQty?.message}
/>
</Grid>
)}
<Grid item xs={6}>
<TextField
label={t("uom")}
@@ -456,6 +447,14 @@ const StockInForm: React.FC<Props> = ({
</Grid> */}
</Grid>
</Grid>
<CalculateExpiryDateModal
open={openModal}
onClose={handleOnModalClose}
onSubmit={handleReturnExpiryDate}
textfieldSx={textfieldSx}
/>
</>
);
};
export default StockInForm;

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

@@ -15,7 +15,7 @@
"name": "名稱",
"description": "描述",
"Type": "類型",
"shelfLife": "保存期限",
"shelfLife": "保質期",
"remarks": "備註",
"countryOfOrigin": "原產地",
"maxQty": "最大數量",


+ 8
- 1
src/i18n/zh/purchaseOrder.json 查看文件

@@ -157,5 +157,12 @@
"salesUnit": "銷售單位",
"download Qr Code": "下載QR碼",
"downloading": "下載中",
"&": "及"
"&": "及",
"Calculate Expiry Date": "沒有到期日,填寫生產日期及保質期",
"shelfLife": "保質期",
"Fill in Expiry Date": "請填寫生產日期及保質期,以計算到期日",
"Expiry Date cannot be earlier than Production Date": "到期日不可早於生產日期",
"Production Date must be earlier than Expiry Date": "生產日期必須早於到期日",
"confirm expiry date": "確認到期日",
"Invalid Date": "無效日期"
}

正在加载...
取消
保存