push rasad front on new repo
This commit is contained in:
335
src/features/guild/components/GuildAddSteward.js
Normal file
335
src/features/guild/components/GuildAddSteward.js
Normal file
@@ -0,0 +1,335 @@
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
FormControl,
|
||||
InputAdornment,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { guildGetStewardsService } from "../services/guild-get-guilds";
|
||||
import { guildGetAllocationData } from "../services/guildGetAllocationData";
|
||||
import { guildGetStewards } from "../services/guild-get-stewards";
|
||||
import { slaughterAllocateStewardService } from "../../slaughter-house/services/slaughter-allocate-steward";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { GuildEditAllocateStewardService } from "../services/guildEditAllocateStewardService";
|
||||
import { NumberInput } from "../../../components/number-format-custom/NumberFormatCustom";
|
||||
|
||||
export const GuildAddSteward = ({
|
||||
stewardKey,
|
||||
guildKey,
|
||||
sellType,
|
||||
isGuild,
|
||||
weight,
|
||||
quantity,
|
||||
item,
|
||||
totalAverageWeightOfCarcasses,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
const [price, setPrice] = useState();
|
||||
|
||||
const { guildGetStewardsState } = useSelector((state) => state.generalSlice);
|
||||
|
||||
useEffect(() => {
|
||||
if (sellType !== "exclusive") {
|
||||
dispatch(guildGetStewardsService());
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getOptionLabel = (option) => option.label;
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
slaughteSteward: Yup.string(),
|
||||
// price: Yup.number().when("quantity", {
|
||||
// is: quantity,
|
||||
// then: Yup.number().required("لطفا این فیلد را پر کنید"),
|
||||
// otherwise: Yup.number(),
|
||||
// }),
|
||||
wholePrice: Yup.number().when("quantity", {
|
||||
is: quantity,
|
||||
then: Yup.number().required("لطفا این فیلد را پر کنید"),
|
||||
otherwise: Yup.number(),
|
||||
}),
|
||||
numberOfPieces: Yup.number()
|
||||
.required("حجم لاشه را وارد کنید")
|
||||
.min(1, "حداقل یک قطعه"),
|
||||
weight: Yup.number()
|
||||
.required("وزن لاشه را وارد کنید")
|
||||
.min(0.01, "حداقل 0.01 کیلوگرم"),
|
||||
});
|
||||
|
||||
let defaultKey;
|
||||
|
||||
if (isGuild) {
|
||||
defaultKey = guildKey;
|
||||
} else {
|
||||
defaultKey = stewardKey;
|
||||
}
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
slaughteSteward: defaultKey,
|
||||
numberOfPieces: "",
|
||||
wholePrice: "",
|
||||
weight: weight ? weight : "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
let req;
|
||||
|
||||
if (quantity) {
|
||||
dispatch(
|
||||
GuildEditAllocateStewardService({
|
||||
steward_allocation_key: item.key,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
})
|
||||
).then(() => {
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(guildGetStewards({ date: selectedDate1 }));
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (isGuild) {
|
||||
req = {
|
||||
guild_key: values.slaughteSteward,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
sell_type: sellType,
|
||||
date: selectedDate1,
|
||||
broadcast_type: "steward_broadcast",
|
||||
amount: Number(price),
|
||||
total_amount: Number(values.wholePrice),
|
||||
};
|
||||
} else {
|
||||
req = {
|
||||
guild_key: values.slaughteSteward,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
sell_type: sellType,
|
||||
date: selectedDate1,
|
||||
broadcast_type: "steward_broadcast",
|
||||
amount: Number(price),
|
||||
total_amount: Number(values.wholePrice),
|
||||
};
|
||||
}
|
||||
dispatch(slaughterAllocateStewardService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(guildGetStewards({ date: selectedDate1 }));
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const finalQuantity = formik.values.weight / totalAverageWeightOfCarcasses;
|
||||
formik.setFieldValue("numberOfPieces", Number(finalQuantity).toFixed(0));
|
||||
}, [formik.values.weight]);
|
||||
|
||||
useEffect(() => {
|
||||
const calcPrice = formik.values.wholePrice / Number(formik.values.weight);
|
||||
setPrice(Number(calcPrice.toFixed(0)));
|
||||
}, [formik.values.wholePrice]);
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container width="100%" gap={SPACING.SMALL}>
|
||||
{!stewardKey && !guildKey && !isGuild && !quantity && (
|
||||
<Autocomplete
|
||||
disablePortal
|
||||
options={guildGetStewardsState}
|
||||
getOptionLabel={getOptionLabel}
|
||||
sx={{ width: "100%" }}
|
||||
size="small"
|
||||
onChange={(event, value) =>
|
||||
formik.setFieldValue("slaughteSteward", value.value)
|
||||
}
|
||||
onBlur={formik.handleBlur("slaughteSteward")}
|
||||
// value={formik.values.slaughteSteward}
|
||||
renderInput={(params) => <TextField {...params} label="مباشر" />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isGuild && !quantity && !stewardKey && !guildKey && (
|
||||
<Autocomplete
|
||||
disablePortal
|
||||
options={guildGetStewardsState}
|
||||
getOptionLabel={getOptionLabel}
|
||||
sx={{ width: "100%" }}
|
||||
size="small"
|
||||
onChange={(event, value) =>
|
||||
formik.setFieldValue("slaughteSteward", value.value)
|
||||
}
|
||||
onBlur={formik.handleBlur("slaughteSteward")}
|
||||
// value={formik.values.slaughteSteward}
|
||||
renderInput={(params) => <TextField {...params} label="اصناف" />}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="weight"
|
||||
name="weight"
|
||||
type="number"
|
||||
label="وزن لاشه"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">کیلوگرم</InputAdornment>
|
||||
),
|
||||
}}
|
||||
{...formik.getFieldProps("weight")}
|
||||
error={formik.touched.weight && formik.errors.weight}
|
||||
helperText={formik.touched.weight && formik.errors.weight}
|
||||
/>
|
||||
|
||||
{!quantity && (
|
||||
<>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
size="small"
|
||||
id="wholePrice"
|
||||
label="هزینه کل"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="start">ریال</InputAdornment>
|
||||
),
|
||||
}}
|
||||
value={formik.values.wholePrice}
|
||||
error={
|
||||
formik.touched.wholePrice
|
||||
? Boolean(formik.errors.wholePrice)
|
||||
: null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.wholePrice && Boolean(formik.errors.wholePrice)
|
||||
? formik.errors.wholePrice
|
||||
: null
|
||||
}
|
||||
/>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-select-label">خودرو حمل لاشه</InputLabel>
|
||||
<Select
|
||||
labelId="demo-select-label"
|
||||
id="demo-select"
|
||||
value=""
|
||||
disabled
|
||||
label="Select Option"
|
||||
size="small"
|
||||
>
|
||||
{/* You can add MenuItem components for each option */}
|
||||
<MenuItem value="" disabled>
|
||||
Select an option
|
||||
</MenuItem>
|
||||
<MenuItem value={10}>Option 1</MenuItem>
|
||||
<MenuItem value={20}>Option 2</MenuItem>
|
||||
<MenuItem value={30}>Option 3</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
size="small"
|
||||
fullWidth
|
||||
id="price"
|
||||
label="قیمت هر کیلو مرغ"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="start">ریال</InputAdornment>
|
||||
),
|
||||
readOnly: true,
|
||||
}}
|
||||
value={price}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="numberOfPieces"
|
||||
name="numberOfPieces"
|
||||
type="number"
|
||||
label="حجم لاشه"
|
||||
size="small"
|
||||
variant="outlined"
|
||||
value={formik.values.numberOfPieces}
|
||||
InputProps={{
|
||||
endAdornment: <InputAdornment position="end">قطعه</InputAdornment>,
|
||||
}}
|
||||
{...formik.getFieldProps("numberOfPieces")}
|
||||
error={formik.touched.numberOfPieces && formik.errors.numberOfPieces}
|
||||
helperText={
|
||||
formik.touched.numberOfPieces && formik.errors.numberOfPieces
|
||||
}
|
||||
/>
|
||||
|
||||
<Button variant="contained" fullWidth type="submit">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
778
src/features/guild/components/GuildBroadCastManagement.js
Normal file
778
src/features/guild/components/GuildBroadCastManagement.js
Normal file
@@ -0,0 +1,778 @@
|
||||
import {
|
||||
Button,
|
||||
Collapse,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import axios from "axios";
|
||||
import moment from "moment/moment";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { guildGetStewards } from "../services/guild-get-stewards";
|
||||
import { formatJustDate } from "../../../utils/formatTime";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SimpleTable } from "../../../components/simple-table/SimpleTable";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
OPEN_MODAL,
|
||||
} from "../../../lib/redux/slices/appSlice";
|
||||
import { GuildAddSteward } from "./GuildAddSteward";
|
||||
import { guildGetAllocationData } from "../services/guildGetAllocationData";
|
||||
import { GuildManageInventoryAllocationOperations } from "./GuildManageInventoryAllocationOperations";
|
||||
import { guildInventoryFinalSubmitService } from "../services/guildInventoryFinalSubmitService";
|
||||
import BoxList from "../../../components/box-list/BoxList";
|
||||
import { RespSlaughterGuildListItem } from "../../slaughter-house/components/resp-slaughter-guild-list-item/RespSlaughterGuildListItem";
|
||||
import { RespGuildExclusiveItem } from "../../slaughter-house/components/resp-guild-exclusive-item/RespGuildExclusiveItem";
|
||||
import { SlaughterSubmitOutProvinceSell } from "../../slaughter-house/components/slaughter-submit-out-province-sell/SlaughterSubmitOutProvinceSell";
|
||||
import { guildGetFreeSaleBarService } from "../services/guild-get-free-sale-bar";
|
||||
import { guildDeleteOutOfProvinceSell } from "../services/guild-delete-free-sale";
|
||||
|
||||
export const GuildBroadCastManagement = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1, setSelectedDate1] = useContext(AppContext);
|
||||
const [stewardsDataTable, setStewardsDataTable] = useState([]);
|
||||
const [inventoryAllocationsDataTable, setInventoryAllocationsDataTable] =
|
||||
useState([]);
|
||||
|
||||
const {
|
||||
guildGetInventoryStock,
|
||||
guildStewards,
|
||||
guildGetGuildData,
|
||||
guildFreeSaleBars,
|
||||
} = useSelector((state) => state.generalSlice);
|
||||
|
||||
const [outOfProvinceSells, setOutOfProvinceSells] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
).then(() => {
|
||||
dispatch(
|
||||
guildGetFreeSaleBarService({
|
||||
date: selectedDate1,
|
||||
steward_key: guildGetInventoryStock?.stewardKey,
|
||||
})
|
||||
);
|
||||
});
|
||||
dispatch(guildGetStewards({ date: selectedDate1 }));
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
}, [selectedDate1]);
|
||||
|
||||
useEffect(() => {
|
||||
const inventoryAllocationsData = guildGetGuildData?.map((item, i) => {
|
||||
let sellType, sellerType;
|
||||
if (item.sellerType === "guilds") {
|
||||
sellerType = "صنف";
|
||||
} else if (item.sellerType === "steward") {
|
||||
sellerType = "مباشر";
|
||||
}
|
||||
|
||||
if (item.sellType === "free") {
|
||||
sellType = "آزاد";
|
||||
} else {
|
||||
if (item.type === "manual") {
|
||||
sellType = "اختصاصی (دستی)";
|
||||
} else {
|
||||
sellType = "اختصاصی (اتوماتیک)";
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
i + 1,
|
||||
item?.guilds?.guildsId,
|
||||
formatJustDate(item.date),
|
||||
sellerType,
|
||||
sellType,
|
||||
item?.guilds?.guildsName,
|
||||
item?.guilds?.user?.fullname,
|
||||
item?.guilds?.user?.nationalId,
|
||||
item?.guilds?.user?.mobile,
|
||||
item?.guilds?.typeActivity,
|
||||
item?.guilds?.areaActivity,
|
||||
item?.guilds?.licenseNumber,
|
||||
item?.guilds?.address?.city.name,
|
||||
item?.numberOfCarcasses,
|
||||
item?.weightOfCarcasses,
|
||||
item?.loggedRegistrationCode ? item.loggedRegistrationCode : "-",
|
||||
<GuildManageInventoryAllocationOperations item={item} key={i} />,
|
||||
];
|
||||
});
|
||||
setInventoryAllocationsDataTable(inventoryAllocationsData);
|
||||
|
||||
const d1 = guildStewards?.map((item, i) => {
|
||||
return [
|
||||
item?.guildsId,
|
||||
"صنف",
|
||||
item.guildsName,
|
||||
item.user.fullname,
|
||||
item.user.nationalId,
|
||||
item.user.mobile,
|
||||
item.typeActivity,
|
||||
item.areaActivity,
|
||||
item.licenseNumber,
|
||||
item.address.city.name,
|
||||
item?.allocationLimit
|
||||
? `${item?.allocationLimit?.toLocaleString()} کیلوگرم`
|
||||
: "بدون محدودیت",
|
||||
<Button
|
||||
key={i}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تخصیص به صنف",
|
||||
size: 300,
|
||||
content: (
|
||||
<GuildAddSteward
|
||||
sellType={"exclusive"}
|
||||
key={item.key + i}
|
||||
isGuild={false}
|
||||
stewardKey={item.key}
|
||||
totalAverageWeightOfCarcasses={
|
||||
guildGetInventoryStock?.totalAverageWeightOfCarcasses
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تخصیص
|
||||
</Button>,
|
||||
];
|
||||
});
|
||||
|
||||
setStewardsDataTable(d1);
|
||||
|
||||
const sells = guildFreeSaleBars?.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
formatJustDate(item?.createDate),
|
||||
item?.buyerName,
|
||||
item?.buyerMobile,
|
||||
item?.province,
|
||||
item?.city,
|
||||
item?.driverName,
|
||||
item?.driverMobile,
|
||||
item?.driverName,
|
||||
item?.clearanceCode,
|
||||
item?.numberOfCarcasses,
|
||||
item?.weightOfCarcasses,
|
||||
<>
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ویرایش فروش خارج از استان",
|
||||
content: (
|
||||
<SlaughterSubmitOutProvinceSell
|
||||
stewardKey={guildGetInventoryStock?.stewardKey}
|
||||
isEdit={true}
|
||||
item={item}
|
||||
selectedDate={selectedDate1}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="secondary"
|
||||
onClick={() => {
|
||||
dispatch(guildDeleteOutOfProvinceSell(item?.key)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetFreeSaleBarService({
|
||||
date: selectedDate1,
|
||||
steward_key: guildGetInventoryStock?.stewardKey,
|
||||
})
|
||||
);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.data.result,
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</>,
|
||||
];
|
||||
});
|
||||
|
||||
setOutOfProvinceSells(sells);
|
||||
}, [guildStewards, guildGetGuildData, guildFreeSaleBars]);
|
||||
|
||||
const finalSubmitDisabled =
|
||||
(Array.isArray(guildGetGuildData) && !guildGetGuildData?.length) ||
|
||||
(Array.isArray(guildGetGuildData) &&
|
||||
guildGetGuildData[0]?.finalRegistration);
|
||||
|
||||
const [inventoryDate, setInventoryDate] = useState(new Date(selectedDate1));
|
||||
|
||||
useEffect(() => {
|
||||
const tempDate = new Date(inventoryDate);
|
||||
tempDate.setDate(new Date(selectedDate1).getDate() - 1);
|
||||
setInventoryDate(tempDate);
|
||||
}, [selectedDate1]);
|
||||
|
||||
const [isMessageVisible, setMessageVisible] = useState(true);
|
||||
|
||||
const toggleMessageVisibility = () => {
|
||||
setMessageVisible(!isMessageVisible);
|
||||
};
|
||||
|
||||
const isMobile = window.innerWidth <= 600;
|
||||
|
||||
const [value, setValue] = useState("");
|
||||
const [searchFilter, setSearchFilter] = useState([]);
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
const regex = new RegExp(value, "i");
|
||||
const d = stewardsDataTable.filter((item) => regex.test(item));
|
||||
setSearchFilter(d);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
alignItems="center"
|
||||
justifyContent="start"
|
||||
width="100%"
|
||||
>
|
||||
<Typography variant="h6">مدیریت پخش</Typography>
|
||||
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid width="100%">
|
||||
{isMobile ? (
|
||||
<Grid p={SPACING.TINY}>
|
||||
<Grid container alignItems="center" justifyContent="space-between">
|
||||
<Grid container alignItems="center">
|
||||
<Typography>موجودی انبار</Typography>
|
||||
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}Broadcast_management/?date=${selectedDate1}&kill_house_key=${"AAA"}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "فروش آزاد",
|
||||
content: (
|
||||
<SlaughterSubmitOutProvinceSell
|
||||
stewardKey={guildGetInventoryStock?.stewardKey}
|
||||
selectedDate={selectedDate1}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
فروش آزاد
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<BoxList
|
||||
columns={[
|
||||
"حجم لاشه ها",
|
||||
"وزن لاشه ها (کیلوگرم)",
|
||||
// "تعداد تخصیصات",
|
||||
"حجم لاشه تخصیص داده شده",
|
||||
"وزن تخصیص داده شده (کیلوگرم)",
|
||||
"حجم لاشه قابل تخصیص",
|
||||
"وزن قابل تخصیص (کیلوگرم)",
|
||||
"وزن بار فروش آزاد (کیلوگرم)",
|
||||
"حجم بار فروش آزاد (قطعه)",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
guildGetInventoryStock?.realNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.realWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.allocatedTotalNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.allocatedTotalWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.remainTotalNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.remainTotalWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.freeSaleWeight?.toLocaleString(),
|
||||
guildGetInventoryStock?.freeSaleQuantity?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
) : (
|
||||
<SimpleTable
|
||||
name={
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid container alignItems="center">
|
||||
<Typography>موجودی انبار</Typography>
|
||||
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}Broadcast_management/?date=${selectedDate1}&kill_house_key=${"AAA"}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "فروش آزاد",
|
||||
content: (
|
||||
<SlaughterSubmitOutProvinceSell
|
||||
stewardKey={guildGetInventoryStock?.stewardKey}
|
||||
selectedDate={selectedDate1}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
فروش آزاد
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
}
|
||||
columns={[
|
||||
"حجم لاشه ها",
|
||||
"وزن لاشه ها (کیلوگرم)",
|
||||
// "تعداد تخصیصات",
|
||||
"حجم لاشه تخصیص داده شده",
|
||||
"وزن تخصیص داده شده (کیلوگرم)",
|
||||
"حجم لاشه قابل تخصیص",
|
||||
"وزن قابل تخصیص (کیلوگرم)",
|
||||
"وزن بار فروش آزاد (کیلوگرم)",
|
||||
"حجم بار فروش آزاد (قطعه)",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
guildGetInventoryStock?.realNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.realWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.allocatedTotalNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.allocatedTotalWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.remainTotalNumberOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.remainTotalWeightOfCarcasses?.toLocaleString(),
|
||||
guildGetInventoryStock?.freeSaleWeight?.toLocaleString(),
|
||||
guildGetInventoryStock?.freeSaleQuantity?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid width="100%">
|
||||
<List>
|
||||
<ListItem
|
||||
sx={{ backgroundColor: "#dfe6e9", cursor: "pointer" }}
|
||||
onClick={toggleMessageVisibility}
|
||||
>
|
||||
<ListItemText primary={"صنف اختصاصی"} />
|
||||
<Button variant="text" onClick={toggleMessageVisibility}>
|
||||
{isMessageVisible ? <ExpandLessIcon /> : <ExpandMoreIcon />}
|
||||
</Button>
|
||||
</ListItem>
|
||||
|
||||
<Collapse in={isMessageVisible}>
|
||||
<Grid mt={SPACING.TINY}>
|
||||
<TextField
|
||||
label="جستجو ..."
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onChange={handleChange}
|
||||
fullWidth
|
||||
/>
|
||||
</Grid>
|
||||
{isMobile ? (
|
||||
<RespSlaughterGuildListItem
|
||||
data={value ? searchFilter : stewardsDataTable}
|
||||
/>
|
||||
) : (
|
||||
<ListItem>
|
||||
<SimpleTable
|
||||
columns={[
|
||||
"شناسه صنف",
|
||||
"ماهیت",
|
||||
"نام واحد صنفی",
|
||||
"نام شخص/شرکت",
|
||||
"کدملی",
|
||||
"موبایل",
|
||||
"نوع فعالیت",
|
||||
"حوزه فعالیت",
|
||||
"شماره مجوز",
|
||||
"شهرستان",
|
||||
"میانگین سهم",
|
||||
"عملیات",
|
||||
]}
|
||||
data={value ? searchFilter : stewardsDataTable}
|
||||
/>
|
||||
</ListItem>
|
||||
)}
|
||||
</Collapse>
|
||||
</List>
|
||||
</Grid>
|
||||
{isMobile ? (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
gap={SPACING.SMALL}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Typography>مدیریت کل تخصیصات</Typography>
|
||||
<Grid container gap={SPACING.SMALL} alignItems="center">
|
||||
<Button
|
||||
// disabled={!guildGetGuildData?.length}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تخصیص آزاد به صنف",
|
||||
content: (
|
||||
<GuildAddSteward
|
||||
isGuild
|
||||
sellType="free"
|
||||
totalAverageWeightOfCarcasses={
|
||||
guildStewards.totalAverageWeightOfCarcasses
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تخصیص آزاد به صنف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={finalSubmitDisabled}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت نهایی",
|
||||
content: (
|
||||
<Grid container gap={SPACING.SMALL}>
|
||||
<Typography>
|
||||
در صورت ثبت نهایی انجام هیچگونه عملیاتی مانند حذف و
|
||||
ویرایش امکان پذیر نمی باشد.
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.TINY}
|
||||
width="100%"
|
||||
>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
guildInventoryFinalSubmitService({
|
||||
steward_guild_allocation_list:
|
||||
guildGetGuildData.map((item) => item.key),
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ارسال یکجا کداحراز
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<RespGuildExclusiveItem data={inventoryAllocationsDataTable} />
|
||||
{!!outOfProvinceSells?.length && (
|
||||
<Grid mt={2}>
|
||||
<BoxList
|
||||
name={"فروش خارج از استان"}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ",
|
||||
"نام خریدار",
|
||||
"تلفن",
|
||||
"استان",
|
||||
"شهر",
|
||||
"نام راننده",
|
||||
"تلفن راننده",
|
||||
"نوع خودرو",
|
||||
"کد قرنطینه",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"عملیات",
|
||||
]}
|
||||
data={outOfProvinceSells}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Grid width="100%">
|
||||
<SimpleTable
|
||||
name={
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
gap={SPACING.SMALL}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Typography>مدیریت کل تخصیصات</Typography>
|
||||
<Grid container gap={SPACING.SMALL} alignItems="center">
|
||||
<Button
|
||||
// disabled={!guildGetGuildData?.length}
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تخصیص آزاد به صنف",
|
||||
content: (
|
||||
<GuildAddSteward
|
||||
isGuild
|
||||
sellType="free"
|
||||
totalAverageWeightOfCarcasses={
|
||||
guildGetInventoryStock?.totalAverageWeightOfCarcasses
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تخصیص آزاد به صنف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={finalSubmitDisabled}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت نهایی",
|
||||
content: (
|
||||
<Grid container gap={SPACING.SMALL}>
|
||||
<Typography>
|
||||
در صورت ثبت نهایی انجام هیچگونه عملیاتی مانند
|
||||
حذف و ویرایش امکان پذیر نمی باشد.
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.TINY}
|
||||
width="100%"
|
||||
>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
guildInventoryFinalSubmitService({
|
||||
steward_guild_allocation_list:
|
||||
guildGetGuildData.map(
|
||||
(item) => item.key
|
||||
),
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ارسال یکجا کداحراز
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"شناسه صنف",
|
||||
"تاریخ ثبت",
|
||||
"ماهیت",
|
||||
"نوع تخصیص",
|
||||
"نام واحد صنفی",
|
||||
"نام شخص/شرکت",
|
||||
"کدملی",
|
||||
"موبایل",
|
||||
"نوع فعالیت",
|
||||
"حوزه فعالیت",
|
||||
"شماره مجوز",
|
||||
"شهرستان",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"کداحراز",
|
||||
"عملیات",
|
||||
]}
|
||||
data={inventoryAllocationsDataTable}
|
||||
/>
|
||||
{!!outOfProvinceSells?.length && (
|
||||
<Grid mt={2}>
|
||||
<SimpleTable
|
||||
name={"فروش خارج از استان"}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ",
|
||||
"نام خریدار",
|
||||
"تلفن",
|
||||
"استان",
|
||||
"شهر",
|
||||
"نام راننده",
|
||||
"تلفن راننده",
|
||||
"نوع خودرو",
|
||||
"کد قرنطینه",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"عملیات",
|
||||
]}
|
||||
data={outOfProvinceSells}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
78
src/features/guild/components/GuildInventoryOperation.js
Normal file
78
src/features/guild/components/GuildInventoryOperation.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { VscNewFolder } from "react-icons/vsc";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import LinkItem from "../../../components/link-item/LinkItem";
|
||||
import { NavLink } from "../../../components/nav-link/NavLink";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import {
|
||||
ROUTE_STEWARD_SALE_IN_PROVINCE,
|
||||
ROUTE_STEWARD_INVENTORY_STOCK,
|
||||
ROUTE_STEWARD_PURCHASE_OUT_PROVINCE,
|
||||
ROUTE_STEWARD_SALE_OUT_PROVINCE,
|
||||
ROUTE_STEWARD_SEGMENT,
|
||||
} from "../../../routes/routes";
|
||||
|
||||
export const GuildInventoryOperation = () => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
p={SPACING.SMALL}
|
||||
direction={{ xs: "row", md: "row" }}
|
||||
justifyContent="center"
|
||||
// style={{ placeContent: "baseline" }}
|
||||
xs={12}
|
||||
alignItems="center"
|
||||
>
|
||||
<NavLink
|
||||
to={ROUTE_STEWARD_INVENTORY_STOCK}
|
||||
active={pathname === ROUTE_STEWARD_INVENTORY_STOCK ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="ورود به انبار"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={ROUTE_STEWARD_SALE_IN_PROVINCE}
|
||||
active={pathname === ROUTE_STEWARD_SALE_IN_PROVINCE ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="فروش داخل استان"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={ROUTE_STEWARD_PURCHASE_OUT_PROVINCE}
|
||||
active={
|
||||
pathname === ROUTE_STEWARD_PURCHASE_OUT_PROVINCE ? "true" : null
|
||||
}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="خرید خارج استان"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={ROUTE_STEWARD_SALE_OUT_PROVINCE}
|
||||
active={pathname === ROUTE_STEWARD_SALE_OUT_PROVINCE ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="فروش به خارج استان"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={ROUTE_STEWARD_SEGMENT}
|
||||
active={pathname === ROUTE_STEWARD_SEGMENT ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="قطعه بندی"
|
||||
/>
|
||||
</NavLink>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
415
src/features/guild/components/GuildManageGuilds.js
Normal file
415
src/features/guild/components/GuildManageGuilds.js
Normal file
@@ -0,0 +1,415 @@
|
||||
import {
|
||||
Button,
|
||||
Pagination,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
|
||||
import { ManageGuildsOperations } from "../../province/components/manage-guilds-operations/ManageGuildsOperations";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { CreateGuilds } from "../../province/components/create-guilds/CreateGuilds";
|
||||
import { PageTable } from "../../../components/page-table/PageTable";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import BoxList from "../../../components/box-list/BoxList";
|
||||
|
||||
const GuildMaangeGuilds = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [dataTableM, setDataTableM] = useState([]);
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
|
||||
const [textValue, setTextValue] = useState("");
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const fetchApiData = async (page, textValue) => {
|
||||
setLoading(true);
|
||||
let response = await axios.get(
|
||||
`total_guilds/?role=Guilds&steward=true&search=filter&value=${textValue}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page, textValue);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = async (newPerPage, page) => {
|
||||
setLoading(true);
|
||||
|
||||
let response = await axios.get(
|
||||
`total_guilds/?role=Guilds&steward=true&search=filter&value=${textValue}&page=${page}&page_size=${newPerPage}`
|
||||
);
|
||||
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setPerPage(newPerPage);
|
||||
|
||||
setLoading(false);
|
||||
dispatch(LOADING_END());
|
||||
};
|
||||
|
||||
const [page, setPage] = useState(0);
|
||||
const handleChangePageM = (event, newPage) => {
|
||||
dispatch(LOADING_START());
|
||||
setPage(newPage);
|
||||
fetchApiData(newPage + 1, textValue);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(1);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "شناسه صنف",
|
||||
selector: (item) => item.guildsId,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "نام واحد صنفی",
|
||||
selector: (item) => item?.guildsName,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "نام شخص/شرکت",
|
||||
selector: (item) => `${item?.user?.fullname} (${item?.user?.mobile})`,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
name: "کدملی",
|
||||
selector: (item) => item?.user?.nationalId,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
name: "نوع فعالیت",
|
||||
selector: (item) => item?.typeActivity,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "حوزه فعالیت",
|
||||
selector: (item) => item?.areaActivity,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "کدپستی",
|
||||
selector: (item) => item?.address?.postalCode,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "استان/شهر/آدرس",
|
||||
selector: (item) =>
|
||||
`${item?.address?.province.name}/${item?.address?.city.name}/${item?.address?.address}`,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "مباشر",
|
||||
selector: (item) => (item?.steward ? "می باشد" : "نمی باشد"),
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "محدودیت تخصیص",
|
||||
selector: (item) => (item?.limitationAllocation ? "دارد" : "ندارد"),
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "حداکثر تخصیص",
|
||||
selector: (item) => item?.allocationLimit,
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "مباشر",
|
||||
selector: (item) =>
|
||||
item?.centersAllocation?.map((item) => item.label).join(" - "),
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "کشتارگاه",
|
||||
selector: (item) => {
|
||||
return item?.killHouseInfo
|
||||
?.map((item) => `${item.name} (${item.mobile})`)
|
||||
.join(" - ");
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "وضعیت",
|
||||
selector: (item) => {
|
||||
let state = "";
|
||||
if (item?.provinceAcceptState === "accepted") {
|
||||
state = "تایید شده";
|
||||
} else if (item?.provinceAcceptState === "rejected") {
|
||||
state = "رد شده";
|
||||
} else if (item?.provinceAcceptState === "pending") {
|
||||
state = "در انتظار تایید";
|
||||
}
|
||||
return state;
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
},
|
||||
{
|
||||
name: "عملیات",
|
||||
selector: (item, i) => (
|
||||
<ManageGuildsOperations
|
||||
key={i + item?.guildsId}
|
||||
guild={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "110px",
|
||||
},
|
||||
];
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`total_guilds/?role=${getRoleFromUrl()}&search=filter&value=${textValue}&steward=true`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (getRoleFromUrl() === "CityJahad") {
|
||||
columns.pop();
|
||||
}
|
||||
|
||||
const getItemState = (item) => {
|
||||
let state = "";
|
||||
if (item?.provinceAcceptState === "accepted") {
|
||||
state = "تایید شده";
|
||||
} else if (item?.provinceAcceptState === "rejected") {
|
||||
state = "رد شده";
|
||||
} else if (item?.provinceAcceptState === "pending") {
|
||||
state = "در انتظار تایید";
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
item.guildsId,
|
||||
item?.guildsName,
|
||||
`${item?.user?.fullname} (${item?.user?.mobile})`,
|
||||
item?.user?.nationalId,
|
||||
item?.typeActivity,
|
||||
item?.areaActivity,
|
||||
item?.address?.postalCode,
|
||||
`${item?.address?.province.name}/${item?.address?.city.name}/${item?.address?.address}`,
|
||||
item?.steward ? "می باشد" : "نمی باشد",
|
||||
item?.limitationAllocation ? "دارد" : "ندارد",
|
||||
item?.allocationLimit,
|
||||
item?.centersAllocation?.map((item) => item.label).join(" - "),
|
||||
item?.killHouseInfo
|
||||
?.map((item) => `${item.name} (${item.mobile})`)
|
||||
.join(" - "),
|
||||
getItemState(item),
|
||||
<ManageGuildsOperations key={i + item?.guildsId} guild={item} />,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTableM(d);
|
||||
}, [data]);
|
||||
|
||||
const columnNames = columns.map((column) => column.name);
|
||||
const isMobile = window.innerWidth <= 600;
|
||||
|
||||
const tableTitle = (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
width="100%"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
width="100%"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Typography>مدیریت اصناف</Typography>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
<Grid>
|
||||
{getRoleFromUrl() !== "CityJahad" && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
size: window.innerWidth <= 600 ? "small" : "auto",
|
||||
title: "ثبت واحد جدید",
|
||||
content: <CreateGuilds updateTable={updateTable} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت واحد جدید
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}guilds_excel/?key=${userKey}&role=${getRoleFromUrl()}&search=filter&value=${textValue}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
{isMobile ? (
|
||||
<Grid container justifyContent="center" gap={SPACING.SMALL}>
|
||||
{tableTitle}
|
||||
<BoxList columns={columnNames} data={dataTableM} />
|
||||
<Pagination
|
||||
count={Math.ceil(totalRows / 10)}
|
||||
page={page + 1}
|
||||
variant="outlined"
|
||||
onChange={(event, newPage) => {
|
||||
handleChangePageM(event, newPage - 1);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
) : (
|
||||
<PageTable
|
||||
title={tableTitle}
|
||||
columns={columns}
|
||||
data={data}
|
||||
progressPending={loading}
|
||||
pagination
|
||||
paginationServer
|
||||
paginationTotalRows={totalRows}
|
||||
onChangeRowsPerPage={handlePerRowsChange}
|
||||
onChangePage={handlePageChange}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default GuildMaangeGuilds;
|
||||
@@ -0,0 +1,197 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { GuildAddSteward } from "./GuildAddSteward";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
LOADING_END,
|
||||
OPEN_MODAL,
|
||||
} from "../../../lib/redux/slices/appSlice";
|
||||
import { guildGetAllocationData } from "../services/guildGetAllocationData";
|
||||
import { guildGetStewards } from "../services/guild-get-stewards";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { useContext } from "react";
|
||||
import { guildDeleteAllocatedService } from "../services/guildDeleteAllocatedService";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { guildInventoryFinalSubmitService } from "../services/guildInventoryFinalSubmitService";
|
||||
import { GuildSubmitAuthCode } from "./GuildSubmitAuthCode";
|
||||
|
||||
export const GuildManageInventoryAllocationOperations = ({ item }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
// const { inventorySelectedKillHouse } = useSelector(
|
||||
// (state) => state.slaughterSlice
|
||||
// );
|
||||
|
||||
return (
|
||||
<Grid container direction="column">
|
||||
{item.systemRegistrationCode && (
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item.finalRegistration || item.loggedRegistrationCode}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "کداحراز",
|
||||
content: <GuildSubmitAuthCode item={item} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت کداحراز
|
||||
</Button>
|
||||
)}
|
||||
{!item.systemRegistrationCode && (
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item.finalRegistration}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ارسال کداحراز",
|
||||
content: (
|
||||
<Grid container gap={SPACING.SMALL}>
|
||||
<Typography>
|
||||
در صورت ارسال کداحراز انجام هیچگونه عملیاتی مانند حذف و
|
||||
ویرایش امکان پذیر نمی باشد.
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.TINY}
|
||||
width="100%"
|
||||
>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
guildInventoryFinalSubmitService({
|
||||
steward_guild_allocation_list: [item.key],
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ارسال کداحراز
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!item.systemRegistrationCode && (
|
||||
<>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item.finalRegistration}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش تخصیص",
|
||||
content: (
|
||||
<GuildAddSteward
|
||||
stewardKey={item.key}
|
||||
item={item}
|
||||
quantity={item?.numberOfCarcasses}
|
||||
weight={item?.weightOfCarcasses}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item.finalRegistration}
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
guildDeleteAllocatedService({
|
||||
steward_allocation_key: item.key,
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(LOADING_END());
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(guildGetStewards({ date: selectedDate1 }));
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
حذف
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
67
src/features/guild/components/GuildProfile.js
Normal file
67
src/features/guild/components/GuildProfile.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Box } from "@mui/system";
|
||||
import { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SimpleTable } from "../../../components/simple-table/SimpleTable";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import { guildGetProfile } from "../services/guild-get-profile";
|
||||
|
||||
export const GuildProfile = () => {
|
||||
const { guildProfile } = useSelector((state) => state.generalSlice);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(guildGetProfile()).then((r) => {
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.LARGE}>
|
||||
<Grid container direction="column" xs={12}>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<>
|
||||
<Grid>
|
||||
<SimpleTable
|
||||
name={`اطلاعات صنف`}
|
||||
columns={[
|
||||
"نام صنف",
|
||||
"شناسه صنف",
|
||||
"شماره مجوز",
|
||||
"حوزه فعالیت",
|
||||
"نوع فعالیت",
|
||||
"محدودیت مباشر",
|
||||
"محدودیت کشتارگاه",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
guildProfile?.guildsName,
|
||||
guildProfile?.guildsId,
|
||||
guildProfile?.licenseNumber,
|
||||
guildProfile?.areaActivity,
|
||||
guildProfile?.typeActivity,
|
||||
guildProfile?.centersAllocation
|
||||
?.map((item) => item.label)
|
||||
.join(" - "),
|
||||
guildProfile?.killHouseCentersAllocation
|
||||
?.map((item) => item.label)
|
||||
.join(" - "),
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
317
src/features/guild/components/GuildReceiveBarOperation.js
Normal file
317
src/features/guild/components/GuildReceiveBarOperation.js
Normal file
@@ -0,0 +1,317 @@
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Divider,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { useFormik } from "formik";
|
||||
import { guildAllocatedStockOperationService } from "../services/guild-allocated-stock-operation";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { guildGetInventoryAllocatedService } from "../services/guild-get-inventory-allocated";
|
||||
import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { senfGetInventoryStockService } from "../services/senf-get-inventory-stock";
|
||||
import { senfGetInventoryAllocatedService } from "../services/senf-get-inventory-allocated";
|
||||
|
||||
export const GuildReceiveBarOperation = ({ item }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [selectedValue, setSelectedValue] = useState("option1");
|
||||
|
||||
const handleChange = (event) => {
|
||||
setSelectedValue(event.target.value);
|
||||
};
|
||||
|
||||
const initialValues = {
|
||||
authCode: "",
|
||||
};
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
authCode: Yup.string().required("کداحراز اجباری است"),
|
||||
});
|
||||
|
||||
const onSubmit = () => {
|
||||
// Handle form submission here
|
||||
// console.log("Form submitted with values:", values);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues,
|
||||
validationSchema,
|
||||
onSubmit,
|
||||
});
|
||||
|
||||
const [isChecked, setChecked] = useState(false);
|
||||
|
||||
const handleCheckboxChange = () => {
|
||||
setChecked(!isChecked);
|
||||
};
|
||||
|
||||
const formikRealInfo = useFormik({
|
||||
initialValues: {
|
||||
number: "",
|
||||
weight: "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا وزن را وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
formikRealInfo.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
width="100%"
|
||||
direction="column"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.TINY}
|
||||
>
|
||||
<Grid container justifyContent="space-around">
|
||||
<Typography variant="caption">
|
||||
وزن تخصیصی: {item.weightOfCarcasses.toLocaleString()} کیلوگرم
|
||||
</Typography>
|
||||
<Typography variant="caption">
|
||||
تعداد تخصیصی: {item.numberOfCarcasses.toLocaleString()} قطعه
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Divider />
|
||||
|
||||
<Grid container spacing={1} alignItems="center">
|
||||
<Grid item>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
size="small"
|
||||
checked={isChecked}
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
}
|
||||
label="ثبت تعداد واقعی تحویلی"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid container xs={12} spacing={1}>
|
||||
<Grid item xs={6}>
|
||||
<TextField
|
||||
id="weight"
|
||||
size="small"
|
||||
label="وزن"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
disabled={!isChecked}
|
||||
onChange={formikRealInfo.handleChange}
|
||||
onBlur={formikRealInfo.handleBlur}
|
||||
value={formikRealInfo.values.weight}
|
||||
error={
|
||||
formikRealInfo.touched.weight &&
|
||||
Boolean(formikRealInfo.errors.weight)
|
||||
}
|
||||
helperText={
|
||||
formikRealInfo.touched.weight
|
||||
? formikRealInfo.errors.weight
|
||||
: ""
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<FormControl component="fieldset">
|
||||
<RadioGroup
|
||||
row
|
||||
aria-label="radio-buttons-group"
|
||||
name="radio-buttons-group"
|
||||
value={selectedValue}
|
||||
onChange={handleChange}
|
||||
style={{ justifyContent: "space-between", flexDirection: "row" }}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="option1"
|
||||
control={<Radio />}
|
||||
label="تحویل بار با کداحراز"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="option2"
|
||||
control={<Radio />}
|
||||
label="تحویل بار بدون کداحراز"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
|
||||
{selectedValue === "option1" && (
|
||||
<TextField
|
||||
fullWidth
|
||||
id="authCode"
|
||||
name="authCode"
|
||||
label="کداحراز"
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur} // Add onBlur to track touched state
|
||||
value={formik.values.authCode}
|
||||
error={formik.touched.authCode && Boolean(formik.errors.authCode)}
|
||||
helperText={formik.touched.authCode ? formik.errors.authCode : ""}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
disabled={
|
||||
(selectedValue === "option1" ? !formik.isValid : false) ||
|
||||
(isChecked ? !formikRealInfo.isValid : false)
|
||||
}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
let reqObj = {};
|
||||
if (formik.values.authCode) {
|
||||
if (getRoleFromUrl() === "senf") {
|
||||
reqObj = {
|
||||
guild_check_allocation: true,
|
||||
receiver_real_number_of_carcasses: 0,
|
||||
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
|
||||
? formikRealInfo.values.weight
|
||||
: item.weightOfCarcasses,
|
||||
allocation_key: item.key,
|
||||
registration_code: Number(formik.values.authCode),
|
||||
state: "accepted",
|
||||
};
|
||||
} else {
|
||||
reqObj = {
|
||||
steward_check_allocation: true,
|
||||
allocation_key: item.key,
|
||||
receiver_real_number_of_carcasses: 0,
|
||||
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
|
||||
? formikRealInfo.values.weight
|
||||
: item.weightOfCarcasses,
|
||||
registration_code: Number(formik.values.authCode),
|
||||
state: "accepted",
|
||||
};
|
||||
}
|
||||
} else {
|
||||
if (getRoleFromUrl() === "senf") {
|
||||
reqObj = {
|
||||
guild_check_allocation: true,
|
||||
allocation_key: item.key,
|
||||
receiver_real_number_of_carcasses: 0,
|
||||
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
|
||||
? formikRealInfo.values.weight
|
||||
: item.weightOfCarcasses,
|
||||
state: "accepted",
|
||||
};
|
||||
} else {
|
||||
reqObj = {
|
||||
steward_check_allocation: true,
|
||||
allocation_key: item.key,
|
||||
receiver_real_number_of_carcasses: 0,
|
||||
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
|
||||
? formikRealInfo.values.weight
|
||||
: item.weightOfCarcasses,
|
||||
state: "accepted",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(guildAllocatedStockOperationService(reqObj)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
if (getRoleFromUrl() === "senf") {
|
||||
dispatch(
|
||||
senfGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
senfGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
}
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تحویل بار
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
guildAllocatedStockOperationService({
|
||||
steward_check_allocation: true,
|
||||
allocation_key: item.key,
|
||||
state: "rejected",
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
رد بار
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
87
src/features/guild/components/GuildSubmitAuthCode.js
Normal file
87
src/features/guild/components/GuildSubmitAuthCode.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import { useContext } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { guildGetAllocationData } from "../services/guildGetAllocationData";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { guildAuthCodeSubmitService } from "../services/guild-auth-code-submit";
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
phoneNumber: Yup.string()
|
||||
.matches(/^\d+$/, "فقط عدد مجاز است")
|
||||
.required("کداحراز اجباری است"),
|
||||
});
|
||||
|
||||
export const GuildSubmitAuthCode = ({ item }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
phoneNumber: "",
|
||||
},
|
||||
validationSchema: validationSchema,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
guildAuthCodeSubmitService({
|
||||
logged_registration_code: values.phoneNumber,
|
||||
steward_allocation_key: item.key,
|
||||
role: getRoleFromUrl(),
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetAllocationData({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container width="100%" direction="column" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
fullWidth
|
||||
id="phoneNumber"
|
||||
name="phoneNumber"
|
||||
label="کداحراز"
|
||||
variant="outlined"
|
||||
value={formik.values.phoneNumber}
|
||||
error={
|
||||
formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)
|
||||
}
|
||||
helperText={formik.touched.phoneNumber && formik.errors.phoneNumber}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
/>
|
||||
<Button type="submit" fullWidth variant="contained">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
380
src/features/guild/components/GuildSubmitFreeBar.js
Normal file
380
src/features/guild/components/GuildSubmitFreeBar.js
Normal file
@@ -0,0 +1,380 @@
|
||||
import { Button, InputAdornment, TextField, Typography } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { useFormik } from "formik";
|
||||
// import moment from "moment/moment";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { fixBase64 } from "../../../utils/toBase64";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { ImageUpload } from "../../../components/image-upload/ImageUpload";
|
||||
import { guildSubmitFreeBar } from "../services/guild-submit-free-bar";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { guildGetInventoryAllocatedService } from "../services/guild-get-inventory-allocated";
|
||||
import { DRAWER } from "../../../lib/redux/slices/appSlice";
|
||||
import { guildGetFreeBars } from "../services/guild-get-free-bars";
|
||||
import { guildEditFreeBar } from "../services/guild-edit-free-bar";
|
||||
|
||||
const ValidationSchema = Yup.object().shape({
|
||||
// kill_house_key: Yup.string().required("کد خانه کشتار الزامی است"),
|
||||
slaughter_name: Yup.string().required("نام کشتارگاه الزامی است"),
|
||||
slaughter_mobile: Yup.string()
|
||||
.required("شماره موبایل کشتارگاه الزامی است")
|
||||
.min(11, "شماره موبایل باید دقیقاً 11 رقم باشد")
|
||||
.max(11, "شماره موبایل باید دقیقاً 11 رقم باشد"),
|
||||
province: Yup.string().required("استان الزامی است"),
|
||||
city: Yup.string().required("شهر الزامی است"),
|
||||
vet_farm_name: Yup.string().required("نام دامپزشک مربوطه الزامی است"),
|
||||
vet_farm_mobile: Yup.string()
|
||||
.required("شماره موبایل دامپزشک مربوطه الزامی است")
|
||||
.min(11, "شماره موبایل باید دقیقاً 11 رقم باشد")
|
||||
.max(11, "شماره موبایل باید دقیقاً 11 رقم باشد"),
|
||||
driver_name: Yup.string().required("نام راننده الزامی است"),
|
||||
driver_mobile: Yup.string()
|
||||
.required("شماره موبایل راننده الزامی است")
|
||||
.min(11, "شماره موبایل باید دقیقاً 11 رقم باشد")
|
||||
.max(11, "شماره موبایل باید دقیقاً 11 رقم باشد"),
|
||||
car: Yup.string().required("نوع خودرو الزامی است"),
|
||||
number_of_carcasses: Yup.number()
|
||||
.required("حجم لاشه الزامی است")
|
||||
.min(1, "حجم لاشه باید بیشتر از 0 باشد"),
|
||||
weight_of_carcasses: Yup.number()
|
||||
.required("وزن لاشه الزامی است")
|
||||
.min(0.01, "وزن باید بیشتر از 0 باشد"),
|
||||
bar_image: Yup.string(),
|
||||
selectedDate: Yup.date().required("تاریخ الزامی است"),
|
||||
});
|
||||
|
||||
export const GuildSubmitFreeBar = ({ guildKey, item, editMode }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
// const { inventorySelectedKillHouse } = useSelector(
|
||||
// (state) => state.slaughterSlice
|
||||
// );
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
|
||||
const thenCallback = (r) => {
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(
|
||||
guildGetFreeBars({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const [profileImages, setProfileImages] = useState([]);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
kill_house_key: "",
|
||||
slaughter_name: item ? item.killHouseName : "",
|
||||
slaughter_mobile: item ? item.killHouseMobile : "",
|
||||
province: item ? item.province : "",
|
||||
city: item ? item.city : "",
|
||||
vet_farm_name: item ? item.killHouseVetName : "",
|
||||
vet_farm_mobile: item ? item.killHouseVetMobile : "",
|
||||
driver_name: item ? item.driverName : "",
|
||||
driver_mobile: item ? item.driverMobile : "",
|
||||
car: item ? item.car : "",
|
||||
number_of_carcasses: item ? item.numberOfCarcasses : "",
|
||||
weight_of_carcasses: item ? item.weightOfCarcasses : "",
|
||||
bar_image: "",
|
||||
selectedDate: item ? new Date(item.date) : new Date(),
|
||||
},
|
||||
validationSchema: ValidationSchema,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
if (item?.barImage) {
|
||||
factorPaymentHandler([{ data_url: item?.barImage }]);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const factorPaymentHandler = (imageList, addUpdateIndex) => {
|
||||
if (imageList[0]) {
|
||||
formik.setFieldValue("bar_image", fixBase64(imageList[0]?.data_url));
|
||||
}
|
||||
setProfileImages(imageList);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction="column">
|
||||
<form
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: SPACING.LARGE,
|
||||
}}
|
||||
>
|
||||
<DatePicker
|
||||
disabled={editMode}
|
||||
label="تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "100%" }} {...params} />
|
||||
)}
|
||||
value={formik.values.selectedDate}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("selectedDate", new Date(e));
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
id="slaughter_name"
|
||||
name="slaughter_name"
|
||||
label="نام کشتارگاه"
|
||||
value={formik.values.slaughter_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.slaughter_name &&
|
||||
Boolean(formik.errors.slaughter_name)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.slaughter_name && formik.errors.slaughter_name
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="slaughter_mobile"
|
||||
name="slaughter_mobile"
|
||||
label="تلفن کشتارگاه"
|
||||
value={formik.values.slaughter_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.slaughter_mobile &&
|
||||
Boolean(formik.errors.slaughter_mobile)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.slaughter_mobile && formik.errors.slaughter_mobile
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="province"
|
||||
name="province"
|
||||
label="استان"
|
||||
value={formik.values.province}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.province && Boolean(formik.errors.province)}
|
||||
helperText={formik.touched.province && formik.errors.province}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="city"
|
||||
name="city"
|
||||
label="شهر"
|
||||
value={formik.values.city}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.city && Boolean(formik.errors.city)}
|
||||
helperText={formik.touched.city && formik.errors.city}
|
||||
/>
|
||||
<TextField
|
||||
id="vet_farm_name"
|
||||
name="vet_farm_name"
|
||||
label="نام دامپزشک کشتارگاه"
|
||||
value={formik.values.vet_farm_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.vet_farm_name && Boolean(formik.errors.vet_farm_name)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.vet_farm_name && formik.errors.vet_farm_name
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="vet_farm_mobile"
|
||||
name="vet_farm_mobile"
|
||||
label="تلفن دامپزشک کشتارگاه"
|
||||
value={formik.values.vet_farm_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.vet_farm_mobile &&
|
||||
Boolean(formik.errors.vet_farm_mobile)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.vet_farm_mobile && formik.errors.vet_farm_mobile
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="driver_name"
|
||||
name="driver_name"
|
||||
label="نام راننده"
|
||||
value={formik.values.driver_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.driver_name && Boolean(formik.errors.driver_name)
|
||||
}
|
||||
helperText={formik.touched.driver_name && formik.errors.driver_name}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="driver_mobile"
|
||||
name="driver_mobile"
|
||||
label="تلفن راننده"
|
||||
value={formik.values.driver_mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.driver_mobile && Boolean(formik.errors.driver_mobile)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.driver_mobile && formik.errors.driver_mobile
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="car"
|
||||
name="car"
|
||||
label="خودرو"
|
||||
value={formik.values.car}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.car && Boolean(formik.errors.car)}
|
||||
helperText={formik.touched.car && formik.errors.car}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="number_of_carcasses"
|
||||
name="number_of_carcasses"
|
||||
label="حجم لاشه"
|
||||
InputProps={{
|
||||
endAdornment: <InputAdornment position="end">قطعه</InputAdornment>,
|
||||
}}
|
||||
value={formik.values.number_of_carcasses}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.number_of_carcasses &&
|
||||
Boolean(formik.errors.number_of_carcasses)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.number_of_carcasses &&
|
||||
formik.errors.number_of_carcasses
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="weight_of_carcasses"
|
||||
name="weight_of_carcasses"
|
||||
label="وزن لاشه"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">کیلوگرم</InputAdornment>
|
||||
),
|
||||
}}
|
||||
value={formik.values.weight_of_carcasses}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.weight_of_carcasses &&
|
||||
Boolean(formik.errors.weight_of_carcasses)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.weight_of_carcasses &&
|
||||
formik.errors.weight_of_carcasses
|
||||
}
|
||||
/>
|
||||
|
||||
<ImageUpload
|
||||
onChange={factorPaymentHandler}
|
||||
images={profileImages}
|
||||
maxNumber={1}
|
||||
title={"تصویر بار"}
|
||||
/>
|
||||
|
||||
{formik.touched.driver_mobile &&
|
||||
Boolean(formik.errors.driver_mobile) && (
|
||||
<Typography color="error">ثبت تصویر بار الزامی است</Typography>
|
||||
)}
|
||||
|
||||
<Button
|
||||
disabled={!formik.isValid}
|
||||
onClick={() => {
|
||||
if (editMode) {
|
||||
dispatch(
|
||||
guildEditFreeBar({
|
||||
key: guildKey,
|
||||
kill_house_name: formik.values.slaughter_name,
|
||||
kill_house_mobile: formik.values.slaughter_mobile,
|
||||
kill_house_vet_name: formik.values.vet_farm_name,
|
||||
kill_house_vet_mobile: formik.values.vet_farm_mobile,
|
||||
province: formik.values.province,
|
||||
city: formik.values.city,
|
||||
driver_name: formik.values.driver_name,
|
||||
driver_mobile: formik.values.driver_mobile,
|
||||
car: formik.values.car,
|
||||
number_of_carcasses: formik.values.number_of_carcasses,
|
||||
weight_of_carcasses: formik.values.weight_of_carcasses,
|
||||
bar_image: formik.values.bar_image,
|
||||
date: formik.values.selectedDate,
|
||||
})
|
||||
).then(thenCallback);
|
||||
} else {
|
||||
dispatch(
|
||||
guildSubmitFreeBar({
|
||||
steward_key: guildKey,
|
||||
kill_house_name: formik.values.slaughter_name,
|
||||
kill_house_mobile: formik.values.slaughter_mobile,
|
||||
kill_house_vet_name: formik.values.vet_farm_name,
|
||||
kill_house_vet_mobile: formik.values.vet_farm_mobile,
|
||||
province: formik.values.province,
|
||||
city: formik.values.city,
|
||||
driver_name: formik.values.driver_name,
|
||||
driver_mobile: formik.values.driver_mobile,
|
||||
car: formik.values.car,
|
||||
number_of_carcasses: formik.values.number_of_carcasses,
|
||||
weight_of_carcasses: formik.values.weight_of_carcasses,
|
||||
bar_image: formik.values.bar_image,
|
||||
date: formik.values.selectedDate,
|
||||
})
|
||||
).then(thenCallback);
|
||||
}
|
||||
}}
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
>
|
||||
{editMode ? "ویرایش" : "ثبت"}
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
5
src/features/guild/components/GuilldBroadcast.js
Normal file
5
src/features/guild/components/GuilldBroadcast.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { GuildBroadCastManagement } from "./GuildBroadCastManagement";
|
||||
|
||||
export const GuildBroadcast = () => {
|
||||
return <GuildBroadCastManagement />;
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
import { useFormik } from "formik";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { Button, InputAdornment, TextField } from "@mui/material";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { guildUpdateAllocatedStockService } from "../services/guild-update-allocated-stock";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
|
||||
import { guildGetInventoryAllocatedService } from "../services/guild-get-inventory-allocated";
|
||||
import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { senfGetInventoryStockService } from "../services/senf-get-inventory-stock";
|
||||
import { senfGetInventoryAllocatedService } from "../services/senf-get-inventory-allocated";
|
||||
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
|
||||
|
||||
const schema = Yup.object().shape({
|
||||
quantity: Yup.number().required("وارد کردن تعداد اجباری است"),
|
||||
weight: Yup.number().required("وارد کردن وزن اجباری است"),
|
||||
});
|
||||
|
||||
export const RegisterEditDeliveryNumberAndWeight = ({ item }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
quantity: item?.receiverRealNumberOfCarcasses,
|
||||
weight: item?.receiverRealWeightOfCarcasses,
|
||||
},
|
||||
validationSchema: schema,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
guildUpdateAllocatedStockService({
|
||||
steward: true,
|
||||
allocation_key: item.key,
|
||||
receiver_real_number_of_carcasses: Number(values.quantity),
|
||||
receiver_real_weight_of_carcasses: Number(values.weight),
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
if (getRoleFromUrl() === "senf") {
|
||||
dispatch(
|
||||
senfGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
senfGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
guildGetInventoryStockService({
|
||||
date: selectedDate1,
|
||||
role_key: checkPathStartsWith("senf")
|
||||
? selectedSubUser?.key
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
guildGetInventoryAllocatedService({
|
||||
date: selectedDate1,
|
||||
role_key: checkPathStartsWith("senf")
|
||||
? selectedSubUser?.key
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const quantity = formik.values.weight / item.indexWeight;
|
||||
formik.setFieldValue("quantity", quantity.toFixed(0));
|
||||
}, [formik.values.weight]);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" width="100%">
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
id="weight"
|
||||
name="weight"
|
||||
label="وزن واقعی تحویلی"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">کیلوگرم</InputAdornment>
|
||||
),
|
||||
}}
|
||||
value={formik.values.weight}
|
||||
onChange={formik.handleChange}
|
||||
error={formik.touched.weight && formik.errors.weight}
|
||||
helperText={formik.touched.weight && formik.errors.weight}
|
||||
/>
|
||||
<TextField
|
||||
id="quantity"
|
||||
name="quantity"
|
||||
label="تعداد واقعی تحویلی"
|
||||
disabled={true}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">قطعه</InputAdornment>
|
||||
),
|
||||
}}
|
||||
value={formik.values.quantity}
|
||||
onChange={formik.handleChange}
|
||||
error={formik.touched.quantity && formik.errors.quantity}
|
||||
helperText={formik.touched.quantity && formik.errors.quantity}
|
||||
/>
|
||||
<Button type="submit" fullWidth variant="contained">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
890
src/features/guild/components/StewardAllocationToGuild.js
Normal file
890
src/features/guild/components/StewardAllocationToGuild.js
Normal file
@@ -0,0 +1,890 @@
|
||||
import React, { useContext, useEffect, useState, useCallback } from "react";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputAdornment,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useFormik } from "formik";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { provincePolicyGetUploadImageService } from "../../province/services/province-policy-upload-image";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { slaughterGetProductsService } from "../../slaughter-house/services/slaughter-inventory-gets";
|
||||
import { slaughterGetGuildsForAllocateService } from "../../slaughter-house/services/slaughter-get-guilds-for-allocate";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { fixBase64 } from "../../../utils/toBase64";
|
||||
import { CLOSE_MODAL, DRAWER } from "../../../lib/redux/slices/appSlice";
|
||||
import { NumberInput } from "../../../components/number-format-custom/NumberFormatCustom";
|
||||
import { ImageUpload } from "../../../components/image-upload/ImageUpload";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import {
|
||||
slaughterAllocateStewardService,
|
||||
slaughterEditAllocateStewardService,
|
||||
} from "../../slaughter-house/services/slaughter-allocate-steward";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../slaughter-house/services/handle-fetch-slaughter-products";
|
||||
import MonthlyDataCalendar from "../../../components/date-picker/MonthlyDataCalendar";
|
||||
import PersianDate from "persian-date";
|
||||
import axios from "axios";
|
||||
import { LabelField } from "../../../components/label-field/LabelField";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
|
||||
|
||||
export const StewardAllocationToGuild = ({
|
||||
item,
|
||||
key,
|
||||
sellerType,
|
||||
fetchData,
|
||||
buyerType,
|
||||
allocationType,
|
||||
sellType,
|
||||
updateTable,
|
||||
fetchApiData,
|
||||
editData,
|
||||
coldHouseKey,
|
||||
coldHouseItemKey,
|
||||
killHouseAllocation,
|
||||
priceInfo,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [productData, setProductData] = useState([]);
|
||||
const [guildsData, setGuildsData] = useState([]);
|
||||
const [selectedInventory, setSelectedInventory] = useState("governmental");
|
||||
const [approvedStatus, setApprovedStatus] = useState("true");
|
||||
const [productKey, setProductKey] = useState(null);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [profileImages, setProfileImages] = useState(
|
||||
editData?.image ? [{ data_url: editData.image }] : []
|
||||
);
|
||||
|
||||
const [value, setValue] = useState("own");
|
||||
const [imageUploadLimit, setImageUploadLimit] = useState(1);
|
||||
const [imageChanged, setImageChanged] = useState(false);
|
||||
const [changeMobile, setChangeMobile] = useState(false);
|
||||
const [selectedCalendarDate, setSelectedCalendarDate] = useState(null);
|
||||
const [calendarDayData, setCalendarDayData] = useState({});
|
||||
const [productionDate, setProductionDate] = useState(null);
|
||||
const [selectedDateAmount, setSelectedDateAmount] = useState(null);
|
||||
const [calendarRawData, setCalendarRawData] = useState({
|
||||
governmental: [],
|
||||
free: [],
|
||||
});
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
setBuyerData({
|
||||
key: "",
|
||||
item: "",
|
||||
buyerType: "",
|
||||
allocationType: "",
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (priceInfo?.active === false) {
|
||||
setApprovedStatus("false");
|
||||
}
|
||||
}, [priceInfo?.active]);
|
||||
|
||||
useEffect(() => {
|
||||
if (approvedStatus === "true" && priceInfo?.active) {
|
||||
formik.setFieldValue("price", priceInfo?.killHousePrice);
|
||||
}
|
||||
}, [approvedStatus]);
|
||||
|
||||
const handleSellType = (event) => {
|
||||
const newType = event.target.value;
|
||||
setSelectedInventory(newType);
|
||||
};
|
||||
|
||||
const handleApprovedPrice = (event) => {
|
||||
const newType = event.target.value;
|
||||
setApprovedStatus(newType);
|
||||
};
|
||||
|
||||
const handleDateSelect = (dateInfo) => {
|
||||
if (dateInfo && dateInfo.formattedDate) {
|
||||
setSelectedCalendarDate(dateInfo.formattedDate);
|
||||
|
||||
const data = calendarDayData[dateInfo.formattedDate];
|
||||
|
||||
if (data && data.originalDay) {
|
||||
setProductionDate(data.originalDay);
|
||||
}
|
||||
|
||||
if (data && (data.amount !== undefined || data.value1 !== undefined)) {
|
||||
const rawAmount = data.amount !== undefined ? data.amount : data.value1;
|
||||
const normalizedAmount =
|
||||
typeof rawAmount === "string"
|
||||
? Number(rawAmount.replace(/,/g, ""))
|
||||
: Number(rawAmount);
|
||||
setSelectedDateAmount(
|
||||
Number.isFinite(normalizedAmount) ? normalizedAmount : null
|
||||
);
|
||||
} else {
|
||||
setSelectedDateAmount(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const transformCalendarData = useCallback((dataArray) => {
|
||||
if (!Array.isArray(dataArray)) return {};
|
||||
|
||||
const transformedData = {};
|
||||
dataArray.forEach((item) => {
|
||||
if (item.day && item.amount !== undefined) {
|
||||
const persianDate = new PersianDate(new Date(item.day));
|
||||
const persianDateStr = persianDate.format("YYYY/MM/DD");
|
||||
const rawAmount = item.amount;
|
||||
const normalizedAmount =
|
||||
typeof rawAmount === "string"
|
||||
? Number(rawAmount.replace(/,/g, ""))
|
||||
: Number(rawAmount);
|
||||
transformedData[persianDateStr] = {
|
||||
value1: normalizedAmount,
|
||||
originalDay: item.day,
|
||||
active: item.active === true, // Store active status
|
||||
};
|
||||
}
|
||||
});
|
||||
return transformedData;
|
||||
}, []);
|
||||
|
||||
const updateCalendarData = useCallback((dataArray) => {
|
||||
const transformed = transformCalendarData(dataArray);
|
||||
setCalendarDayData(transformed);
|
||||
}, []);
|
||||
|
||||
const fetchCalendarData = useCallback(
|
||||
async (dateParam = selectedDate1) => {
|
||||
try {
|
||||
const response = await axios.get("/steward-remain-weight/", {
|
||||
params: {
|
||||
date: dateParam,
|
||||
role_key: checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key
|
||||
: "",
|
||||
},
|
||||
});
|
||||
if (response.data) {
|
||||
setCalendarRawData({
|
||||
governmental: response.data.governmental || [],
|
||||
free: response.data.free || [],
|
||||
});
|
||||
const dataToShow =
|
||||
selectedInventory === "governmental"
|
||||
? response.data.governmental
|
||||
: response.data.free;
|
||||
updateCalendarData(dataToShow || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching calendar data:", error);
|
||||
}
|
||||
},
|
||||
[selectedInventory, updateCalendarData, selectedDate1, selectedSubUser]
|
||||
);
|
||||
|
||||
const [buyerData, setBuyerData] = useState({
|
||||
key,
|
||||
item,
|
||||
buyerType,
|
||||
allocationType,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (getRoleFromUrl() === "Steward") {
|
||||
setValue("free");
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCalendarData(selectedDate1);
|
||||
}, [selectedDate1]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
calendarRawData.governmental.length > 0 ||
|
||||
calendarRawData.free.length > 0
|
||||
) {
|
||||
const dataToShow =
|
||||
selectedInventory === "governmental"
|
||||
? calendarRawData.governmental
|
||||
: calendarRawData.free;
|
||||
updateCalendarData(dataToShow);
|
||||
setSelectedCalendarDate(null);
|
||||
setProductionDate(null);
|
||||
setSelectedDateAmount(null);
|
||||
}
|
||||
}, [selectedInventory, calendarRawData]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
provincePolicyGetUploadImageService({
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload?.data) {
|
||||
setImageUploadLimit(r.payload.data.killHouseAllocation);
|
||||
}
|
||||
});
|
||||
|
||||
if (!editData) {
|
||||
dispatch(
|
||||
slaughterGetProductsService({
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
setProductData(r.payload.data);
|
||||
});
|
||||
if (!item) {
|
||||
dispatch(
|
||||
slaughterGetGuildsForAllocateService({
|
||||
free: value === "free" ? true : false,
|
||||
role_key: checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setGuildsData(r.payload.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [value, selectedSubUser?.key]);
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
mobile: Yup.string().when([], {
|
||||
is: () => !editData,
|
||||
then: (schema) =>
|
||||
schema
|
||||
.required("شماره موبایل الزامی است")
|
||||
.min(11, "شماره موبایل باید 11 رقم باشد")
|
||||
.max(11, "شماره موبایل باید 11 رقم باشد")
|
||||
.matches(
|
||||
/^09\d{9}$/,
|
||||
"شماره موبایل باید با 09 شروع شود و 11 رقم باشد"
|
||||
),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.integer("عدد باید صحیح باشد!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!")
|
||||
.test(
|
||||
"max-production-date-amount",
|
||||
`وزن نمیتواند بیشتر از موجودی تاریخ تولید (${
|
||||
selectedDateAmount?.toLocaleString() || 0
|
||||
} کیلوگرم) باشد!`,
|
||||
function (value) {
|
||||
if (!selectedDateAmount || selectedDateAmount === null) return true;
|
||||
return (
|
||||
value <= selectedDateAmount + (editData?.realWeightOfCarcasses || 0)
|
||||
);
|
||||
}
|
||||
),
|
||||
price: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!"),
|
||||
wholePrice: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!"),
|
||||
...(killHouseAllocation && {
|
||||
image: Yup.string().when([], {
|
||||
is: () => (!editData || imageChanged) && imageUploadLimit > 0,
|
||||
then: Yup.string().required("عکس الزامی است"),
|
||||
otherwise: Yup.string().notRequired(),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const factorPaymentHandler = (imageList) => {
|
||||
if (imageList[0]) {
|
||||
formik.setFieldValue("image", fixBase64(imageList[0]?.data_url));
|
||||
setImageChanged(true);
|
||||
} else {
|
||||
formik.setFieldValue("image", "");
|
||||
setImageChanged(true);
|
||||
}
|
||||
setProfileImages(imageList);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
mobile: "",
|
||||
weight: editData?.realWeightOfCarcasses || "",
|
||||
wholePrice: editData?.totalAmount || "",
|
||||
price: editData?.amount || "",
|
||||
image: editData?.image || "",
|
||||
},
|
||||
validationSchema,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, [selectedDateAmount]);
|
||||
|
||||
useEffect(() => {
|
||||
if (formik.values.weight && formik.values.price) {
|
||||
formik.setFieldValue(
|
||||
"wholePrice",
|
||||
formik.values.price * formik.values.weight
|
||||
);
|
||||
}
|
||||
}, [formik.values.price, formik.values.weight]);
|
||||
|
||||
const successSubmit = () => {
|
||||
dispatch(
|
||||
fetchSlaughterBroadcastAndProducts({
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
content: null,
|
||||
})
|
||||
);
|
||||
fetchApiData && fetchApiData(1);
|
||||
updateTable && updateTable();
|
||||
fetchData && fetchData(1);
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
};
|
||||
|
||||
const [dateRangeError, setDateRangeError] = useState(null);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
direction="column"
|
||||
justifyContent="center"
|
||||
alignItems="flex-start"
|
||||
gap={1.8}
|
||||
>
|
||||
{!editData && (
|
||||
<DatePicker
|
||||
label="تاریخ ثبت توزیع"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...params}
|
||||
error={Boolean(dateRangeError) || params.error}
|
||||
helperText={dateRangeError || params.helperText}
|
||||
/>
|
||||
)}
|
||||
shouldDisableDate={(date) => {
|
||||
const d = moment(date);
|
||||
const today = moment();
|
||||
const yesterday = moment().subtract(1, "day");
|
||||
return !(d.isSame(today, "day") || d.isSame(yesterday, "day"));
|
||||
}}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
if (!e) {
|
||||
setDateRangeError(null);
|
||||
return;
|
||||
}
|
||||
const d = moment(e);
|
||||
const today = moment();
|
||||
const yesterday = moment().subtract(1, "day");
|
||||
const isAllowed =
|
||||
d.isSame(today, "day") || d.isSame(yesterday, "day");
|
||||
if (!isAllowed) {
|
||||
setDateRangeError(
|
||||
"تنها امکان انتخاب «امروز» یا «دیروز» وجود دارد."
|
||||
);
|
||||
return;
|
||||
}
|
||||
setDateRangeError(null);
|
||||
const formatted = moment(e).format("YYYY-MM-DD");
|
||||
setSelectedDate1(formatted);
|
||||
fetchCalendarData(formatted);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!editData && !coldHouseKey && (
|
||||
<Grid xs={12} container>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="hatching"
|
||||
options={
|
||||
productData
|
||||
? productData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i.name}`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setProductKey(value.data);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب محصول" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!editData && (
|
||||
<LabelField label="خریداران">
|
||||
<FormControl fullWidth>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="own"
|
||||
control={<Radio />}
|
||||
label="اختصاصی"
|
||||
/>
|
||||
<FormControlLabel value="free" control={<Radio />} label="آزاد" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)}
|
||||
|
||||
{!item && !editData && (
|
||||
<Grid xs={12} container>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="hatching"
|
||||
options={
|
||||
guildsData
|
||||
? guildsData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i?.guildsName} ${i?.user?.fullname} (${i?.user?.mobile})`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setBuyerData({
|
||||
item: value?.data,
|
||||
key: value?.data?.key,
|
||||
allocationType: "steward_guild",
|
||||
buyerType: "Guild",
|
||||
});
|
||||
formik.setFieldValue("mobile", value?.data?.user?.mobile);
|
||||
formik.setFieldTouched("mobile", true, false);
|
||||
formik.validateField("mobile");
|
||||
const reg = new RegExp(/^09\d{9}$/);
|
||||
if (!reg.test(value?.data?.user?.mobile)) {
|
||||
setChangeMobile(true);
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب صنف" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{!item && !editData && (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
p={1}
|
||||
gap={SPACING.TINY}
|
||||
sx={{
|
||||
border: 2,
|
||||
borderColor: "#e6e6e6",
|
||||
borderRadius: 2,
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="error">
|
||||
<Checkbox
|
||||
sx={{ ml: -1.25 }}
|
||||
checked={changeMobile}
|
||||
onChange={() => setChangeMobile(!changeMobile)}
|
||||
/>
|
||||
از این قسمت میتوانید تلفن صنف را ویرایش کنید.
|
||||
</Typography>
|
||||
|
||||
{buyerData?.key && changeMobile && (
|
||||
<TextField
|
||||
fullWidth
|
||||
id="mobile"
|
||||
value={formik.values.mobile}
|
||||
error={
|
||||
formik.touched.mobile ? Boolean(formik.errors.mobile) : null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.mobile && Boolean(formik.errors.mobile)
|
||||
? formik.errors.mobile
|
||||
: null
|
||||
}
|
||||
label="موبایل"
|
||||
autoComplete="current-password"
|
||||
variant="outlined"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!item && !editData && priceInfo?.active !== false && (
|
||||
<LabelField label="نوع فروش">
|
||||
<FormControl fullWidth>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={approvedStatus}
|
||||
onChange={handleApprovedPrice}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value={true}
|
||||
control={<Radio />}
|
||||
label="قیمت دولتی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value={false}
|
||||
control={<Radio />}
|
||||
label="قیمت آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)}
|
||||
|
||||
{!item && !editData && (
|
||||
<LabelField label="نوع انبار">
|
||||
<FormControl fullWidth>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={selectedInventory}
|
||||
onChange={handleSellType}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="governmental"
|
||||
control={<Radio />}
|
||||
label="دولتی"
|
||||
/>
|
||||
<FormControlLabel value="free" control={<Radio />} label="آزاد" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)}
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
gap={SPACING.TINY}
|
||||
sx={{ width: "100%" }}
|
||||
direction="column"
|
||||
>
|
||||
<MonthlyDataCalendar
|
||||
onDateSelect={handleDateSelect}
|
||||
dayData={calendarDayData}
|
||||
selectedDate={selectedCalendarDate}
|
||||
maxGregorianDate={selectedDate1}
|
||||
label={`تاریخ تولید گوشت ${
|
||||
selectedDateAmount !== null
|
||||
? `(موجودی: ${selectedDateAmount?.toLocaleString()} کیلوگرم)`
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
{productionDate &&
|
||||
selectedDate1 &&
|
||||
moment(productionDate).isAfter(moment(selectedDate1), "day") && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "#d32f2f",
|
||||
fontSize: "0.75rem",
|
||||
marginTop: "4px",
|
||||
marginRight: "14px",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
تاریخ تولید نمیتواند بعد از تاریخ انتخابی باشد
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
decimalScale={0}
|
||||
allowNegative={false}
|
||||
fullWidth
|
||||
id="weight"
|
||||
label="وزن لاشه"
|
||||
variant="outlined"
|
||||
value={formik.values.weight}
|
||||
error={
|
||||
!selectedDateAmount && !productionDate
|
||||
? true
|
||||
: formik.touched.weight
|
||||
? Boolean(formik.errors.weight)
|
||||
: selectedDateAmount && formik.values.weight > selectedDateAmount
|
||||
}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (value === "" || value === null || value === undefined) {
|
||||
formik.setFieldValue("weight", "");
|
||||
return;
|
||||
}
|
||||
const intValue = Math.floor(Number(value));
|
||||
if (intValue > 0) {
|
||||
formik.setFieldValue("weight", intValue);
|
||||
} else if (intValue === 0) {
|
||||
formik.setFieldValue("weight", "");
|
||||
}
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
!selectedDateAmount && !productionDate
|
||||
? "لطفاً ابتدا تاریخ تولید را انتخاب کنید!"
|
||||
: formik.touched.weight && Boolean(formik.errors.weight)
|
||||
? formik.errors.weight
|
||||
: null
|
||||
}
|
||||
disabled={!selectedDateAmount && !productionDate}
|
||||
sx={{
|
||||
"& .MuiFormHelperText-root": {
|
||||
color:
|
||||
selectedDateAmount && formik.values.weight > selectedDateAmount
|
||||
? "error.main"
|
||||
: undefined,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
id="price"
|
||||
label="قیمت هر کیلوگرم"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
endAdornment: <InputAdornment position="start">ریال</InputAdornment>,
|
||||
}}
|
||||
value={formik.values.price}
|
||||
error={formik.touched.price ? Boolean(formik.errors.price) : null}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.price && Boolean(formik.errors.price)
|
||||
? formik.errors.price
|
||||
: null
|
||||
}
|
||||
/>
|
||||
|
||||
<NumberInput
|
||||
disabled
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
id="wholePrice"
|
||||
label="هزینه کل"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
endAdornment: <InputAdornment position="start">ریال</InputAdornment>,
|
||||
}}
|
||||
value={formik.values.wholePrice}
|
||||
error={
|
||||
formik.touched.wholePrice ? Boolean(formik.errors.wholePrice) : null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.wholePrice && Boolean(formik.errors.wholePrice)
|
||||
? formik.errors.wholePrice
|
||||
: null
|
||||
}
|
||||
/>
|
||||
{(killHouseAllocation || (editData && editData.image)) && (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<ImageUpload
|
||||
onChange={factorPaymentHandler}
|
||||
images={profileImages}
|
||||
maxNumber={1}
|
||||
title={"بارگزاری سند"}
|
||||
/>
|
||||
{formik.touched.image && Boolean(formik.errors.image) && (
|
||||
<Typography color="error">ثبت تصویر الزامی است</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid container xs={12} spacing={SPACING.SMALL}>
|
||||
<Grid xs={6}>
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
disabled={
|
||||
editData
|
||||
? !formik.isValid
|
||||
: !formik.isValid ||
|
||||
(coldHouseKey ? false : !productKey) ||
|
||||
!buyerData?.item?.key ||
|
||||
!productionDate ||
|
||||
(productionDate &&
|
||||
selectedDate1 &&
|
||||
moment(selectedDate1).isBefore(
|
||||
moment(productionDate),
|
||||
"day"
|
||||
))
|
||||
}
|
||||
onClick={() => {
|
||||
let req = {};
|
||||
if (coldHouseItemKey) {
|
||||
req = {
|
||||
allocation_key: coldHouseItemKey,
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
amount: formik.values.price,
|
||||
total_amount: formik.values.wholePrice,
|
||||
role_key: checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
distribution_type: "web",
|
||||
...(imageChanged && { image: formik.values.image }),
|
||||
};
|
||||
} else if (!editData) {
|
||||
req = {
|
||||
seller_type: sellerType,
|
||||
buyer_type: "Guild",
|
||||
guild_key: buyerData?.item?.key,
|
||||
cold_house_key: coldHouseKey || null,
|
||||
product_key: coldHouseKey ? null : productKey.key,
|
||||
type: "manual",
|
||||
allocation_type: coldHouseKey ? "ColdHouse" : "steward_guild",
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
sell_type: sellType,
|
||||
amount: formik.values.price,
|
||||
total_amount: formik.values.wholePrice,
|
||||
approved_price_status:
|
||||
approvedStatus === "true" ? true : false,
|
||||
quota: selectedInventory,
|
||||
date: selectedDate1,
|
||||
production_date: productionDate,
|
||||
role_key: checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
distribution_type: "web",
|
||||
...(buyerData?.item?.user?.mobile !== formik.values.mobile
|
||||
? { interface_number: formik.values.mobile }
|
||||
: {}),
|
||||
...(profileImages.length > 0 && {
|
||||
image: formik.values.image,
|
||||
}),
|
||||
};
|
||||
req = Object.fromEntries(
|
||||
Object.entries(req).filter(([, value]) => value !== null)
|
||||
);
|
||||
} else {
|
||||
req = {
|
||||
allocation_key: editData?.key,
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
amount: formik.values.price,
|
||||
role_key: checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
total_amount: formik.values.wholePrice,
|
||||
distribution_type: "web",
|
||||
...(imageChanged && { image: formik.values.image }),
|
||||
};
|
||||
}
|
||||
|
||||
if (!editData) {
|
||||
dispatch(slaughterAllocateStewardService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
successSubmit();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch(slaughterEditAllocateStewardService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
successSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{editData ? "ویرایش" : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
}}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
609
src/features/guild/components/StewardDailyList.js
Normal file
609
src/features/guild/components/StewardDailyList.js
Normal file
@@ -0,0 +1,609 @@
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import InputAdornment from "@mui/material/InputAdornment";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import axios from "axios";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
IconButton,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
import moment from "moment";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../lib/redux/slices/appSlice";
|
||||
import { slaughterGetProductsService } from "../../slaughter-house/services/slaughter-inventory-gets";
|
||||
import {
|
||||
slaughterDeleteDailyListService,
|
||||
slaughterGetPriceService,
|
||||
submitBatchAllocationsService,
|
||||
} from "../../slaughter-house/services/slaughter-add-daily-list";
|
||||
import { SlaughterAddDailyList } from "../../slaughter-house/components/slaughter-add-daily-list/SlaughterAddDailyList";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { NumberInput } from "../../../components/number-format-custom/NumberFormatCustom";
|
||||
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
|
||||
|
||||
export const StewardDailyList = () => {
|
||||
const [productsTable, setProductsTable] = useState();
|
||||
const [slaughterProducts, setSlaughterProducts] = useState();
|
||||
const [prices, setPrices] = useState([]);
|
||||
const [rendered, setrendered] = useState(false);
|
||||
const [weights, setWeights] = useState([]);
|
||||
const [data, setData] = useState([]);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [filteredData, setFilteredData] = useState([]);
|
||||
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const priceRefs = useRef([]);
|
||||
const weightRefs = useRef([]);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [priceState, setPriceState] = useState({
|
||||
active: false,
|
||||
killHousePrice: 0,
|
||||
stewardPrice: 0,
|
||||
guildPrice: 0,
|
||||
});
|
||||
|
||||
const getPriceByRole = () => {
|
||||
const role = getRoleFromUrl();
|
||||
if (role === "KillHouse") return priceState.killHousePrice;
|
||||
if (role === "Steward") return priceState.stewardPrice;
|
||||
if (role === "Guilds") return priceState.guildPrice;
|
||||
return 0;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
priceRefs.current = priceRefs.current.slice(0, data?.length || 0);
|
||||
weightRefs.current = weightRefs.current.slice(0, data?.length || 0);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchTerm) {
|
||||
const filtered = tableData.filter((item) =>
|
||||
item.some((cell) =>
|
||||
String(cell).toLowerCase().includes(searchTerm.toLowerCase())
|
||||
)
|
||||
);
|
||||
setFilteredData(filtered);
|
||||
} else {
|
||||
setFilteredData(tableData);
|
||||
}
|
||||
}, [searchTerm, tableData]);
|
||||
|
||||
const handleKeyDown = (e, index, fieldType) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
|
||||
if (fieldType === "price") {
|
||||
const updatedPrices = [...prices];
|
||||
updatedPrices[index] = Number(e.target.value.replace(/,/g, ""));
|
||||
setPrices(updatedPrices);
|
||||
|
||||
if (weightRefs.current[index]) {
|
||||
weightRefs.current[index].focus();
|
||||
}
|
||||
} else if (fieldType === "weight") {
|
||||
const updatedWeights = [...weights];
|
||||
updatedWeights[index] = Number(e.target.value.replace(/,/g, ""));
|
||||
setWeights(updatedWeights);
|
||||
|
||||
if (priceState?.active) {
|
||||
let nextIndex = index + 1;
|
||||
while (nextIndex < data.length) {
|
||||
if (weightRefs.current[nextIndex]) {
|
||||
weightRefs.current[nextIndex].focus();
|
||||
break;
|
||||
}
|
||||
nextIndex++;
|
||||
}
|
||||
|
||||
if (nextIndex >= data.length && weightRefs.current[0]) {
|
||||
weightRefs.current[0]?.focus();
|
||||
}
|
||||
} else {
|
||||
let nextIndex = index + 1;
|
||||
while (nextIndex < data.length) {
|
||||
if (priceRefs.current[nextIndex]) {
|
||||
priceRefs.current[nextIndex].focus();
|
||||
break;
|
||||
}
|
||||
nextIndex++;
|
||||
}
|
||||
|
||||
if (nextIndex >= data.length && priceRefs.current[0]) {
|
||||
priceRefs.current[0]?.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const fetchPriceStatus = async () => {
|
||||
dispatch(
|
||||
slaughterGetPriceService({
|
||||
role: getRoleFromUrl(),
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
setPriceState(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchApiData = async () => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`commonly-used/?search=filter&value=&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&page=1&page_size=10000`
|
||||
);
|
||||
setrendered(true);
|
||||
setData(response.data.results || []);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
const getPrice =
|
||||
parseInt(priceState?.active ? getPriceByRole() : prices[i]) *
|
||||
parseInt(weights[i]);
|
||||
return [
|
||||
i + 1,
|
||||
item?.guild?.steward ? "مباشر" : "صنف",
|
||||
`${item?.guild?.guildsName}/${item?.guild?.user?.fullname}/${item?.guild?.user?.city}/${item?.guild?.user?.mobile}`,
|
||||
item?.exclusive ? "اختصاصی" : "آزاد",
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
key={`price-${i}`}
|
||||
size="small"
|
||||
label="قیمت"
|
||||
disabled={priceState?.active}
|
||||
value={priceState?.active ? getPriceByRole() : prices[i] || ""}
|
||||
onKeyDown={(e) => handleKeyDown(e, i, "price")}
|
||||
inputRef={(el) => (priceRefs.current[i] = el)}
|
||||
variant="outlined"
|
||||
style={{ width: 100 }}
|
||||
/>,
|
||||
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
key={`weight-${i}`}
|
||||
size="small"
|
||||
label="وزن"
|
||||
value={weights[i] || ""}
|
||||
onKeyDown={(e) => {
|
||||
handleKeyDown(e, i, "weight");
|
||||
}}
|
||||
inputRef={(el) => (weightRefs.current[i] = el)}
|
||||
variant="outlined"
|
||||
style={{ width: 100 }}
|
||||
/>,
|
||||
isNaN(getPrice) ? "وارد نشده! " : getPrice?.toLocaleString() + " ریال",
|
||||
<IconButton key={i} color="error">
|
||||
<DeleteIcon onClick={() => handleDeleteItem(item.key)} />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
setFilteredData(d);
|
||||
}, [data, prices, weights, priceState]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData();
|
||||
fetchPriceStatus();
|
||||
dispatch(slaughterGetProductsService()).then((r) => {
|
||||
setSlaughterProducts(r.payload.data);
|
||||
});
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = slaughterProducts?.map((item) => {
|
||||
return [item?.name, item?.totalRemainWeight?.toLocaleString()];
|
||||
});
|
||||
|
||||
setProductsTable(d);
|
||||
}, [slaughterProducts]);
|
||||
|
||||
const handleDeleteItem = (key) => {
|
||||
dispatch(slaughterDeleteDailyListService(key)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
fetchApiData(1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleSendAllocate = () => {
|
||||
const filterdData = data?.map((item, i) => {
|
||||
const price = priceState?.active ? getPriceByRole() : prices[i];
|
||||
let d = {
|
||||
seller_type: "Steward",
|
||||
buyer_type: item?.guild?.steward ? "Steward" : "Guild",
|
||||
guild_key: !item?.guild?.steward ? item?.guild?.key : null,
|
||||
steward_key: item?.guild?.steward ? item?.guild?.key : null,
|
||||
product_key: slaughterProducts[0]?.key,
|
||||
type: "manual",
|
||||
allocation_type: item?.steward ? "steward_steward" : "steward_guild",
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: weights[i] || null,
|
||||
sell_type: "free",
|
||||
amount: price || null,
|
||||
total_amount: price * weights[i],
|
||||
approved_price_status: priceState?.active,
|
||||
date: moment(new Date()).format("YYYY-MM-DD"),
|
||||
};
|
||||
d = Object.fromEntries(
|
||||
Object.entries(d).filter(([_, value]) => value !== null)
|
||||
);
|
||||
return d;
|
||||
});
|
||||
|
||||
const finalData = filterdData.filter(
|
||||
(option) =>
|
||||
option.total_amount > 1 && option?.amount && option?.weight_of_carcasses
|
||||
);
|
||||
|
||||
dispatch(submitBatchAllocationsService(finalData)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
setPrices([]);
|
||||
setWeights([]);
|
||||
fetchApiData(1);
|
||||
fetchPriceStatus();
|
||||
dispatch(slaughterGetProductsService()).then((r) => {
|
||||
setSlaughterProducts(r.payload.data);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
title={"موجودی انبار"}
|
||||
columns={["محصول", "مانده انبار (کیلوگرم)"]}
|
||||
data={productsTable}
|
||||
customColors={[{ name: "محصول", color: "red" }]}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
xs={12}
|
||||
container
|
||||
spacing={2}
|
||||
mt={2}
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid item xs={12} md="auto">
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
sx={{ borderRadius: 3, px: 3 }}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: <SlaughterAddDailyList updateTable={fetchApiData} />,
|
||||
title: "افزودن",
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
افزودن مباشر/صنف
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md>
|
||||
<Card variant="outlined" sx={{ borderRadius: 3, boxShadow: 1 }}>
|
||||
<CardContent>
|
||||
<Grid
|
||||
container
|
||||
spacing={2}
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">
|
||||
مجموع وزن وارد شده
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
{weights?.length
|
||||
? weights.reduce((a, b) => a + b, 0).toLocaleString()
|
||||
: "۰"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<Typography variant="subtitle2">وزن باقیمانده</Typography>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color={
|
||||
weights?.length && slaughterProducts
|
||||
? weights?.reduce((a, b) => a + b, 0) >
|
||||
slaughterProducts[0]?.totalRemainWeight
|
||||
? "error"
|
||||
: "text.secondary"
|
||||
: "text.secondary"
|
||||
}
|
||||
>
|
||||
{slaughterProducts?.[0]?.totalRemainWeight !== undefined
|
||||
? weights?.length
|
||||
? (
|
||||
slaughterProducts[0]?.totalRemainWeight -
|
||||
weights.reduce((a, b) => a + b, 0)
|
||||
).toLocaleString()
|
||||
: slaughterProducts[0]?.totalRemainWeight.toLocaleString()
|
||||
: "۰"}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
startIcon={<CheckCircleIcon />}
|
||||
sx={{ borderRadius: 3, px: 3 }}
|
||||
onClick={handleSendAllocate}
|
||||
disabled={
|
||||
weights.length
|
||||
? weights.reduce((a, b) => a + b, 0) >
|
||||
slaughterProducts[0]?.totalRemainWeight
|
||||
: true
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container xs={12} mt={2} gap={1} sx={{ userSelect: "none" }}>
|
||||
<InfoIcon color="error" />
|
||||
<Typography variant="body1" color="error">
|
||||
پس از وارد کردن هر مقدار، کلید Enter را فشار دهید!
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid container xs={12} mt={2} gap={1} sx={{ userSelect: "none" }}>
|
||||
<InfoIcon color="primary" />
|
||||
<Typography variant="body1" color="primary">
|
||||
صرفا تخصیصاتی که هر دو مقدار قیمت و وزن آنها را وارد کنید ثبت خواهند
|
||||
شد.
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid container xs={12} mt={2}>
|
||||
<TextField
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
placeholder="جستجو..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchIcon />
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{filteredData?.length ? (
|
||||
<Grid container xs={12} gap={1} mt={2} mb={2}>
|
||||
{filteredData?.map((item, i) => (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
key={i}
|
||||
sx={{
|
||||
p: 2,
|
||||
pl: 5,
|
||||
borderRadius: 2,
|
||||
backgroundColor: i % 2 === 0 ? "#fef6f0" : "#ffffff",
|
||||
boxShadow: "0 2px 6px rgba(0,0,0,0.05)",
|
||||
position: "relative",
|
||||
flexDirection: "row",
|
||||
gap: 2,
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
top: 12,
|
||||
left: 12,
|
||||
backgroundColor: "#fb8c00",
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: "50%",
|
||||
color: "#fff",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: "0.8rem",
|
||||
fontWeight: 700,
|
||||
boxShadow: "0 1px 4px rgba(0,0,0,0.2)",
|
||||
}}
|
||||
>
|
||||
{item[0]}
|
||||
</Box>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{ minWidth: 64 }}
|
||||
>
|
||||
ماهیت:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[1]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{ minWidth: 64 }}
|
||||
>
|
||||
خریدار:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[2]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{ minWidth: 64 }}
|
||||
>
|
||||
نوع فروش:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[3]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
قیمت هرکیلو:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[4]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
وزن لاشه:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[5]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{ minWidth: 64 }}
|
||||
>
|
||||
قیمت کل:
|
||||
</Typography>
|
||||
<Typography variant="body2" fontSize="0.8rem">
|
||||
{item[6]}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid
|
||||
item
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
{item[7]}
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
{!priceState?.active &&
|
||||
(!prices[i] || !weights[i]) &&
|
||||
(prices[i] || weights[i]) && (
|
||||
<Typography variant="caption" color="error">
|
||||
لطفا همه موارد را وارد کنید و کلید Enter را بزنید
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
<Typography mt={4}>
|
||||
{!rendered
|
||||
? searchTerm
|
||||
? "نتیجهای یافت نشد"
|
||||
: "در حال بارگزاری..."
|
||||
: "موردی یافت نشد!"}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
|
||||
|
||||
export const StewardDispenserSaleOutDashboard = ({ dashboardData }) => {
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
title={"اطلاعات کلی"}
|
||||
columns={["تعداد فروش", "خریدار", "وزن کل لاشه ها"]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.numberOfBars?.toLocaleString(),
|
||||
dashboardData?.numberOfBuyers?.toLocaleString(),
|
||||
dashboardData?.barsWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
230
src/features/guild/components/StewardNorEnterdBarChangeState.js
Normal file
230
src/features/guild/components/StewardNorEnterdBarChangeState.js
Normal file
@@ -0,0 +1,230 @@
|
||||
import React, { useContext } from "react";
|
||||
import {
|
||||
Grid,
|
||||
TextField,
|
||||
Button,
|
||||
RadioGroup,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
FormControl,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { guildAllocatedStockOperationService } from "../services/guild-allocated-stock-operation";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const StewardNorEnterdBarChangeState = ({
|
||||
item,
|
||||
handleUpdate,
|
||||
updateTable,
|
||||
}) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
decision: "approve",
|
||||
weight: item?.realWeightOfCarcasses,
|
||||
volume: item?.realNumberOfCarcasses,
|
||||
weightLoss: item?.weightLossOfCarcasses,
|
||||
regCode: "",
|
||||
regState: "with_code",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
decision: Yup.string().required("انتخاب گزینه الزامی است"),
|
||||
regState: Yup.string(),
|
||||
weight: Yup.string().when("decision", {
|
||||
is: "approve",
|
||||
then: Yup.string().required("وزن الزامی است"),
|
||||
}),
|
||||
volume: Yup.string().when("decision", {
|
||||
is: "approve",
|
||||
then: Yup.string().required("حجم الزامی است"),
|
||||
}),
|
||||
weightLoss: Yup.string().when("decision", {
|
||||
is: "approve",
|
||||
then: Yup.string().required("افت وزن الزامی است"),
|
||||
}),
|
||||
regCode: Yup.string()
|
||||
.matches(/^\d{5}$/, "کد باید یک عدد پنج رقمی باشد")
|
||||
.typeError("یک عدد پنج رقمی وارد کنید!")
|
||||
.when(["regState", "decision"], {
|
||||
is: (regState, decision) =>
|
||||
regState === "with_code" && decision === "approve",
|
||||
then: Yup.string().required("کد احراز الزامی است"),
|
||||
}),
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
const baseRequest = {
|
||||
check_allocation: true,
|
||||
allocation_key: item?.key,
|
||||
};
|
||||
|
||||
const req =
|
||||
values.decision === "reject"
|
||||
? { ...baseRequest, state: "rejected" }
|
||||
: {
|
||||
...baseRequest,
|
||||
state: "accepted",
|
||||
...(values.regState === "with_code" && {
|
||||
registration_code: parseInt(values.regCode),
|
||||
}),
|
||||
receiver_real_number_of_carcasses: parseInt(values.volume),
|
||||
receiver_real_weight_of_carcasses: parseInt(values.weight),
|
||||
weight_loss_of_carcasses: parseInt(values.weightLoss),
|
||||
};
|
||||
|
||||
dispatch(guildAllocatedStockOperationService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
handleUpdate();
|
||||
updateTable && updateTable();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleDecisionChange = (event) => {
|
||||
formik.setFieldValue("decision", event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container spacing={2} justifyContent="center" alignItems="center">
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset">
|
||||
<RadioGroup
|
||||
fullWidth
|
||||
row
|
||||
name="decision"
|
||||
value={formik.values.decision}
|
||||
onChange={handleDecisionChange}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="approve"
|
||||
control={<Radio />}
|
||||
label="تایید"
|
||||
/>
|
||||
<FormControlLabel value="reject" control={<Radio />} label="رد" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
{formik.touched.decision && formik.errors.decision && (
|
||||
<div style={{ color: "red", fontSize: 12 }}>
|
||||
{formik.errors.decision}
|
||||
</div>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{formik.values.decision === "approve" && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="weight"
|
||||
label="وزن"
|
||||
value={formik.values.weight}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.weight && Boolean(formik.errors.weight)}
|
||||
helperText={formik.touched.weight && formik.errors.weight}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="volume"
|
||||
label="حجم"
|
||||
value={formik.values.volume}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.volume && Boolean(formik.errors.volume)}
|
||||
helperText={formik.touched.volume && formik.errors.volume}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="weightLoss"
|
||||
label="افت وزن (کیلوگرم)"
|
||||
value={formik.values.weightLoss}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.weightLoss && Boolean(formik.errors.weightLoss)
|
||||
}
|
||||
helperText={formik.touched.weightLoss && formik.errors.weightLoss}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormControl component="fieldset">
|
||||
<RadioGroup
|
||||
fullWidth
|
||||
row
|
||||
name="regState"
|
||||
value={formik.values.regState}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("regState", e.target.value);
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="with_code"
|
||||
control={<Radio />}
|
||||
label="با کد احراز"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="without_code"
|
||||
control={<Radio />}
|
||||
label="بدون کد احراز"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
{formik.touched.regState && formik.errors.regState && (
|
||||
<div style={{ color: "red", fontSize: 12 }}>
|
||||
{formik.errors.regState}
|
||||
</div>
|
||||
)}
|
||||
</Grid>
|
||||
{formik.values.regState === "with_code" && (
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="regCode"
|
||||
label="کد احراز"
|
||||
value={formik.values.regCode}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.regCode && Boolean(formik.errors.regCode)}
|
||||
helperText={formik.touched.regCode && formik.errors.regCode}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
onClick={formik.handleSubmit}
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color={formik.values.decision === "approve" ? "primary" : "error"}
|
||||
fullWidth
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
|
||||
|
||||
export const StewardSaleDispenserWithinDashboard = ({ dashboardData }) => {
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
title={"اطلاعات کلی"}
|
||||
columns={[
|
||||
"تعداد توزیع",
|
||||
"کل وزن توزیع",
|
||||
"وزن توزیع به مباشر",
|
||||
"وزن توزیع به صنف",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.numberOfAllocations?.toLocaleString(),
|
||||
dashboardData?.totalWeight?.toLocaleString(),
|
||||
dashboardData?.totalStewardWeight?.toLocaleString(),
|
||||
dashboardData?.totalGuildWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
316
src/features/guild/components/StewardSegmant.js
Normal file
316
src/features/guild/components/StewardSegmant.js
Normal file
@@ -0,0 +1,316 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import moment from "moment";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { StewardSegmentSubmitOperation } from "./StewardSegmentSubmitOperation";
|
||||
import { stewardGetOutSellService } from "../services/steward-get-sell-out-service";
|
||||
import { formatJustDate, formatTime } from "../../../utils/formatTime";
|
||||
import { StewardSegmentOperation } from "./StewardSegmentOperation";
|
||||
import { stawardGetSegmentDashboardService } from "../services/steward-get-dashboard-service";
|
||||
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
|
||||
|
||||
export const StewardSegmant = () => {
|
||||
const [data, setData] = useState([]);
|
||||
const [products, setProducts] = useState([]);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
// const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
const getDashboardData = () => {
|
||||
dispatch(
|
||||
stawardGetSegmentDashboardService({
|
||||
value: textValue,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
|
||||
getDashboardData();
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage]);
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
const updateTable = () => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
dispatch(
|
||||
stewardGetOutSellService({
|
||||
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
setProducts(r.payload.data);
|
||||
});
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.toGuild ? "قطعه بند" : "مباشر",
|
||||
`${item?.buyer?.fullname}(${item?.buyer?.mobile})`,
|
||||
item?.toGuild
|
||||
? `${item?.toGuild?.user?.fullname}(${item?.toGuild?.user?.mobile})`
|
||||
: "-",
|
||||
item?.date ? formatTime(item?.date) : "-",
|
||||
item?.productionDate ? formatJustDate(item?.productionDate) : "-",
|
||||
item?.distributionType === "web"
|
||||
? "سایت"
|
||||
: item?.distributionType === "app"
|
||||
? "موبایل"
|
||||
: item?.distributionType === "pos"
|
||||
? "پوز"
|
||||
: item?.distributionType || "-",
|
||||
item?.weight,
|
||||
item?.quota === "governmental"
|
||||
? "دولتی"
|
||||
: item?.quota === "free"
|
||||
? "آزاد"
|
||||
: "-",
|
||||
item?.saleType === "governmental"
|
||||
? "دولتی"
|
||||
: item?.saleType === "free"
|
||||
? "آزاد"
|
||||
: "-",
|
||||
<StewardSegmentOperation
|
||||
key={i}
|
||||
item={item}
|
||||
productKey={products?.[0]?.key}
|
||||
updateTable={updateTable}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
getDashboardData();
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction="column" flexWrap="nowrap" mt={SPACING.SMALL}>
|
||||
<Grid
|
||||
xs={12}
|
||||
container
|
||||
alignItems="center"
|
||||
gap={SPACING.SMALL}
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={[
|
||||
"وزن کل (کیلوگرم)",
|
||||
// "تخصیصات مباشر",
|
||||
"وزن قطعه بندی",
|
||||
// "تخصیصات قطعه بند",
|
||||
"وزن تخصیصی به قطعه بندها",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.totalWeight?.toLocaleString() || "0",
|
||||
// dashboardData?.totalSelfCount?.toLocaleString() || "0",
|
||||
dashboardData?.totalSelfWeight?.toLocaleString() || "0",
|
||||
// dashboardData?.totalOtherCount?.toLocaleString() || "0",
|
||||
dashboardData?.totalOtherWeight?.toLocaleString() || "0",
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
<form>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ثبت ",
|
||||
width: {
|
||||
xs: "100%",
|
||||
sm: "360px",
|
||||
},
|
||||
content: (
|
||||
<StewardSegmentSubmitOperation
|
||||
updateTable={updateTable}
|
||||
productKey={products?.[0]?.key}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت قطعه بندی
|
||||
</Button>
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) =>
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"))
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) =>
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"))
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
{/* <Tooltip title="خروجی اکسل">
|
||||
<Button
|
||||
color="success"
|
||||
onClick={() => {
|
||||
const link = `${
|
||||
axios.defaults.baseURL
|
||||
}kill_house_free_bar_excel/?role=${getRoleFromUrl()}&key=${userKey}&date1=${selectedDate1}&date2=${selectedDate2}&type=carcass&search=filter&value=${textValue}&date_type=buy`;
|
||||
window.location.href = link;
|
||||
}}
|
||||
>
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</Tooltip> */}
|
||||
</Grid>
|
||||
</form>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"ماهیت",
|
||||
"مباشر",
|
||||
"تخصیص به قطعه بند",
|
||||
"تاریخ ",
|
||||
"تاریخ تولید گوشت",
|
||||
"ثبت شده",
|
||||
"وزن (کیلوگرم)",
|
||||
"سهمیه",
|
||||
"نوع فروش",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="قطعه بندی"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
108
src/features/guild/components/StewardSegmentOperation.js
Normal file
108
src/features/guild/components/StewardSegmentOperation.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { stewardDeleteSegmentService } from "../services/steward-segment-delete-operation";
|
||||
import {
|
||||
IconButton,
|
||||
Popover,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { DRAWER } from "../../../lib/redux/slices/appSlice";
|
||||
import { StewardSegmentSubmitOperation } from "./StewardSegmentSubmitOperation";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
||||
import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined";
|
||||
|
||||
export const StewardSegmentOperation = ({ item, updateTable, productKey }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
const handleDelete = () => {
|
||||
handleClose();
|
||||
dispatch(stewardDeleteSegmentService(item.key)).then(() => {
|
||||
updateTable();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<TuneIcon />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<List sx={{ p: 1 }}>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
sx={{ color: "primary.main" }}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ویرایش قطعه بندی",
|
||||
content: (
|
||||
<StewardSegmentSubmitOperation
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
editData={item}
|
||||
productKey={productKey}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "inherit" }}>
|
||||
<EditOutlinedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2">ویرایش</Typography>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton sx={{ color: "error.main" }} onClick={handleDelete}>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "inherit" }}>
|
||||
<DeleteOutlineOutlinedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" color="inherit">
|
||||
حذف
|
||||
</Typography>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</List>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
654
src/features/guild/components/StewardSegmentSubmitOperation.js
Normal file
654
src/features/guild/components/StewardSegmentSubmitOperation.js
Normal file
@@ -0,0 +1,654 @@
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputAdornment,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { SPACING } from "../../../data/spacing";
|
||||
import { Grid } from "../../../components/grid/Grid";
|
||||
import { DRAWER } from "../../../lib/redux/slices/appSlice";
|
||||
import { stewardSegmentSubmitService } from "../services/steward-segment-submit-service";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useContext, useEffect, useState, useCallback } from "react";
|
||||
import { AppContext } from "../../../contexts/AppContext";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../lib/yup/yup";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { stewardEditSegmentService } from "../services/steward-segment-edit-operation";
|
||||
import MonthlyDataCalendar from "../../../components/date-picker/MonthlyDataCalendar";
|
||||
import PersianDate from "persian-date";
|
||||
import axios from "axios";
|
||||
import { LabelField } from "../../../components/label-field/LabelField";
|
||||
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
|
||||
import {
|
||||
slaughterGetGuildsForAllocateService,
|
||||
slaughterGetStewardsForAllocateService,
|
||||
} from "../../slaughter-house/services/slaughter-get-guilds-for-allocate";
|
||||
import { Typography } from "@mui/material";
|
||||
|
||||
const getValidationSchema = (selectedDateAmount) =>
|
||||
Yup.object().shape({
|
||||
weight: Yup.number()
|
||||
.required("وزن لاشه الزامی است")
|
||||
.min(0.01, "وزن باید بیشتر از 0 باشد")
|
||||
.test(
|
||||
"max-production-date-amount",
|
||||
`وزن نمیتواند بیشتر از موجودی تاریخ تولید (${
|
||||
selectedDateAmount?.toLocaleString() || 0
|
||||
} کیلوگرم) باشد!`,
|
||||
function (value) {
|
||||
if (!selectedDateAmount || selectedDateAmount === null) return true;
|
||||
return value <= selectedDateAmount;
|
||||
}
|
||||
),
|
||||
product_key: Yup.string().when("segmentType", {
|
||||
is: "own",
|
||||
then: Yup.string().required("انتخاب کلید الزامی است"),
|
||||
}),
|
||||
});
|
||||
|
||||
export const StewardSegmentSubmitOperation = ({
|
||||
updateTable,
|
||||
productKey,
|
||||
editData,
|
||||
item,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [segmentType, setSegmentType] = useState("own");
|
||||
const [selectedInventory] = useState("free");
|
||||
const [approvedStatus, setApprovedStatus] = useState("governmental");
|
||||
const [buyerCategory, setBuyerCategory] = useState(""); // "stewards" or "guilds"
|
||||
const [guildsData, setGuildsData] = useState([]);
|
||||
const [stewardsData, setStewardsData] = useState([]);
|
||||
const [buyerData, setBuyerData] = useState({
|
||||
key: "",
|
||||
item: "",
|
||||
buyerType: "",
|
||||
allocationType: "",
|
||||
});
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const [selectedCalendarDate, setSelectedCalendarDate] = useState(null);
|
||||
const [calendarDayData, setCalendarDayData] = useState({});
|
||||
const [productionDate, setProductionDate] = useState(null);
|
||||
const [selectedDateAmount, setSelectedDateAmount] = useState(null);
|
||||
const [calendarRawData, setCalendarRawData] = useState({
|
||||
governmental: [],
|
||||
free: [],
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
product_key: productKey || editData?.productkey || "",
|
||||
weight: editData?.weight || "",
|
||||
segmentType: editData ? (editData?.guildkey ? "free" : "own") : "own",
|
||||
},
|
||||
validationSchema: getValidationSchema(selectedDateAmount),
|
||||
onSubmit: (values) => {
|
||||
if (editData) {
|
||||
const req = {
|
||||
weight: values.weight,
|
||||
key: item?.key,
|
||||
};
|
||||
|
||||
dispatch(stewardEditSegmentService(req)).then((r) => {
|
||||
if (r.payload?.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let req;
|
||||
|
||||
if (segmentType === "own") {
|
||||
req = {
|
||||
product_key: values?.product_key,
|
||||
weight: values.weight,
|
||||
sale_type: selectedInventory,
|
||||
quota: approvedStatus,
|
||||
production_date: productionDate,
|
||||
distribution_type: "web",
|
||||
};
|
||||
} else {
|
||||
if (!buyerData?.key) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "لطفا مباشر یا صنف را انتخاب کنید",
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
req = {
|
||||
guild_key: buyerData?.buyerType === "Guild" ? buyerData?.key : null,
|
||||
steward_key:
|
||||
buyerData?.buyerType === "Steward" ? buyerData?.key : null,
|
||||
weight: values.weight,
|
||||
product_key: productKey || "",
|
||||
sale_type: selectedInventory,
|
||||
quota: approvedStatus,
|
||||
production_date: productionDate,
|
||||
distribution_type: "web",
|
||||
};
|
||||
req = Object.fromEntries(
|
||||
Object.entries(req).filter(([, val]) => val !== null)
|
||||
);
|
||||
}
|
||||
|
||||
dispatch(stewardSegmentSubmitService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const handleSegmentTypeChange = (event) => {
|
||||
const newType = event.target.value;
|
||||
setSegmentType(newType);
|
||||
formik.setFieldValue("segmentType", newType);
|
||||
};
|
||||
|
||||
// const handleSellType = (event) => {
|
||||
// const newType = event.target.value;
|
||||
// setSelectedInventory(newType);
|
||||
// };
|
||||
|
||||
const handleApprovedPrice = (event) => {
|
||||
const newType = event.target.value;
|
||||
setApprovedStatus(newType);
|
||||
};
|
||||
|
||||
const handleBuyerCategoryChange = (event) => {
|
||||
const newCategory = event.target.value;
|
||||
setBuyerCategory(newCategory);
|
||||
setBuyerData({
|
||||
key: "",
|
||||
item: "",
|
||||
buyerType: "",
|
||||
allocationType: "",
|
||||
});
|
||||
setGuildsData([]);
|
||||
setStewardsData([]);
|
||||
};
|
||||
|
||||
// Calendar functions
|
||||
const handleDateSelect = (dateInfo) => {
|
||||
if (dateInfo && dateInfo.formattedDate) {
|
||||
setSelectedCalendarDate(dateInfo.formattedDate);
|
||||
|
||||
// Get the data for the selected date
|
||||
const data = calendarDayData[dateInfo.formattedDate];
|
||||
|
||||
if (data && data.originalDay) {
|
||||
setProductionDate(data.originalDay);
|
||||
}
|
||||
|
||||
// Get the amount for the selected date
|
||||
if (data && data.value1 !== undefined) {
|
||||
setSelectedDateAmount(data.value1);
|
||||
} else {
|
||||
setSelectedDateAmount(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const transformCalendarData = useCallback((dataArray) => {
|
||||
if (!Array.isArray(dataArray)) return {};
|
||||
|
||||
const transformedData = {};
|
||||
dataArray.forEach((item) => {
|
||||
if (item.day && item.amount !== undefined) {
|
||||
const persianDate = new PersianDate(new Date(item.day));
|
||||
const persianDateStr = persianDate.format("YYYY/MM/DD");
|
||||
transformedData[persianDateStr] = {
|
||||
value1: item.amount,
|
||||
originalDay: item.day,
|
||||
active: item.active === true,
|
||||
};
|
||||
}
|
||||
});
|
||||
return transformedData;
|
||||
}, []);
|
||||
|
||||
const updateCalendarData = useCallback(
|
||||
(dataArray) => {
|
||||
const transformed = transformCalendarData(dataArray);
|
||||
setCalendarDayData(transformed);
|
||||
},
|
||||
[transformCalendarData]
|
||||
);
|
||||
|
||||
// Fetch calendar data from API
|
||||
const fetchCalendarData = useCallback(async () => {
|
||||
try {
|
||||
const currentRole = getRoleFromUrl();
|
||||
console.log(getRoleFromUrl());
|
||||
let remainWeightEndpoint = "kill-house-remain-weight";
|
||||
if (currentRole === "Steward") {
|
||||
remainWeightEndpoint = "steward-remain-weight";
|
||||
} else if (currentRole === "Guilds") {
|
||||
remainWeightEndpoint = "guild-remain-weight";
|
||||
}
|
||||
|
||||
const response = await axios.get(`${remainWeightEndpoint}/`, {
|
||||
params: {
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") ||
|
||||
checkPathStartsWith("steward") ||
|
||||
checkPathStartsWith("senf")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
},
|
||||
});
|
||||
if (response.data) {
|
||||
setCalendarRawData({
|
||||
governmental: response.data.governmental || [],
|
||||
free: response.data.free || [],
|
||||
});
|
||||
const dataToShow =
|
||||
approvedStatus === "governmental"
|
||||
? response.data.governmental
|
||||
: response.data.free;
|
||||
updateCalendarData(dataToShow);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching calendar data:", error);
|
||||
}
|
||||
}, [approvedStatus, updateCalendarData, selectedSubUser]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCalendarData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editData && buyerCategory) {
|
||||
if (buyerCategory === "guilds") {
|
||||
dispatch(
|
||||
slaughterGetGuildsForAllocateService({
|
||||
free: true,
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setGuildsData(r.payload.data || []);
|
||||
});
|
||||
} else if (buyerCategory === "stewards") {
|
||||
dispatch(
|
||||
slaughterGetStewardsForAllocateService({
|
||||
free: true,
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setStewardsData(r.payload.data || []);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [buyerCategory, selectedSubUser?.key, editData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
calendarRawData.governmental.length > 0 ||
|
||||
calendarRawData.free.length > 0
|
||||
) {
|
||||
const dataToShow =
|
||||
approvedStatus === "governmental"
|
||||
? calendarRawData.governmental
|
||||
: calendarRawData.free;
|
||||
updateCalendarData(dataToShow);
|
||||
setSelectedCalendarDate(null);
|
||||
setProductionDate(null);
|
||||
setSelectedDateAmount(null);
|
||||
}
|
||||
}, [approvedStatus, calendarRawData, updateCalendarData]);
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, [selectedDateAmount]);
|
||||
|
||||
// Set segmentType to "own" for Guilds role
|
||||
useEffect(() => {
|
||||
const currentRole = getRoleFromUrl();
|
||||
if (currentRole === "Guilds" && !editData) {
|
||||
setSegmentType("own");
|
||||
formik.setFieldValue("segmentType", "own");
|
||||
}
|
||||
}, [editData]);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" justifyContent="center" gap={2}>
|
||||
<Grid container direction="column" justifyContent="center" gap={2} pt={2}>
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: SPACING.LARGE + 4,
|
||||
}}
|
||||
>
|
||||
{!editData && getRoleFromUrl() !== "Guilds" && (
|
||||
<LabelField label="قطعه بندی (کاربر)">
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={segmentType}
|
||||
onChange={handleSegmentTypeChange}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="own"
|
||||
control={<Radio />}
|
||||
label="قطعه بندی (کاربر)"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="free"
|
||||
control={<Radio />}
|
||||
label="تخصیص به قطعه بند"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)}
|
||||
|
||||
{!editData && segmentType === "free" && (
|
||||
<>
|
||||
<LabelField label="خریداران">
|
||||
<FormControl fullWidth>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="buyer-category-radio-group"
|
||||
name="buyerCategory"
|
||||
value={buyerCategory}
|
||||
onChange={handleBuyerCategoryChange}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="stewards"
|
||||
control={<Radio />}
|
||||
label="مباشرین"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="guilds"
|
||||
control={<Radio />}
|
||||
label="اصناف"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
|
||||
{buyerCategory && (
|
||||
<Grid xs={12} container>
|
||||
{(() => {
|
||||
const currentData =
|
||||
buyerCategory === "guilds" ? guildsData : stewardsData;
|
||||
const isEmpty = !currentData || currentData.length === 0;
|
||||
|
||||
if (isEmpty) {
|
||||
return (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
padding: 2,
|
||||
fontStyle: "italic",
|
||||
}}
|
||||
>
|
||||
{buyerCategory === "guilds"
|
||||
? "هیچ صنفی یافت نشد"
|
||||
: "هیچ مباشری یافت نشد"}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
disablePortal
|
||||
id="buyer-selection"
|
||||
options={
|
||||
buyerCategory === "guilds"
|
||||
? guildsData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i?.guildsName} ${i?.user?.fullname} (${i?.user?.mobile})`,
|
||||
};
|
||||
})
|
||||
: stewardsData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i?.name || ""} - ${
|
||||
i?.user?.fullname || ""
|
||||
} (${i?.user?.mobile || ""})`,
|
||||
};
|
||||
})
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
if (buyerCategory === "guilds") {
|
||||
setBuyerData({
|
||||
item: value?.data,
|
||||
key: value?.data?.key,
|
||||
allocationType: value?.data?.steward
|
||||
? "steward_steward"
|
||||
: "steward_guild",
|
||||
buyerType: value?.data?.steward
|
||||
? "Steward"
|
||||
: "Guild",
|
||||
});
|
||||
} else if (buyerCategory === "stewards") {
|
||||
setBuyerData({
|
||||
item: value?.data,
|
||||
key: value?.data?.key,
|
||||
allocationType: "steward_steward",
|
||||
buyerType: "Steward",
|
||||
});
|
||||
}
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
fullWidth
|
||||
{...params}
|
||||
label={
|
||||
buyerCategory === "guilds"
|
||||
? "انتخاب صنف"
|
||||
: "انتخاب مباشر"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
})()}
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* {!editData && (
|
||||
<LabelField label="نوع فروش">
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={selectedInventory}
|
||||
onChange={handleSellType}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
disabled
|
||||
value="governmental"
|
||||
control={<Radio />}
|
||||
label="قیمت دولتی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="free"
|
||||
control={<Radio />}
|
||||
label="قیمت آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)} */}
|
||||
{!editData && (
|
||||
<LabelField label="نوع انبار">
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={approvedStatus}
|
||||
onChange={handleApprovedPrice}
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="governmental"
|
||||
control={<Radio />}
|
||||
label="دولتی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="free"
|
||||
control={<Radio />}
|
||||
label="آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
)}
|
||||
{!editData && (
|
||||
<Grid
|
||||
style={{ width: "100%" }}
|
||||
container
|
||||
xs={12}
|
||||
lg={3}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
>
|
||||
<MonthlyDataCalendar
|
||||
onDateSelect={handleDateSelect}
|
||||
dayData={calendarDayData}
|
||||
selectedDate={selectedCalendarDate}
|
||||
label={`تاریخ تولید گوشت ${
|
||||
selectedDateAmount !== null
|
||||
? `(موجودی: ${selectedDateAmount?.toLocaleString()} کیلوگرم)`
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="weight"
|
||||
name="weight"
|
||||
label="وزن لاشه"
|
||||
type="number"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">کیلوگرم</InputAdornment>
|
||||
),
|
||||
}}
|
||||
value={formik.values.weight}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
(formik.touched.weight && Boolean(formik.errors.weight)) ||
|
||||
(selectedDateAmount && formik.values.weight > selectedDateAmount)
|
||||
}
|
||||
helperText={
|
||||
selectedDateAmount && formik.values.weight > selectedDateAmount
|
||||
? `وزن نمیتواند بیشتر از موجودی تاریخ تولید (${selectedDateAmount?.toLocaleString()} کیلوگرم) باشد!`
|
||||
: formik.touched.weight && formik.errors.weight
|
||||
}
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<Grid container spacing={2}>
|
||||
<Grid xs={6}>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={
|
||||
!editData &&
|
||||
(!productionDate ||
|
||||
(selectedDateAmount &&
|
||||
formik.values.weight > selectedDateAmount) ||
|
||||
(segmentType === "free" && !buyerData?.key))
|
||||
}
|
||||
>
|
||||
{editData ? "ویرایش" : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({ right: false, bottom: false, content: null })
|
||||
);
|
||||
}}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,141 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Grid,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
|
||||
export const AddAccessLevelModal = ({ device, onSuccess }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [selectedAccessLevel, setSelectedAccessLevel] = useState("");
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const accessLevelOptions = ["Steward", "KillHouse", "Guilds"];
|
||||
|
||||
const handleCloseModal = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedAccessLevel) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg: "لطفاً یک سطح دسترسی را انتخاب کنید.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device?.key && !device?.id) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg: "شناسه دستگاه یافت نشد. لطفاً دوباره تلاش کنید.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const payload = {
|
||||
pos_key: device?.key || device?.id,
|
||||
name: selectedAccessLevel,
|
||||
};
|
||||
|
||||
await axios.post("/pos-access-level/", payload);
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "success",
|
||||
msg: "سطح دسترسی با موفقیت افزوده شد.",
|
||||
});
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
handleCloseModal();
|
||||
} catch (error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg:
|
||||
error?.response?.data?.result ||
|
||||
error?.response?.data?.detail ||
|
||||
"افزودن سطح دسترسی با خطا مواجه شد.",
|
||||
});
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.SMALL}
|
||||
width="100%"
|
||||
alignItems="stretch"
|
||||
sx={{ minWidth: 300 }}
|
||||
>
|
||||
<Typography variant="body2">
|
||||
دستگاه انتخاب شده:{" "}
|
||||
{device?.serial ||
|
||||
device?.pos_unique_id ||
|
||||
device?.pos_id ||
|
||||
device?.posId ||
|
||||
"-"}
|
||||
</Typography>
|
||||
<FormControl fullWidth size="small">
|
||||
<InputLabel id="access-level-label">سطح دسترسی</InputLabel>
|
||||
<Select
|
||||
labelId="access-level-label"
|
||||
id="access-level-select"
|
||||
value={selectedAccessLevel}
|
||||
label="سطح دسترسی"
|
||||
onChange={(e) => setSelectedAccessLevel(e.target.value)}
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>انتخاب سطح دسترسی</em>
|
||||
</MenuItem>
|
||||
{accessLevelOptions.map((option) => (
|
||||
<MenuItem key={option} value={option}>
|
||||
{getFaUserRole(option)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleCloseModal}
|
||||
disabled={submitting}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSubmit}
|
||||
disabled={!selectedAccessLevel || submitting}
|
||||
>
|
||||
{submitting ? "در حال ثبت..." : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,354 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
MenuItem,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { LabelField } from "../../../../components/label-field/LabelField";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const AssignSubUserModal = ({ device, onSuccess }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [options, setOptions] = useState([]);
|
||||
const [selectedUser, setSelectedUser] = useState(null);
|
||||
const [selectedAccessLevel, setSelectedAccessLevel] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [fetchError, setFetchError] = useState("");
|
||||
const [userType, setUserType] = useState("delegate");
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const fetchUsers = async () => {
|
||||
setLoading(true);
|
||||
setFetchError("");
|
||||
setSelectedUser(null);
|
||||
setSelectedAccessLevel("");
|
||||
try {
|
||||
let response;
|
||||
const role = getRoleFromUrl();
|
||||
|
||||
if (userType === "delegate") {
|
||||
response = await axios.get(
|
||||
`/get_representatives/?role=${role}${
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
response = await axios.get(
|
||||
`/get_dispensers/?role=${role}${
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
if (isMounted) {
|
||||
const rawOptions = Array.isArray(response?.data?.results)
|
||||
? response?.data?.results
|
||||
: Array.isArray(response?.data)
|
||||
? response?.data
|
||||
: Array.isArray(response?.data?.data)
|
||||
? response?.data?.data
|
||||
: Array.isArray(response)
|
||||
? response
|
||||
: [];
|
||||
|
||||
// Normalize the data - both delegates and dispensers have the same structure
|
||||
const normalizedOptions = rawOptions.map((item) => {
|
||||
const fullname = item?.fullname || "-";
|
||||
const mobile = item?.mobile || "";
|
||||
const mobileLabel = mobile ? ` (${mobile})` : "";
|
||||
const label = `${fullname}${mobileLabel}`;
|
||||
|
||||
return {
|
||||
...item,
|
||||
label: label || "-",
|
||||
};
|
||||
});
|
||||
|
||||
setOptions(normalizedOptions);
|
||||
}
|
||||
} catch (error) {
|
||||
if (isMounted) {
|
||||
setFetchError("دریافت لیست کاربران با خطا مواجه شد.");
|
||||
console.error("Error fetching users:", error);
|
||||
}
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchUsers();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, [userType, selectedSubUser?.key]);
|
||||
|
||||
const handleCloseModal = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
};
|
||||
|
||||
const getSubAccessLevels = (user) => {
|
||||
if (!user) return [];
|
||||
|
||||
const subAccessLevels = [];
|
||||
|
||||
// Common excluded boolean fields that are not access levels
|
||||
const excludedFields = [
|
||||
"active",
|
||||
"trash",
|
||||
"deleted",
|
||||
"isActive",
|
||||
"isDeleted",
|
||||
];
|
||||
|
||||
// Get all boolean fields that represent sub access levels
|
||||
// These are fields in the object that are boolean and indicate sub access levels
|
||||
Object.keys(user).forEach((key) => {
|
||||
if (typeof user[key] === "boolean" && user[key] === true) {
|
||||
// Exclude common boolean fields that aren't access levels
|
||||
if (!excludedFields.includes(key.toLowerCase())) {
|
||||
// Use getFaUserRole to get the Persian translation
|
||||
const translatedLabel = getFaUserRole(key);
|
||||
subAccessLevels.push({
|
||||
key: key,
|
||||
label: translatedLabel || key,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return subAccessLevels;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedUser) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg: "لطفاً یک کاربر را انتخاب کنید.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device?.key && !device?.id) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg: "شناسه دستگاه یافت نشد. لطفاً دوباره تلاش کنید.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const payload = {
|
||||
key: device?.key || device?.id,
|
||||
recipient_type:
|
||||
userType === "delegate" ? "representative" : "dispenser",
|
||||
recipient_key: selectedUser?.key || selectedUser?.id,
|
||||
};
|
||||
|
||||
await axios.put("/user-pos-machine/0/", payload);
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "success",
|
||||
msg: "دستگاه با موفقیت به کاربر فرعی اختصاص داده شد.",
|
||||
});
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
handleCloseModal();
|
||||
} catch (error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg:
|
||||
error?.response?.data?.result ||
|
||||
error?.response?.data?.detail ||
|
||||
"اختصاص دستگاه با خطا مواجه شد.",
|
||||
});
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const selectedUserSubAccessLevels = selectedUser
|
||||
? getSubAccessLevels(selectedUser)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.SMALL}
|
||||
width="100%"
|
||||
alignItems="stretch"
|
||||
sx={{ minWidth: 400 }}
|
||||
>
|
||||
<Typography variant="body2">
|
||||
دستگاه انتخاب شده:{" "}
|
||||
{device?.serial ||
|
||||
device?.pos_unique_id ||
|
||||
device?.pos_id ||
|
||||
device?.posId ||
|
||||
"-"}
|
||||
</Typography>
|
||||
<LabelField label="نوع کاربر">
|
||||
<FormControl fullWidth>
|
||||
<RadioGroup
|
||||
row
|
||||
sx={{ gap: 2 }}
|
||||
value={userType}
|
||||
onChange={(e) => setUserType(e.target.value)}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="delegate"
|
||||
control={<Radio />}
|
||||
label="نمایندهها"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="dispenser"
|
||||
control={<Radio />}
|
||||
label="پخشکنندگان"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
{loading ? (
|
||||
<Grid container justifyContent="center">
|
||||
<CircularProgress size={24} />
|
||||
</Grid>
|
||||
) : (
|
||||
<Autocomplete
|
||||
disablePortal
|
||||
fullWidth
|
||||
size="small"
|
||||
options={options}
|
||||
value={selectedUser}
|
||||
loading={loading}
|
||||
loadingText="در حال دریافت..."
|
||||
noOptionsText="موردی یافت نشد."
|
||||
onChange={(event, value) => {
|
||||
setSelectedUser(value);
|
||||
setSelectedAccessLevel("");
|
||||
}}
|
||||
isOptionEqualToValue={(option, value) =>
|
||||
option?.key === value?.key || option?.id === value?.id
|
||||
}
|
||||
getOptionLabel={(option) => option?.label || ""}
|
||||
renderOption={(props, option) => {
|
||||
if (!option) return null;
|
||||
return (
|
||||
<li {...props} key={option?.key || option?.id}>
|
||||
<Grid container direction="column">
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
{option?.label || "-"}
|
||||
</Typography>
|
||||
{option?.city && (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{option.city}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
</li>
|
||||
);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="انتخاب کاربر"
|
||||
placeholder="نام یا شماره تماس"
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? (
|
||||
<CircularProgress color="inherit" size={16} />
|
||||
) : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{fetchError && (
|
||||
<Typography variant="caption" color="error">
|
||||
{fetchError}
|
||||
</Typography>
|
||||
)}
|
||||
{selectedUser && selectedUserSubAccessLevels.length > 0 && (
|
||||
<LabelField label="سطح دسترسی فرعی">
|
||||
<Select
|
||||
fullWidth
|
||||
size="small"
|
||||
value={selectedAccessLevel}
|
||||
onChange={(e) => setSelectedAccessLevel(e.target.value)}
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>انتخاب سطح دسترسی</em>
|
||||
</MenuItem>
|
||||
{selectedUserSubAccessLevels.map((level) => (
|
||||
<MenuItem key={level.key} value={level.key}>
|
||||
{level.label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</LabelField>
|
||||
)}
|
||||
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleCloseModal}
|
||||
disabled={submitting}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSubmit}
|
||||
disabled={!selectedUser || submitting || loading}
|
||||
>
|
||||
{submitting ? "در حال ثبت..." : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,266 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
IconButton,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Popover,
|
||||
Typography,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import PersonAddAlt1RoundedIcon from "@mui/icons-material/PersonAddAlt1Rounded";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import {
|
||||
LOADING_START,
|
||||
LOADING_END,
|
||||
CLOSE_MODAL,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
import { AssignSubUserModal } from "./AssignSubUserModal";
|
||||
import { AddAccessLevelModal } from "./AddAccessLevelModal";
|
||||
import { EditSubSectionsModal } from "./EditSubSectionsModal";
|
||||
|
||||
export const DeviceOperations = ({
|
||||
device,
|
||||
onSubUserAssigned,
|
||||
fetchApiData,
|
||||
page,
|
||||
}) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const handleOpen = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleAssignSubUser = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "اختصاص دستگاه به کاربر فرعی",
|
||||
width: "auto",
|
||||
content: (
|
||||
<AssignSubUserModal device={device} onSuccess={onSubUserAssigned} />
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleAddAccessLevel = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "افزودن سطح دسترسی",
|
||||
width: "auto",
|
||||
content: (
|
||||
<AddAccessLevelModal device={device} onSuccess={onSubUserAssigned} />
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleEditSubSections = (accessLevel) => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش زیربخشهای سطح دسترسی",
|
||||
width: "auto",
|
||||
content: (
|
||||
<EditSubSectionsModal
|
||||
accessLevel={accessLevel}
|
||||
device={device}
|
||||
onSuccess={() => fetchApiData(page)}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleDeleteAccessLevel = (accessLevel) => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "حذف سطح دسترسی",
|
||||
size: 320,
|
||||
content: (
|
||||
<Grid container spacing={2}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
mb={2}
|
||||
>
|
||||
<Typography variant="body2" color="default">
|
||||
آیا از حذف سطح دسترسی{" "}
|
||||
{getFaUserRole(accessLevel?.name) || accessLevel?.name} مطمئن
|
||||
هستید؟
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={async () => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
await axios.delete(
|
||||
`/pos-access-level/0/?key=${accessLevel?.key}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "success",
|
||||
msg: "سطح دسترسی با موفقیت حذف شد.",
|
||||
});
|
||||
if (fetchApiData) {
|
||||
fetchApiData(page);
|
||||
}
|
||||
} catch (error) {
|
||||
dispatch(LOADING_END());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg:
|
||||
error?.response?.data?.result ||
|
||||
error?.response?.data?.detail ||
|
||||
"حذف سطح دسترسی با خطا مواجه شد.",
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
onClick={() => dispatch(CLOSE_MODAL())}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "device-operations-popover" : undefined;
|
||||
|
||||
const accessLevels = Array.isArray(device?.accessLevels)
|
||||
? device.accessLevels.filter((level) => !level?.trash)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
color="primary"
|
||||
onClick={handleOpen}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
>
|
||||
<List sx={{ minWidth: 200, p: 0 }}>
|
||||
<ListItemButton onClick={handleAssignSubUser}>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "success.main" }}>
|
||||
<PersonAddAlt1RoundedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="اختصاص به کاربر"
|
||||
primaryTypographyProps={{
|
||||
sx: { color: "success.main", fontSize: "0.875rem" },
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton onClick={handleAddAccessLevel}>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "info.main" }}>
|
||||
<AddIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary="افزودن سطح دسترسی"
|
||||
primaryTypographyProps={{
|
||||
sx: { color: "info.main", fontSize: "0.875rem" },
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
{accessLevels.length > 0 && (
|
||||
<>
|
||||
<Box sx={{ pl: 1.5, py: 0.5, bgcolor: "action.hover" }}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
مدیریت سطح دسترسی:
|
||||
</Typography>
|
||||
</Box>
|
||||
{accessLevels.map((level, idx) => (
|
||||
<Box key={level?.key || idx} sx={{ pl: 1, pr: 0.5 }}>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Typography variant="body2" sx={{ py: 0.5, pl: 0.5 }}>
|
||||
{getFaUserRole(level?.name) || level?.name || "-"}
|
||||
</Typography>
|
||||
<Grid gap={0.5}>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={() => handleEditSubSections(level)}
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
color="error"
|
||||
onClick={() => handleDeleteAccessLevel(level)}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,202 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { LabelField } from "../../../../components/label-field/LabelField";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
|
||||
export const EditSubSectionsModal = ({ accessLevel, device, onSuccess }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [values, setValues] = useState({
|
||||
in_province_sale: accessLevel?.in_province_sale || false,
|
||||
out_province_sale: accessLevel?.out_province_sale || false,
|
||||
cutting: accessLevel?.cutting || false,
|
||||
freezing: accessLevel?.freezing || false,
|
||||
warehouse: accessLevel?.warehouse || false,
|
||||
retail: accessLevel?.retail || false,
|
||||
});
|
||||
|
||||
const handleCloseModal = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
};
|
||||
|
||||
const handleChange = (field) => (event) => {
|
||||
setValues((prev) => ({
|
||||
...prev,
|
||||
[field]: event.target.checked,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!accessLevel?.key) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg: "شناسه سطح دسترسی یافت نشد. لطفاً دوباره تلاش کنید.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const payload = {
|
||||
key: accessLevel.key,
|
||||
in_province_sale: values.in_province_sale,
|
||||
out_province_sale: values.out_province_sale,
|
||||
cutting: values.cutting,
|
||||
freezing: values.freezing,
|
||||
warehouse: values.warehouse,
|
||||
retail: values.retail,
|
||||
};
|
||||
|
||||
await axios.put("/pos-access-level/0/", payload);
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "success",
|
||||
msg: "زیربخشهای سطح دسترسی با موفقیت ویرایش شد.",
|
||||
});
|
||||
|
||||
if (onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
handleCloseModal();
|
||||
} catch (error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
severity: "error",
|
||||
msg:
|
||||
error?.response?.data?.result ||
|
||||
error?.response?.data?.detail ||
|
||||
"ویرایش زیربخشها با خطا مواجه شد.",
|
||||
});
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.SMALL}
|
||||
width="100%"
|
||||
alignItems="stretch"
|
||||
sx={{ minWidth: 400 }}
|
||||
>
|
||||
<Typography variant="body2">
|
||||
سطح دسترسی:{" "}
|
||||
{getFaUserRole(accessLevel?.name) || accessLevel?.name || "-"}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
دستگاه:{" "}
|
||||
{device?.serial ||
|
||||
device?.pos_unique_id ||
|
||||
device?.pos_id ||
|
||||
device?.posId ||
|
||||
"-"}
|
||||
</Typography>
|
||||
<LabelField label="تنظیمات زیربخشها">
|
||||
<Grid container p={1}>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.in_province_sale}
|
||||
onChange={handleChange("in_province_sale")}
|
||||
/>
|
||||
}
|
||||
label="فروش داخل استان"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.out_province_sale}
|
||||
onChange={handleChange("out_province_sale")}
|
||||
/>
|
||||
}
|
||||
label="فروش خارج استان"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.cutting}
|
||||
onChange={handleChange("cutting")}
|
||||
/>
|
||||
}
|
||||
label="قطعه بندی"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.freezing}
|
||||
onChange={handleChange("freezing")}
|
||||
/>
|
||||
}
|
||||
label="انجماد"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.warehouse}
|
||||
onChange={handleChange("warehouse")}
|
||||
/>
|
||||
}
|
||||
label="انبار"
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={values.retail}
|
||||
onChange={handleChange("retail")}
|
||||
/>
|
||||
}
|
||||
label="خردهفروشی"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</LabelField>
|
||||
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={handleCloseModal}
|
||||
disabled={submitting}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSubmit}
|
||||
disabled={submitting}
|
||||
>
|
||||
{submitting ? "در حال ثبت..." : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,284 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { BackButton } from "../../../../components/back-button/BackButton";
|
||||
import { Autocomplete, Button, TextField, Box, Chip } from "@mui/material";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
import { DeviceOperations } from "./DeviceOperations";
|
||||
import { Lock } from "@mui/icons-material";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
const GuildPspDevices = () => {
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(1);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [brands, setBrands] = useState([]);
|
||||
const [selectedBrand, setSelectedBrand] = useState("");
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const fetchBrands = async () => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`/get_all_pos_company/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`
|
||||
);
|
||||
setBrands(response.data);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching brands:", error);
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
};
|
||||
|
||||
const canDoAction = (item) => {
|
||||
if (item?.owner?.role?.includes("KillHouse")) {
|
||||
return getRoleFromUrl() === "KillHouse";
|
||||
}
|
||||
if (item?.owner?.includes("Steward")) {
|
||||
return getRoleFromUrl() === "Steward";
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
let url = `/user-pos-machine/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&page=${page}&page_size=${perPage}`;
|
||||
if (selectedBrand) {
|
||||
url += `&company=${selectedBrand}`;
|
||||
}
|
||||
const response = await axios.get(url);
|
||||
|
||||
setData(response.data?.results || []);
|
||||
setTotalRows(response.data?.count || 0);
|
||||
} catch (error) {
|
||||
console.error("Error fetching devices:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
const owner = item?.owner || {};
|
||||
const posCompany = item?.posCompany || {};
|
||||
|
||||
// Format recipient information
|
||||
const recipientDisplay = item?.recipient
|
||||
? `${item?.recipient?.firstName || ""} ${
|
||||
item?.recipient?.lastName || ""
|
||||
}`.trim() +
|
||||
(item?.recipient?.mobile
|
||||
? ` (${item?.recipient?.mobile} - ${
|
||||
item?.recipient?.agentType === "dispenser"
|
||||
? "توزیع کننده"
|
||||
: "نماینده"
|
||||
})`
|
||||
: "")
|
||||
: "-";
|
||||
|
||||
// Format access_levels to display as chips only (filter out trash items)
|
||||
const activeAccessLevels = Array.isArray(item?.accessLevels)
|
||||
? item.accessLevels.filter((level) => !level?.trash)
|
||||
: [];
|
||||
const accessLevelsDisplay =
|
||||
activeAccessLevels.length > 0 ? (
|
||||
<Grid container gap={0.5} flexWrap="wrap">
|
||||
{activeAccessLevels.map((level, idx) => (
|
||||
<Chip
|
||||
key={level?.key || idx}
|
||||
label={getFaUserRole(level?.name) || level?.name || "-"}
|
||||
size="small"
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
) : (
|
||||
"-"
|
||||
);
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
posCompany?.name || "-",
|
||||
item?.serial ?? "-",
|
||||
item?.receiverNumber ?? "-",
|
||||
item?.terminalNumber ?? "-",
|
||||
item?.password ?? "-",
|
||||
item?.posUniqueId || item?.posId || "-",
|
||||
owner?.fullname ? `${owner?.fullname} (${owner?.mobile ?? "-"})` : "-",
|
||||
owner?.nationalId || owner?.nationalCode || "-",
|
||||
item?.createDate ? formatJustDate(item?.createDate) : "-",
|
||||
accessLevelsDisplay,
|
||||
recipientDisplay,
|
||||
item?.active ? "فعال" : "غیرفعال",
|
||||
canDoAction(item) ? (
|
||||
<DeviceOperations
|
||||
key={item?.id || item?.key || `device-${i}`}
|
||||
device={item}
|
||||
/>
|
||||
) : (
|
||||
<Lock sx={{ fontSize: 20, mt: 1, color: "gray" }} />
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchBrands();
|
||||
}, [dispatch, selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(page);
|
||||
}, [selectedBrand, perPage, selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
fetchApiData(1);
|
||||
};
|
||||
|
||||
const tableTitle = (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
mb={1}
|
||||
padding={2}
|
||||
width="100%"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
width="100%"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
gap={SPACING.SMALL}
|
||||
xs={12}
|
||||
md="auto"
|
||||
>
|
||||
<Autocomplete
|
||||
size="small"
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="brand"
|
||||
options={
|
||||
Array.isArray(brands)
|
||||
? brands.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i?.name || ""}`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setSelectedBrand(value?.data?.key);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب برند دستگاه" />
|
||||
)}
|
||||
/>
|
||||
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
return (
|
||||
<Box display="flex" justifyContent="center">
|
||||
<Grid container xs={12} lg={10}>
|
||||
<BackButton />
|
||||
{tableTitle}
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"برند دستگاه",
|
||||
"شماره سریال",
|
||||
"شماره پذیرنده",
|
||||
"شماره ترمینال",
|
||||
"کلمه عبور امنیتی",
|
||||
"کلید پوز",
|
||||
"مالک",
|
||||
"کدملی",
|
||||
"تاریخ ایجاد",
|
||||
"سطوح دسترسی",
|
||||
"تحویل گیرنده",
|
||||
"فعال / غیرفعال",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="مدیریت دستگاه ها"
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default GuildPspDevices;
|
||||
20
src/features/guild/services/guilDeleteFreeBar.js
Normal file
20
src/features/guild/services/guilDeleteFreeBar.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildDeleteFreeBar = createAsyncThunk(
|
||||
"GUILD_DELETE_FREE_BAR",
|
||||
async (id, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.delete(
|
||||
"/steward_free_bar/0/?key=" + id
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildAllocatedStockOperationService = createAsyncThunk(
|
||||
"GUILD_ALLOCATED_STOCK_OPERATION_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put("steward-allocation/0/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
21
src/features/guild/services/guild-auth-code-submit.js
Normal file
21
src/features/guild/services/guild-auth-code-submit.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildAuthCodeSubmitService = createAsyncThunk(
|
||||
"GUILD_AUTH_CODE_SUBMIT_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put(
|
||||
"steward-guild-allocation/0/",
|
||||
d
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
20
src/features/guild/services/guild-delete-free-sale.js
Normal file
20
src/features/guild/services/guild-delete-free-sale.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildDeleteOutOfProvinceSell = createAsyncThunk(
|
||||
"GUILD_DELETE_OUT_OF_PROVINCE_SELL",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.delete(
|
||||
`steward_free_sale_bar/0/?key=${d}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/guild-edit-free-bar.js
Normal file
18
src/features/guild/services/guild-edit-free-bar.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildEditFreeBar = createAsyncThunk(
|
||||
"GUILD_EDIT_FREE_BAR",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put("steward_free_bar/0/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/guild-get-free-bars.js
Normal file
15
src/features/guild/services/guild-get-free-bars.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetFreeBars = createAsyncThunk(
|
||||
"GUILD_GET_FREE_BARS",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward_free_bar/", {
|
||||
params: { date: d.date },
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/guild-get-free-sale-bar.js
Normal file
15
src/features/guild/services/guild-get-free-sale-bar.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetFreeSaleBarService = createAsyncThunk(
|
||||
"GUILD_GET_FREE_SALE_BARS",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward_free_sale_bar/", {
|
||||
params: d,
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
19
src/features/guild/services/guild-get-guilds.js
Normal file
19
src/features/guild/services/guild-get-guilds.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetStewardsService = createAsyncThunk(
|
||||
"GUILD_GET_GUILDS_SERVICE",
|
||||
async (id, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get(
|
||||
"guilds/?other_guilds_for_steward=true/",
|
||||
{
|
||||
params: { role: getRoleFromUrl() },
|
||||
}
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/guild-get-inventory-allocated.js
Normal file
15
src/features/guild/services/guild-get-inventory-allocated.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetInventoryAllocatedService = createAsyncThunk(
|
||||
"GUILD_GET_INVENTORY_ALLOCATED_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward-allocation/", {
|
||||
params: { date: d.date, steward: true, role_key: d.role_key || "" },
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/guild-get-inventory-stock.js
Normal file
15
src/features/guild/services/guild-get-inventory-stock.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetInventoryStockService = createAsyncThunk(
|
||||
"GUILD_GET_INVENTORY_STOCK_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward_warehouse/", {
|
||||
params: { date: d.date, role_key: d.role_key || "" },
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
10
src/features/guild/services/guild-get-profile.js
Normal file
10
src/features/guild/services/guild-get-profile.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
|
||||
export const guildGetProfile = createAsyncThunk(
|
||||
"GUILD_GET_PROFILE",
|
||||
async () => {
|
||||
const { data, status } = await axios.get("guilds/0/?profile");
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/guild-get-stewards.js
Normal file
18
src/features/guild/services/guild-get-stewards.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetStewards = createAsyncThunk(
|
||||
"GUILD_GET_STEWARDS",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("guilds/", {
|
||||
params: {
|
||||
date: d.date,
|
||||
steward_sub_guilds: true,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
24
src/features/guild/services/guild-sales-info-dashboard.js
Normal file
24
src/features/guild/services/guild-sales-info-dashboard.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
|
||||
export const guildSalesInfoDashboardService = createAsyncThunk(
|
||||
"GUILD_SALES_INFO_DASHBOARD_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.get("guild-sales-info-dashboard/", {
|
||||
params: {
|
||||
role: d.role || getRoleFromUrl(),
|
||||
role_key: d.role_key || "",
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response?.data?.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/guild-submit-free-bar.js
Normal file
18
src/features/guild/services/guild-submit-free-bar.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildSubmitFreeBar = createAsyncThunk(
|
||||
"GUILD_SUBMIT_FREE_BAR",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.post("steward_free_bar/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/guild-update-allocated-stock.js
Normal file
18
src/features/guild/services/guild-update-allocated-stock.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildUpdateAllocatedStockService = createAsyncThunk(
|
||||
"GUILD_UPDATE_ALLOCATED_STOCK_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put("steward-allocation/0/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
17
src/features/guild/services/guildDeleteAllocatedService.js
Normal file
17
src/features/guild/services/guildDeleteAllocatedService.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildDeleteAllocatedService = createAsyncThunk(
|
||||
"GUILD_DELETE_ALLOCATED_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.delete("steward-guild-allocation/0/", {
|
||||
params: {
|
||||
steward_allocation_key: d.steward_allocation_key,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const GuildEditAllocateStewardService = createAsyncThunk(
|
||||
"GUILD_EDIT_ALLOCATE_STEWARD_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put(
|
||||
"steward-guild-allocation/0/",
|
||||
d
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
20
src/features/guild/services/guildGetAllocationData.js
Normal file
20
src/features/guild/services/guildGetAllocationData.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildGetAllocationData = createAsyncThunk(
|
||||
"GUILD_GET_ALLOCATION_DATA",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get(
|
||||
"steward-allocation/?steward_guilds_allocations=true/",
|
||||
{
|
||||
params: {
|
||||
date: d.date,
|
||||
},
|
||||
}
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const guildInventoryFinalSubmitService = createAsyncThunk(
|
||||
"GUILD_INVENTORY_FINAL_SUBMIT_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put(
|
||||
"steward-guild-allocation/0/",
|
||||
d
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/senf-get-allocation-dashboard.js
Normal file
15
src/features/guild/services/senf-get-allocation-dashboard.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const senfGetAllocationDashboardService = createAsyncThunk(
|
||||
"SENF_GET_ALLOCATION_DASHBOARD_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("guild-allocation-dashbord/", {
|
||||
params: d,
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
23
src/features/guild/services/senf-get-inventory-allocated.js
Normal file
23
src/features/guild/services/senf-get-inventory-allocated.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
|
||||
export const senfGetInventoryAllocatedService = createAsyncThunk(
|
||||
"SENF_GET_INVENTORY_ALLOCATED_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward-allocation/", {
|
||||
params: {
|
||||
date1: d.date1,
|
||||
date2: d.date2,
|
||||
type: d.type || "",
|
||||
role_key: d.role_key || "",
|
||||
role: getRoleFromUrl(),
|
||||
search: d.search,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
15
src/features/guild/services/senf-get-inventory-stock.js
Normal file
15
src/features/guild/services/senf-get-inventory-stock.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const senfGetInventoryStockService = createAsyncThunk(
|
||||
"SENF_GET_INVENTORY_STOCK_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("guilds_warehouse/", {
|
||||
params: d,
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/steward-edit-sell-out-buyer.js
Normal file
18
src/features/guild/services/steward-edit-sell-out-buyer.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stewardEditBuyerDataService = createAsyncThunk(
|
||||
"SLAUGHTER_EDIT_BUYER_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.put("steward_free_sale_bar/0/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
18
src/features/guild/services/steward-get-dashboard-service.js
Normal file
18
src/features/guild/services/steward-get-dashboard-service.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stawardGetSegmentDashboardService = createAsyncThunk(
|
||||
"STEWARD_GET_SEGMENT_DASHBOARD_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("segmentation-dashboard/", {
|
||||
params: {
|
||||
search: "filter",
|
||||
...d,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
19
src/features/guild/services/steward-get-out-dashboard.js
Normal file
19
src/features/guild/services/steward-get-out-dashboard.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
|
||||
export const stawardGetOutDashboardService = createAsyncThunk(
|
||||
"STEWARD-GET-OUT_DASHBOARD_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("steward_free_bar_dashboard", {
|
||||
params: {
|
||||
...d,
|
||||
role: getRoleFromUrl(),
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
17
src/features/guild/services/steward-get-segmant-role.js
Normal file
17
src/features/guild/services/steward-get-segmant-role.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stawardGetSegmantRoleService = createAsyncThunk(
|
||||
"STEWARD_GET_SEGMANT_ROLE_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("guilds/?&all=true", {
|
||||
params: {
|
||||
...d,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
19
src/features/guild/services/steward-get-sell-out-service.js
Normal file
19
src/features/guild/services/steward-get-sell-out-service.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
|
||||
export const stewardGetOutSellService = createAsyncThunk(
|
||||
"STEWRD_GET_OUT_SELL_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("roles-products", {
|
||||
params: {
|
||||
role: getRoleFromUrl(),
|
||||
...d,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stewardDeleteSegmentService = createAsyncThunk(
|
||||
"STEWARD_DELETE_SEGMENT",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.delete(
|
||||
`app-segmentation/0/?key=${d}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
|
||||
export const stewardEditSegmentService = createAsyncThunk(
|
||||
"STEWARD_EDIT_SEGMENT_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put(`app-segmentation/0/`, d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response?.data?.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,18 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const stewardSegmentSubmitService = createAsyncThunk(
|
||||
"STEWARD_SUBMIT_SEGMANT",
|
||||
async (d, { dispatch }) => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.post("app-segmentation/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stewardDeleteOutSellService = createAsyncThunk(
|
||||
"STEWARD_DELETE_OUT_OF_PROVINCE_SELL",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.delete(
|
||||
`steward_free_sale_bar/0/?key=${d}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e };
|
||||
}
|
||||
}
|
||||
);
|
||||
41
src/features/guild/services/steward-sell-out-get-buyers.js
Normal file
41
src/features/guild/services/steward-sell-out-get-buyers.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
|
||||
export const stewardSellOutGetBuyers = createAsyncThunk(
|
||||
"STEWARD_GET_BUYERS_SELL_OUT",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get("out-province-carcasses-buyer/", {
|
||||
params: {
|
||||
role: getRoleFromUrl(),
|
||||
role_key: d?.role_key || "",
|
||||
mobile: d?.mobile,
|
||||
},
|
||||
});
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
|
||||
export const stewatdSubmitBuyerDataService = createAsyncThunk(
|
||||
"STEWARD_SUBMIT_BUYER_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
try {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.post(
|
||||
"out-province-carcasses-buyer/",
|
||||
{
|
||||
...d,
|
||||
}
|
||||
);
|
||||
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,24 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
|
||||
|
||||
export const stewardSellOutGetDashboard = createAsyncThunk(
|
||||
"SLAUGHTRE_SELL_DASHBOARD",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
const { data, status } = await axios.get(
|
||||
`steward_free_sale_bar_dashboard`,
|
||||
{
|
||||
params: {
|
||||
date1: d.selectedDate1,
|
||||
date2: d.selectedDate2,
|
||||
role: getRoleFromUrl(),
|
||||
role_key: d.role_key || "",
|
||||
},
|
||||
}
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
}
|
||||
);
|
||||
17
src/features/guild/services/steward-sell-out-submit-sell.js
Normal file
17
src/features/guild/services/steward-sell-out-submit-sell.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
|
||||
export const stewardSellOuutSubmitSell = createAsyncThunk(
|
||||
"STEWARD_SELL_OUT_SUBMIT_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
try {
|
||||
const { data, status } = await axios.post(`steward_free_sale_bar/`, d);
|
||||
dispatch(LOADING_START());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response.data.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,50 @@
|
||||
import { createAsyncThunk } from "@reduxjs/toolkit";
|
||||
import axios from "axios";
|
||||
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
|
||||
|
||||
export const stewardSubmitFreeBarService = createAsyncThunk(
|
||||
"STEWARD_FREE_BAR_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.post("steward_free_bar/", d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response?.data?.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const stewardEditFreeBarService = createAsyncThunk(
|
||||
"STEWARD_EDIT_FREE_BAR_SERVICE",
|
||||
async (d, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.put(`steward_free_bar/0/`, d);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response?.data?.result };
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const stewardDeleteFreeBarService = createAsyncThunk(
|
||||
"STEWARD_DELETE_FREE_BAR_SERVICE",
|
||||
async (key, { dispatch }) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const { data, status } = await axios.delete(
|
||||
`steward_free_bar/0/?key=${key}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
return { data, status };
|
||||
} catch (e) {
|
||||
dispatch(LOADING_END());
|
||||
return { error: e.response?.data?.result || "خطا در حذف اطلاعات" };
|
||||
}
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user