push rasad front on new repo
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { ImageUpload } from "../../../../components/image-upload/ImageUpload";
|
||||
import { fixBase64 } from "../../../../utils/toBase64";
|
||||
import { Typography } from "@mui/material";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { killHouseAssignmentInformationAggregateLoadService } from "../../services/killhouse-assignment-information-aggregate-load";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { resizeImage } from "../../../../utils/resizeImage";
|
||||
|
||||
export const AggregateUploadDoc = ({ isSingular, item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [profileImages, setProfileImages] = useState([]);
|
||||
const [profileImg, setProfileImg] = useState();
|
||||
const { slaughterGetAggregateLoadInformation } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
|
||||
const factorPaymentHandler = (imageList, addUpdateIndex) => {
|
||||
if (imageList[0]) {
|
||||
const file = imageList[0]?.file;
|
||||
resizeImage(file, (resizedDataUrl) => {
|
||||
const optimizedBase64 = fixBase64(resizedDataUrl);
|
||||
setProfileImg(optimizedBase64);
|
||||
});
|
||||
}
|
||||
setProfileImages(imageList);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (profileImg) {
|
||||
if (isSingular) {
|
||||
dispatch(
|
||||
killHouseAssignmentInformationAggregateLoadService({
|
||||
image: profileImg,
|
||||
bar_key: item.key,
|
||||
role: getRoleFromUrl(),
|
||||
})
|
||||
).then((r) => {
|
||||
setProfileImg(null);
|
||||
setProfileImages([]);
|
||||
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",
|
||||
});
|
||||
if (
|
||||
item?.assingmentInformation?.realQuantity &&
|
||||
item?.assingmentInformation?.carWeightWithLoadImage
|
||||
) {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "بار به تب مدیریت بارها منتقل شد.",
|
||||
})
|
||||
);
|
||||
}
|
||||
updateTable(1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
killHouseAssignmentInformationAggregateLoadService({
|
||||
image: profileImg,
|
||||
bar_keys: slaughterGetAggregateLoadInformation?.map(
|
||||
(item) => item.key
|
||||
),
|
||||
role: getRoleFromUrl(),
|
||||
})
|
||||
).then((r) => {
|
||||
setProfileImg(null);
|
||||
setProfileImages([]);
|
||||
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",
|
||||
});
|
||||
updateTable(1);
|
||||
if (
|
||||
item?.assingmentInformation?.realQuantity &&
|
||||
item?.assingmentInformation?.carWeightWithLoadImage
|
||||
) {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "بار به تب مدیریت بارها منتقل شد.",
|
||||
// content: "",
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [profileImg, profileImages]);
|
||||
|
||||
return (
|
||||
<Grid width="100%">
|
||||
{!isSingular && (
|
||||
<Grid container gap={SPACING.TINY} mb={SPACING.SMALL}>
|
||||
<Typography color={"error"}>نکته:</Typography>
|
||||
<Typography>
|
||||
این سند برای تمامی بارهایی که فاقد سند هستند ثبت خواهد شد.
|
||||
</Typography>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid mt={SPACING.SMALL}>
|
||||
<ImageUpload
|
||||
onChange={factorPaymentHandler}
|
||||
images={profileImages}
|
||||
maxNumber={1}
|
||||
showImages={false}
|
||||
title={
|
||||
item?.assingmentInformation?.carWeightWithLoadImage
|
||||
? "ویرایش"
|
||||
: "ثبت"
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { verificationDirectBuyingCode } from "../../services/edit-verification-direct-buying-code";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
Grid,
|
||||
IconButton,
|
||||
InputAdornment,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useFormik } from "formik";
|
||||
|
||||
function EditVerificationDirectBuy({
|
||||
inputDirectBuyingCode,
|
||||
kill_request_key,
|
||||
updateTable,
|
||||
}) {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [isEditMode, setIsEditMode] = useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
input_direct_buying_code: inputDirectBuyingCode,
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
input_direct_buying_code: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!")
|
||||
.matches(/^[0-9]+$/, "فقط عدد وارد کنید"),
|
||||
// .min(5, "کد باید حداقل ۵ کاراکتر باشد")
|
||||
// .max(20, "کد نمیتواند بیشتر از ۲۰ کاراکتر باشد"),
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
verificationDirectBuyingCode({
|
||||
kill_request_key: kill_request_key,
|
||||
input_direct_buying_code: values.input_direct_buying_code,
|
||||
role: "KillHouse",
|
||||
})
|
||||
).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",
|
||||
});
|
||||
updateTable();
|
||||
}
|
||||
setIsEditMode(false);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.setValues({ input_direct_buying_code: inputDirectBuyingCode });
|
||||
setIsEditMode(false);
|
||||
}, [inputDirectBuyingCode]);
|
||||
|
||||
return isEditMode ? (
|
||||
<Grid container minWidth="130px">
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<TextField
|
||||
variant="standard"
|
||||
name="input_direct_buying_code"
|
||||
value={formik.values.input_direct_buying_code}
|
||||
size="small"
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.input_direct_buying_code &&
|
||||
Boolean(formik.errors.input_direct_buying_code)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.input_direct_buying_code &&
|
||||
formik.errors.input_direct_buying_code
|
||||
}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<Typography
|
||||
style={{ cursor: "pointer" }}
|
||||
color="primary"
|
||||
fontWeight="bold"
|
||||
variant="caption"
|
||||
onClick={formik.handleSubmit}
|
||||
>
|
||||
ثبت
|
||||
</Typography>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</form>
|
||||
</Grid>
|
||||
) : (
|
||||
<Grid container alignItems="center">
|
||||
<Typography variant="caption">{inputDirectBuyingCode}</Typography>
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
setIsEditMode(!isEditMode);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditVerificationDirectBuy;
|
||||
@@ -0,0 +1,732 @@
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { useContext, useEffect, useState, useMemo, useCallback } from "react";
|
||||
import moment from "moment";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { AggregateUploadDoc } from "../aggregate-upload-doc/aggregate-upload-doc";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { useFormik } from "formik";
|
||||
import { salughterAggregateQuantityService } from "../../services/salughter-aggregate-quantity";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { VetFarmEditTrafficCode } from "../../../vet-farm/components/vet-farm-edit-traffic-code/VetFarmEditTrafficCode";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { slaughterEnterLoadInformationGetDashboard } from "../../services/slaughter-enter-load-information-get-dashboard";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
|
||||
import { provincePolicyGetWeightRange } from "../../../province/services/province-policy-get-weight-range";
|
||||
import { isValidIndexWeight } from "../../../../utils/isValidIndexWeight";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
// Constants
|
||||
const ROLES = {
|
||||
PROVINCE_OPERATOR: "ProvinceOperator",
|
||||
SUPER_ADMIN: "SuperAdmin",
|
||||
ADMIN_X: "AdminX",
|
||||
SUPPORTER: "Supporter",
|
||||
VET_SUPERVISOR: "VetSupervisor",
|
||||
VET_FARM: "VetFarm",
|
||||
CITY_VET: "CityVet",
|
||||
};
|
||||
|
||||
const KILL_TYPES = {
|
||||
FREEZING: "انجماد",
|
||||
EXPORT: "صادرات",
|
||||
NORMAL: "عادی",
|
||||
};
|
||||
|
||||
const DEFAULT_PER_PAGE = 10;
|
||||
const DEFAULT_PAGE = 1;
|
||||
|
||||
// Helper functions
|
||||
const formatDate = (date) => {
|
||||
if (!date) return "-";
|
||||
return format(new Date(date), "yyyy/MM/dd");
|
||||
};
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
return value ? `${value.toLocaleString()} ﷼` : "-";
|
||||
};
|
||||
|
||||
const formatNumber = (value) => {
|
||||
return value ? value.toLocaleString() : "-";
|
||||
};
|
||||
|
||||
const formatUserInfo = (name, mobile) => {
|
||||
return name && mobile ? `${name} (${mobile})` : "-";
|
||||
};
|
||||
|
||||
const getKillType = (item) => {
|
||||
if (item?.poultryRequest?.freezing) return KILL_TYPES.FREEZING;
|
||||
if (item?.poultryRequest?.export) return KILL_TYPES.EXPORT;
|
||||
return KILL_TYPES.NORMAL;
|
||||
};
|
||||
|
||||
const buildApiUrl = (params) => {
|
||||
const { textValue, role, date1, date2, page, perPage, roleKey } = params;
|
||||
const baseUrl = "kill_house_request_aggregate_load/";
|
||||
const queryParams = new URLSearchParams({
|
||||
check: "",
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
role: role || "",
|
||||
date1: date1 || "",
|
||||
date2: date2 || "",
|
||||
page: page || DEFAULT_PAGE,
|
||||
page_size: perPage || DEFAULT_PER_PAGE,
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseUrl}?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const buildExcelUrl = (params) => {
|
||||
const { baseURL, date1, date2, role, roleKey, userKey, textValue } = params;
|
||||
const queryParams = new URLSearchParams({
|
||||
start: date1 || "",
|
||||
end: date2 || "",
|
||||
role: role || "",
|
||||
state: "bar_pending",
|
||||
key: userKey || "",
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseURL}bar_excel/?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const isTrafficCodeEditable = (role, item) => {
|
||||
const adminRoles = [
|
||||
ROLES.PROVINCE_OPERATOR,
|
||||
ROLES.SUPER_ADMIN,
|
||||
ROLES.ADMIN_X,
|
||||
ROLES.SUPPORTER,
|
||||
ROLES.VET_SUPERVISOR,
|
||||
];
|
||||
|
||||
if (adminRoles.includes(role)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const vetRoles = [ROLES.VET_FARM, ROLES.CITY_VET];
|
||||
return (
|
||||
item.trash !== true &&
|
||||
item.assignmentStateArchive === "pending" &&
|
||||
!item?.clearanceCode &&
|
||||
vetRoles.includes(role)
|
||||
);
|
||||
};
|
||||
|
||||
export const EnterAggregateLoadInformation = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
// Redux
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// State
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(DEFAULT_PER_PAGE);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(DEFAULT_PAGE);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
|
||||
// Memoized values
|
||||
const currentRole = useMemo(() => getRoleFromUrl(), []);
|
||||
const roleKey = useMemo(
|
||||
() => (checkPathStartsWith("slaughter") ? selectedSubUser?.key || "" : ""),
|
||||
[selectedSubUser?.key]
|
||||
);
|
||||
|
||||
// Initialize dates
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, [setSelectedDate1, setSelectedDate2]);
|
||||
|
||||
// Fetch API data
|
||||
const fetchApiData = useCallback(
|
||||
async (pageNumber = page) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const url = buildApiUrl({
|
||||
textValue,
|
||||
role: currentRole,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
page: pageNumber,
|
||||
perPage,
|
||||
roleKey,
|
||||
});
|
||||
|
||||
const response = await axios.get(url);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
currentRole,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
roleKey,
|
||||
page,
|
||||
dispatch,
|
||||
]
|
||||
);
|
||||
|
||||
// Fetch dashboard data
|
||||
const fetchDashboardData = useCallback(() => {
|
||||
dispatch(
|
||||
slaughterEnterLoadInformationGetDashboard({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
text: textValue,
|
||||
role_key: roleKey,
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}, [selectedDate1, selectedDate2, textValue, roleKey, dispatch]);
|
||||
|
||||
// Handlers
|
||||
const handlePageChange = (newPage) => {
|
||||
fetchApiData(newPage);
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (newPerRows) => {
|
||||
setPerPage(newPerRows);
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
await fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleDateChange1 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate1(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDateChange2 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate2(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenModal = useCallback(
|
||||
(item) => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت اطلاعات بار",
|
||||
content: <Operation item={item} fetchApiData={fetchApiData} />,
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch, fetchApiData]
|
||||
);
|
||||
|
||||
// Initial data fetch
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Refetch when filters change
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedDate1, selectedDate2, perPage, roleKey]);
|
||||
|
||||
// Transform data to table format
|
||||
useEffect(() => {
|
||||
const transformedData = data?.map((item, i) => {
|
||||
const rowNumber =
|
||||
page === DEFAULT_PAGE ? i + 1 : i + perPage * (page - 1) + 1;
|
||||
const hasAssignmentInfo = !!item?.assignmentInfo?.realQuantity;
|
||||
|
||||
return [
|
||||
rowNumber,
|
||||
hasAssignmentInfo ? (
|
||||
<Grid container direction="column" key={item.key}>
|
||||
<Grid>{formatNumber(item?.assignmentInfo?.realQuantity)} قطعه</Grid>
|
||||
<Grid>{formatNumber(item?.assignmentInfo?.netWeight)} کیلوگرم</Grid>
|
||||
<Tooltip title="ویرایش اطلاعات بار" placement="top">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => handleOpenModal(item)}
|
||||
size="small"
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
) : (
|
||||
<Tooltip key={item.key} title="ثبت اطلاعات بار" placement="top">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => handleOpenModal(item)}
|
||||
size="small"
|
||||
>
|
||||
<AddCircleOutlineIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
item?.assingmentInformation?.carWeightWithLoadImage ? (
|
||||
<Grid key={item.key}>
|
||||
<ShowImage
|
||||
src={item?.assingmentInformation?.carWeightWithLoadImage}
|
||||
/>
|
||||
<AggregateUploadDoc
|
||||
isSingular
|
||||
item={item}
|
||||
updateTable={fetchApiData}
|
||||
/>
|
||||
</Grid>
|
||||
) : (
|
||||
<AggregateUploadDoc
|
||||
key={item.key}
|
||||
isSingular
|
||||
item={item}
|
||||
updateTable={fetchApiData}
|
||||
/>
|
||||
),
|
||||
<ShowImage
|
||||
key={`empty-${i}`}
|
||||
src={item?.assignmentInfo?.imageWithoutBar}
|
||||
/>,
|
||||
<ShowImage
|
||||
key={`full-${i}`}
|
||||
src={item?.assignmentInfo?.imageWithBar}
|
||||
/>,
|
||||
<Typography
|
||||
key={`barcode-${i}`}
|
||||
style={{ fontSize: "13px", color: item?.trash ? "red" : "black" }}
|
||||
>
|
||||
{item.barCode}
|
||||
</Typography>,
|
||||
<VetFarmEditTrafficCode
|
||||
key={`traffic-${i}`}
|
||||
updateTable={fetchApiData}
|
||||
killHouseRequestKey={item.key}
|
||||
trafficCode={item?.trafficCode}
|
||||
isEditable={isTrafficCodeEditable(currentRole, item)}
|
||||
/>,
|
||||
formatCurrency(item?.amount),
|
||||
formatDate(item?.poultryRequest?.sendDate),
|
||||
formatUserInfo(
|
||||
item.killhouseUser?.name,
|
||||
item.killhouseUser?.killHouseOperator?.user?.mobile
|
||||
),
|
||||
item?.killer
|
||||
? formatUserInfo(
|
||||
item.killer?.name,
|
||||
item.killer?.killHouseOperator?.user?.mobile
|
||||
)
|
||||
: "-",
|
||||
formatUserInfo(
|
||||
item.poultryRequest?.poultry?.unitName,
|
||||
item.poultryRequest?.poultry?.user?.mobile
|
||||
),
|
||||
item?.poultryRequest?.age || "-",
|
||||
formatNumber(item.quantity),
|
||||
formatNumber(item?.weightInfo?.weight),
|
||||
formatCurrency(item?.poultryRequest?.amount),
|
||||
formatCurrency(item?.weightInfo?.killHousePrice),
|
||||
`${item.addCar?.driver?.typeCar || ""} ${
|
||||
item.addCar?.driver?.pelak || ""
|
||||
}`.trim() || "-",
|
||||
formatUserInfo(
|
||||
item.addCar?.driver?.driverName,
|
||||
item.addCar?.driver?.driverMobile
|
||||
),
|
||||
formatNumber(item.vetAcceptedRealQuantity),
|
||||
formatNumber(item.vetAcceptedRealWeight),
|
||||
item?.poultryRequest?.orderCode || "-",
|
||||
item?.finalBarState || "-",
|
||||
getKillType(item),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(transformedData || []);
|
||||
}, [data, page, perPage, currentRole, handleOpenModal, fetchApiData]);
|
||||
|
||||
// Table columns
|
||||
const dashboardColumns = [
|
||||
"تعداد بار",
|
||||
"مجموع تعداد اولیه",
|
||||
"مجموع وزن اولیه (کیلوگرم)",
|
||||
"مجموع تعداد تحویلی دامپزشک",
|
||||
"مجموع وزن تحویلی دامپزشک (کیلوگرم)",
|
||||
];
|
||||
|
||||
const tableColumns = [
|
||||
"ردیف",
|
||||
"تعداد/وزن خالص",
|
||||
"سند",
|
||||
"بارنامه خالی",
|
||||
"بارنامه پر",
|
||||
"کدبار",
|
||||
"کد بهداشتی حمل و نقل",
|
||||
"قیمت مرغ زندهی بار",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"کشتارکن اختصاصی",
|
||||
"مرغدار",
|
||||
"سن مرغ",
|
||||
"تعداد اولیه",
|
||||
"وزن اولیه بار (کیلوگرم)",
|
||||
"قیمت مرغدار",
|
||||
"قیمت کشتارگاه",
|
||||
"ماشین",
|
||||
"راننده",
|
||||
"تحویلی دامپزشک (قطعه)",
|
||||
"وزن تحویلی دامپزشک (کیلوگرم)",
|
||||
"کدسفارش کشتار",
|
||||
"وضعیت بار",
|
||||
"نوع کشتار",
|
||||
];
|
||||
|
||||
const dashboardRow = [
|
||||
formatNumber(dashboardData?.lenKillHouseRequest),
|
||||
formatNumber(dashboardData?.firstQuantity),
|
||||
formatNumber(dashboardData?.firstWeight),
|
||||
formatNumber(dashboardData?.vetAcceptedRealQuantity),
|
||||
formatNumber(dashboardData?.vetAcceptedRealWeight),
|
||||
];
|
||||
|
||||
const excelUrl = buildExcelUrl({
|
||||
baseURL: axios.defaults.baseURL,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
role: currentRole,
|
||||
roleKey,
|
||||
userKey,
|
||||
textValue,
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="center">
|
||||
<Grid
|
||||
container
|
||||
alignItems="start"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={handleDateChange1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={handleDateChange2}
|
||||
/>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
value={textValue}
|
||||
/>
|
||||
<Button type="submit" endIcon={<RiSearchLine />}>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
{!!data?.length && (
|
||||
<Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a href={excelUrl} rel="noreferrer">
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={dashboardColumns}
|
||||
data={[dashboardRow]}
|
||||
title="خلاصه اطلاعات"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={tableColumns}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="وارد کردن اطلاعات بار"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
const Operation = ({ item, fetchApiData }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const { weightRange } = useSelector((state) => state.provinceSlice);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const currentRole = useMemo(() => getRoleFromUrl(), []);
|
||||
|
||||
// Fetch weight range on mount
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
provincePolicyGetWeightRange({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
// Validation helpers
|
||||
const validateNumeric = (value) => /^\d+$/.test(value);
|
||||
|
||||
const checkVolumeLimits = (quantity) => {
|
||||
const { maximumLoadVolumeReduction, maximumLoadVolumeIncrease } =
|
||||
item?.killhouseUser || {};
|
||||
const acceptedQuantity = item?.acceptedRealQuantity || 0;
|
||||
|
||||
if (
|
||||
maximumLoadVolumeReduction !== 0 &&
|
||||
quantity < acceptedQuantity * (1 - maximumLoadVolumeReduction / 100)
|
||||
) {
|
||||
return {
|
||||
isValid: false,
|
||||
message:
|
||||
"حجم وارد شده با مجوز حداکثر افزایش/کاهش ورود اطلاعات بار مطابقت ندارد!",
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
maximumLoadVolumeIncrease !== 0 &&
|
||||
quantity > acceptedQuantity * (1 + maximumLoadVolumeIncrease / 100)
|
||||
) {
|
||||
return {
|
||||
isValid: false,
|
||||
message:
|
||||
"حجم وارد شده با مجوز حداکثر افزایش/کاهش ورود اطلاعات بار مطابقت ندارد!",
|
||||
};
|
||||
}
|
||||
|
||||
return { isValid: true };
|
||||
};
|
||||
|
||||
const checkWeightValidation = (weight, quantity) => {
|
||||
const adminRoles = [ROLES.SUPER_ADMIN, ROLES.ADMIN_X];
|
||||
if (adminRoles.includes(currentRole)) {
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
const averageWeight = parseInt(weight) / parseInt(quantity);
|
||||
if (
|
||||
!isValidIndexWeight(weightRange, item?.poultryRequest?.age, averageWeight)
|
||||
) {
|
||||
return {
|
||||
isValid: false,
|
||||
message:
|
||||
"میانگین وزنی با احراز سنی مطابقت ندارد. لطفا با اتحادیه تماس بگیرید.",
|
||||
};
|
||||
}
|
||||
|
||||
return { isValid: true };
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
quantity: "",
|
||||
weight: "",
|
||||
},
|
||||
onSubmit: async (values) => {
|
||||
// Validate volume limits
|
||||
const volumeCheck = checkVolumeLimits(parseInt(values.quantity));
|
||||
if (!volumeCheck.isValid) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: volumeCheck.message,
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate weight
|
||||
const weightCheck = checkWeightValidation(values.weight, values.quantity);
|
||||
if (!weightCheck.isValid) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: weightCheck.message,
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Submit data
|
||||
const result = await dispatch(
|
||||
salughterAggregateQuantityService({
|
||||
kill_house_request_key: item.key,
|
||||
role: currentRole,
|
||||
net_weight: values.weight,
|
||||
exploited_carcass: 0,
|
||||
real_quantity: values.quantity,
|
||||
})
|
||||
);
|
||||
|
||||
if (result.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: result.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
}
|
||||
},
|
||||
validate: (values) => {
|
||||
const errors = {};
|
||||
if (!validateNumeric(values.weight)) {
|
||||
errors.weight = "لطفا عدد وارد کنید";
|
||||
}
|
||||
if (!validateNumeric(values.quantity)) {
|
||||
errors.quantity = "لطفا عدد وارد کنید";
|
||||
}
|
||||
return errors;
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<TextField
|
||||
label="وزن خالص (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="text"
|
||||
name="weight"
|
||||
id="weight"
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
value={formik.values.weight}
|
||||
error={formik.touched.weight && Boolean(formik.errors.weight)}
|
||||
helperText={formik.touched.weight && formik.errors.weight}
|
||||
/>
|
||||
<TextField
|
||||
label="تعداد واقعی (قطعه)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="text"
|
||||
name="quantity"
|
||||
id="quantity"
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
value={formik.values.quantity}
|
||||
error={formik.touched.quantity && Boolean(formik.errors.quantity)}
|
||||
helperText={formik.touched.quantity && formik.errors.quantity}
|
||||
/>
|
||||
|
||||
<Button type="submit" fullWidth variant="contained">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import React, { useContext } from "react";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterEditFreeBuyService } from "../../services/slaughter-edit-free-buy";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
|
||||
export const EnterAuthCodeDirectBuy = ({ item, updateTable }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
textFieldValue: "", // Initial value for your text field
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
textFieldValue: Yup.string().required("این فیلد الزامی است"), // Validation schema for the text field
|
||||
}),
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
slaughterEditFreeBuyService({
|
||||
role: getRoleFromUrl(),
|
||||
kill_request_key: item.key,
|
||||
input_direct_buying_code: values.textFieldValue,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r?.payload?.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r?.payload?.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container gap={SPACING.TINY}>
|
||||
<TextField
|
||||
fullWidth
|
||||
id="textFieldValue"
|
||||
name="textFieldValue"
|
||||
label="کداحراز"
|
||||
variant="outlined"
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
value={formik.values.textFieldValue}
|
||||
error={
|
||||
formik.touched.textFieldValue &&
|
||||
Boolean(formik.errors.textFieldValue)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.textFieldValue && formik.errors.textFieldValue
|
||||
}
|
||||
/>
|
||||
|
||||
<Button fullWidth type="submit" variant="contained" color="primary">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,445 @@
|
||||
import { useContext, useEffect, useState, useMemo, useCallback } from "react";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { slaughterGetPermissionToVetService } from "../../services/slaughter-get-premisson-to-vet";
|
||||
import { Box, Switch, TextField, Typography, Button } from "@mui/material";
|
||||
import moment from "moment";
|
||||
import { slaughterPermissionToVetService } from "../../services/slaughter-premisson-to-vet";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { format } from "date-fns-jalali";
|
||||
import axios from "axios";
|
||||
import { VetFarmEditTrafficCode } from "../../../vet-farm/components/vet-farm-edit-traffic-code/VetFarmEditTrafficCode";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { slaughterEnterLoadInformationGetDashboard } from "../../services/slaughter-enter-load-information-get-dashboard";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { SlaughterEnterInformationOperation } from "../slaughter-enter-information-operation/SlaughterEnterInformationOperation";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
// Constants
|
||||
const ROLES = {
|
||||
KILL_HOUSE: "KillHouse",
|
||||
PROVINCE_OPERATOR: "ProvinceOperator",
|
||||
SUPER_ADMIN: "SuperAdmin",
|
||||
VET_SUPERVISOR: "VetSupervisor",
|
||||
VET_FARM: "VetFarm",
|
||||
CITY_VET: "CityVet",
|
||||
};
|
||||
|
||||
const DEFAULT_PER_PAGE = 10;
|
||||
const DEFAULT_PAGE = 1;
|
||||
|
||||
// Helper functions
|
||||
const formatDate = (date) => {
|
||||
if (!date) return "-";
|
||||
return format(new Date(date), "yyyy/MM/dd");
|
||||
};
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
return value ? `${value.toLocaleString()} ﷼` : "-";
|
||||
};
|
||||
|
||||
const formatNumber = (value) => {
|
||||
return value ? value.toLocaleString() : "-";
|
||||
};
|
||||
|
||||
const formatUserInfo = (name, mobile) => {
|
||||
return name && mobile ? `${name} (${mobile})` : "-";
|
||||
};
|
||||
|
||||
const buildApiUrl = (params) => {
|
||||
const { textValue, role, date1, date2, page, perPage, roleKey } = params;
|
||||
const baseUrl = "kill_house_request_complete_information/";
|
||||
const queryParams = new URLSearchParams({
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
role: role || "",
|
||||
date1: date1 || "",
|
||||
date2: date2 || "",
|
||||
page: page || DEFAULT_PAGE,
|
||||
page_size: perPage || DEFAULT_PER_PAGE,
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseUrl}?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const isTrafficCodeEditable = (role, item) => {
|
||||
const adminRoles = [
|
||||
ROLES.PROVINCE_OPERATOR,
|
||||
ROLES.SUPER_ADMIN,
|
||||
ROLES.VET_SUPERVISOR,
|
||||
];
|
||||
|
||||
if (adminRoles.includes(role)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const vetRoles = [ROLES.VET_FARM, ROLES.CITY_VET];
|
||||
return (
|
||||
item.trash !== true &&
|
||||
item.assignmentStateArchive === "pending" &&
|
||||
!item?.clearanceCode &&
|
||||
vetRoles.includes(role)
|
||||
);
|
||||
};
|
||||
|
||||
export const EnterLoadInformation = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
// State
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(DEFAULT_PER_PAGE);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(DEFAULT_PAGE);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
|
||||
// Redux
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Memoized values
|
||||
const currentRole = useMemo(() => getRoleFromUrl(), []);
|
||||
const isKillHouse = useMemo(
|
||||
() => currentRole === ROLES.KILL_HOUSE,
|
||||
[currentRole]
|
||||
);
|
||||
const roleKey = useMemo(
|
||||
() => (checkPathStartsWith("slaughter") ? selectedSubUser?.key || "" : ""),
|
||||
[selectedSubUser?.key]
|
||||
);
|
||||
|
||||
// Initialize dates
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, [setSelectedDate1, setSelectedDate2]);
|
||||
|
||||
// Fetch permission for KillHouse role
|
||||
useEffect(() => {
|
||||
if (isKillHouse) {
|
||||
dispatch(
|
||||
slaughterGetPermissionToVetService({
|
||||
role_key: roleKey,
|
||||
})
|
||||
).then((r) => {
|
||||
setChecked(r.payload.data?.[0]?.allow || false);
|
||||
});
|
||||
}
|
||||
}, [isKillHouse, selectedSubUser?.key, dispatch]);
|
||||
|
||||
// Fetch API data
|
||||
const fetchApiData = useCallback(
|
||||
async (pageNumber = page) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const url = buildApiUrl({
|
||||
textValue,
|
||||
role: currentRole,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
page: pageNumber,
|
||||
perPage,
|
||||
roleKey,
|
||||
});
|
||||
|
||||
const response = await axios.get(url);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
currentRole,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
roleKey,
|
||||
page,
|
||||
dispatch,
|
||||
]
|
||||
);
|
||||
|
||||
// Fetch dashboard data
|
||||
const fetchDashboardData = useCallback(() => {
|
||||
dispatch(
|
||||
slaughterEnterLoadInformationGetDashboard({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
text: textValue,
|
||||
role_key: roleKey,
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}, [selectedDate1, selectedDate2, textValue, roleKey, dispatch]);
|
||||
|
||||
// Update table data
|
||||
const updateTable = useCallback(() => {
|
||||
fetchDashboardData();
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
setPage(DEFAULT_PAGE);
|
||||
}, [fetchDashboardData, fetchApiData]);
|
||||
|
||||
// Transform data to table format
|
||||
useEffect(() => {
|
||||
const transformedData = data?.map((item, i) => [
|
||||
<SlaughterEnterInformationOperation
|
||||
key={i}
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>,
|
||||
<Typography
|
||||
key={i}
|
||||
style={{ fontSize: "13px", color: item?.trash ? "red" : "black" }}
|
||||
>
|
||||
{item.barCode}
|
||||
</Typography>,
|
||||
<VetFarmEditTrafficCode
|
||||
key={i}
|
||||
updateTable={fetchApiData}
|
||||
killHouseRequestKey={item.key}
|
||||
trafficCode={item?.trafficCode}
|
||||
isEditable={isTrafficCodeEditable(currentRole, item)}
|
||||
/>,
|
||||
formatDate(item?.poultryRequest?.sendDate),
|
||||
formatUserInfo(
|
||||
item.killhouseUser?.name,
|
||||
item.killhouseUser?.killHouseOperator?.user?.mobile
|
||||
),
|
||||
item?.killer
|
||||
? formatUserInfo(
|
||||
item.killer?.name,
|
||||
item.killer?.killHouseOperator?.user?.mobile
|
||||
)
|
||||
: "-",
|
||||
formatUserInfo(
|
||||
item.poultryRequest?.poultry?.unitName,
|
||||
item.poultryRequest?.poultry?.user?.mobile
|
||||
),
|
||||
item?.poultryRequest?.age || "-",
|
||||
formatNumber(item.quantity),
|
||||
formatNumber(item?.weightInfo?.weight),
|
||||
`${item.addCar?.driver?.typeCar || ""} ${
|
||||
item.addCar?.driver?.pelak || ""
|
||||
}`.trim() || "-",
|
||||
formatUserInfo(
|
||||
item.addCar?.driver?.driverName,
|
||||
item.addCar?.driver?.driverMobile
|
||||
),
|
||||
formatCurrency(item?.poultryRequest?.amount),
|
||||
formatCurrency(item?.weightInfo?.killHousePrice),
|
||||
formatNumber(item.vetAcceptedRealQuantity),
|
||||
formatNumber(item.vetAcceptedRealWeight),
|
||||
item?.poultryRequest?.orderCode || "-",
|
||||
item?.barDocumentStatus?.title || "-",
|
||||
item?.finalBarState || "-",
|
||||
item?.poultryRequest?.freezing ? "انجماد" : "عادی",
|
||||
]);
|
||||
|
||||
setTableData(transformedData || []);
|
||||
}, [data, currentRole, updateTable, fetchApiData]);
|
||||
|
||||
// Initial data fetch
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
}, []);
|
||||
|
||||
// Refetch when filters change
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
}, [selectedDate1, selectedDate2, perPage, selectedSubUser?.keys]);
|
||||
|
||||
// Handlers
|
||||
const handlePageChange = (newPage) => {
|
||||
fetchApiData(newPage);
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (newPerRows) => {
|
||||
setPerPage(newPerRows);
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
await fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleDateChange1 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate1(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDateChange2 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate2(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSwitchChange = () => {
|
||||
const newValue = !checked;
|
||||
dispatch(
|
||||
slaughterPermissionToVetService({
|
||||
allow: newValue,
|
||||
})
|
||||
);
|
||||
setChecked(newValue);
|
||||
};
|
||||
|
||||
// Table columns
|
||||
const dashboardColumns = [
|
||||
"تعداد بار",
|
||||
"مجموع تعداد اولیه",
|
||||
"مجموع وزن اولیه (کیلوگرم)",
|
||||
"مجموع تعداد تحویلی دامپزشک",
|
||||
"مجموع وزن تحویلی دامپزشک (کیلوگرم)",
|
||||
];
|
||||
|
||||
const tableColumns = [
|
||||
"عملیات",
|
||||
"کدبار",
|
||||
"کدبهداشتی حمل و نقل",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"کشتارکن اختصاصی",
|
||||
"مرغدار",
|
||||
"سن مرغ",
|
||||
"تعداد اولیه",
|
||||
"وزن اولیه بار(کیلوگرم)",
|
||||
"ماشین",
|
||||
"راننده",
|
||||
"قیمت مرغدار",
|
||||
"قیمت کشتارگاه",
|
||||
"تحویلی دامپزشک (قطعه)",
|
||||
"وزن تحویلی دامپزشک(کیلوگرم)",
|
||||
"کد سفارش کشتار",
|
||||
"وضعیت سند",
|
||||
"وضعیت بار",
|
||||
"نوع کشتار",
|
||||
];
|
||||
|
||||
const dashboardRow = [
|
||||
formatNumber(dashboardData?.lenKillHouseRequest),
|
||||
formatNumber(dashboardData?.firstQuantity),
|
||||
formatNumber(dashboardData?.firstWeight),
|
||||
formatNumber(dashboardData?.vetAcceptedRealQuantity),
|
||||
formatNumber(dashboardData?.vetAcceptedRealWeight),
|
||||
];
|
||||
|
||||
return (
|
||||
<Box width="100%">
|
||||
{isKillHouse && (
|
||||
<Grid container alignItems="end" justifyContent="center">
|
||||
<Grid container alignItems="center" xs={12} justifyContent="end">
|
||||
<Grid>
|
||||
<Typography color="gray">
|
||||
دسترسی دامپزشک برای وارد کردن اطلاعات بار
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Switch
|
||||
checked={checked}
|
||||
onChange={handleSwitchChange}
|
||||
name="switch-state"
|
||||
inputProps={{ "aria-label": "switch with state" }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL} xs={12}>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate1}
|
||||
onChange={handleDateChange1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate2}
|
||||
onChange={handleDateChange2}
|
||||
/>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
value={textValue}
|
||||
/>
|
||||
<Button type="submit" endIcon={<RiSearchLine />}>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
gap={SPACING.SMALL}
|
||||
xs={12}
|
||||
mt={2}
|
||||
>
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
columns={dashboardColumns}
|
||||
data={[dashboardRow]}
|
||||
title="خلاصه اطلاعات"
|
||||
isDashboard
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={tableColumns}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="درخواست های در انتظار وارد کردن اطلاعات بار"
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { provinceRejectSlaughterFreeBuyService } from "../../services/province-reject-slaughter-free-buy";
|
||||
|
||||
export const ProviceRejectFreeBuy = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [text, setText] = useState("");
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setText(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction="column" gap={SPACING.TINY} width="100%">
|
||||
<TextField
|
||||
label="دلیل رد درخواست"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={text}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
provinceRejectSlaughterFreeBuyService({
|
||||
state: "rejected",
|
||||
kill_request_key: item.key,
|
||||
direct_buying_message: text,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
ثبت رد درخواست
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
|
||||
export const RespGuildExclusiveItem = ({ data }) => {
|
||||
return (
|
||||
<Grid>
|
||||
{data?.map((item, i) => {
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
key={i}
|
||||
alignItems="center"
|
||||
justifyContent="start"
|
||||
flexWrap="nowrap"
|
||||
style={{
|
||||
backgroundColor:
|
||||
i % 2 === 0 ? "rgb(251 245 255)" : "rgb(224 192 245)",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Grid xs={10}>
|
||||
<Typography textAlign={"justify"} variant="body1">
|
||||
{`${i + 1}- ${item[6]} `}
|
||||
</Typography>
|
||||
<Typography textAlign={"justify"} variant="body2">
|
||||
{`با ماهیت ${item[3]} با کدملی ${item[7]} در شهرستان ${item[12]}`}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid xs={2}>{item[16]}</Grid>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Typography } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
|
||||
export const RespSlaughterGuildListItem = ({ data }) => {
|
||||
return (
|
||||
<Grid mt={2}>
|
||||
{data?.map((item, i) => {
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
key={i}
|
||||
alignItems="center"
|
||||
justifyContent="start"
|
||||
flexWrap="nowrap"
|
||||
style={{
|
||||
backgroundColor:
|
||||
i % 2 === 0 ? "rgb(225 225 155)" : "rgb(227 227 128)",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Grid xs={10}>
|
||||
<Typography textAlign={"justify"} variant="body1">
|
||||
{`${i + 1}- ${item[1]} ${item[3]}`}
|
||||
</Typography>
|
||||
<Typography textAlign={"justify"} variant="body2">
|
||||
{` تلفن ${item[5]} در شهرستان ${item[9]} با میانگین سهم ${item[10]}`}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid xs={2}>{item[11]}</Grid>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
import { IconButton, Tooltip, Typography } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterSubmitRealInventory } from "../slaughter-submit-real-inventory/SlaughterSubmitRealInventory";
|
||||
import { useDispatch } from "react-redux";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
|
||||
export const RespSlaughterStockBarSystem = ({
|
||||
data,
|
||||
inventorySelectedKillHouse,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
return (
|
||||
<Grid>
|
||||
{data?.map((item, i) => {
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
key={i}
|
||||
alignItems="center"
|
||||
justifyContent="start"
|
||||
p={SPACING.SMALL}
|
||||
flexWrap="nowrap"
|
||||
>
|
||||
<Grid>
|
||||
<Typography textAlign={"justify"} variant="caption">
|
||||
{`${i + 1}- مرغدار ${item[1]} کشتارگاه ${item[2]} با کدسفارش ${
|
||||
item[3]
|
||||
} در شهرستان ${item[4]} با تعداد تخصیصی ${item[12]}`}
|
||||
</Typography>
|
||||
{item[17]}
|
||||
<Tooltip title="ورود بار به انبار" key={i}>
|
||||
<IconButton
|
||||
// disabled={
|
||||
// item?.wareHouseAcceptedRealQuantity ||
|
||||
// item?.wareHouseAcceptedRealWeight
|
||||
// }
|
||||
size={"small"}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت موجودی واقعی",
|
||||
content: (
|
||||
<SlaughterSubmitRealInventory
|
||||
item={item}
|
||||
inventorySelectedKillHouse={
|
||||
inventorySelectedKillHouse
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SettingsIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,153 @@
|
||||
import { Card, Grid, IconButton, TextField, Typography } from "@mui/material";
|
||||
import { ROUTE_SLAUGHTER_FILE } from "../../../../routes/routes";
|
||||
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useFormik } from "formik";
|
||||
import moment from "moment";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetActiveRequests } from "../../services/slaughter-get-active-requests";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import PlagiarismIcon from "@mui/icons-material/Plagiarism";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
|
||||
export const SlaughterActiveRequests = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const { slaughterActiveRequests } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(slaughterGetActiveRequests({ selectedDate1, selectedDate2 }));
|
||||
}, [selectedDate1, selectedDate2]);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredData = slaughterActiveRequests?.filter(
|
||||
(item, i) => item.provinceKillState !== "rejected"
|
||||
);
|
||||
const key = "orderCode";
|
||||
const arrayUniqueByKey = [
|
||||
...new Map(filteredData?.map((item) => [item[key], item])).values(),
|
||||
];
|
||||
const d = arrayUniqueByKey.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item.orderCode,
|
||||
format(new Date(item?.sendDate), "yyyy/MM/dd"),
|
||||
item.poultryName,
|
||||
item.poultryMobile,
|
||||
item.city,
|
||||
item.province,
|
||||
item.age,
|
||||
item.mainQuantity + " قطعه",
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() => navigate(ROUTE_SLAUGHTER_FILE + item.poultryReqId)}
|
||||
>
|
||||
<PlagiarismIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTable(d);
|
||||
}, [slaughterActiveRequests]);
|
||||
|
||||
const [tableDataCol] = useState([
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"تاریخ درخواست",
|
||||
"مرغدار",
|
||||
"تلفن مرغدار",
|
||||
"شهر",
|
||||
"استان",
|
||||
"سن مرغ",
|
||||
"تعداد",
|
||||
"مشاهده",
|
||||
]);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
capacity: "",
|
||||
recieveTime: "",
|
||||
recieveDate: moment(Date()).format("YYYY-MM-DD hh:mm:ss"),
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
capacity: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
recieveTime: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا وزن را وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
mt={SPACING.MEDIUM}
|
||||
>
|
||||
<Card sx={{ width: "100%" }}>
|
||||
<AdvancedTable
|
||||
name={
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<Typography>درخواست های فعال</Typography>
|
||||
</Grid>
|
||||
<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>
|
||||
</Grid>
|
||||
}
|
||||
columns={tableDataCol}
|
||||
data={dataTable}
|
||||
/>
|
||||
</Card>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,120 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Autocomplete, Button, Chip, TextField } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import {
|
||||
slaughterAddDailyListService,
|
||||
slaughterGetGuildsService,
|
||||
} from "../../services/slaughter-add-daily-list";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterAddDailyList = ({ updateTable }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const [guildsData, setGuildsData] = useState([]);
|
||||
const [selectedItems, setSelectedItems] = useState([]);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchGuilds = async () => {
|
||||
dispatch(
|
||||
slaughterGetGuildsService({
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setGuildsData(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
fetchGuilds();
|
||||
}, [dispatch]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch(
|
||||
slaughterAddDailyListService({
|
||||
guild_key_list: selectedItems.map((item) => item.key),
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "خطا در ثبت لیست",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "لیست با موفقیت ثبت شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
updateTable(1);
|
||||
}
|
||||
});
|
||||
};
|
||||
const handleDelete = (key) => {
|
||||
setSelectedItems((prev) => prev.filter((item) => item.key !== key));
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
<Autocomplete
|
||||
multiple
|
||||
disablePortal
|
||||
id="guilds-select"
|
||||
options={guildsData}
|
||||
renderTags={() => null}
|
||||
getOptionLabel={(option) =>
|
||||
`${option.steward ? "مباشر" : "صنف"} ${
|
||||
option.name || option.guildsName
|
||||
}
|
||||
${option.user?.fullname || ""}
|
||||
(${option.user?.mobile || ""})`
|
||||
}
|
||||
onChange={(event, values) => {
|
||||
setSelectedItems(values);
|
||||
}}
|
||||
sx={{ width: "250px" }}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
fullWidth
|
||||
label="انتخاب مباشر / صنف"
|
||||
placeholder="انتخاب کنید"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Grid container direction="column" gap={1}>
|
||||
{selectedItems.map((item) => (
|
||||
<Chip
|
||||
key={item.key}
|
||||
label={`${item.steward ? "مباشر" : "صنف"} ${
|
||||
item.name || item.guildsName
|
||||
}`}
|
||||
onDelete={() => handleDelete(item.key)}
|
||||
sx={{ width: "fit-content" }}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSubmit}
|
||||
disabled={selectedItems.length === 0}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,330 @@
|
||||
import { Autocomplete, Button, InputAdornment, TextField } from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { slaughterGetUpdatedInventoryStock } from "../../services/salughter-get-updated-inventory-stock";
|
||||
import { slaughterManageInventoryAllocationsService } from "../../services/salughter-manage-inventory-allocations";
|
||||
import { slaughterAllocateStewardService } from "../../services/slaughter-allocate-steward";
|
||||
import { slaughterEditAllocateStewardService } from "../../services/slaughter-edit-allocate-steward";
|
||||
import { slaughterGetGuildsService } from "../../services/slaughter-get-guilds";
|
||||
import { slaughterGetKillhouseGuildsService } from "../../services/slaughter-get-killhouse-guilds";
|
||||
import { slaughterGetKillhouseStewardsService } from "../../services/slaughter-get-killhouse-stewards";
|
||||
import { slaughterGetStewardsService } from "../../services/slaughter-get-stewards";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
|
||||
export const SlaughterAddSteward = ({
|
||||
stewardKey,
|
||||
guildKey,
|
||||
sellType,
|
||||
isGuild,
|
||||
weight,
|
||||
quantity,
|
||||
item,
|
||||
totalAverageWeightOfCarcasses,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
const [price, setPrice] = useState();
|
||||
|
||||
const {
|
||||
slaughterGetStewards,
|
||||
inventorySelectedKillHouse,
|
||||
slaughterGetGuilds,
|
||||
} = useSelector((state) => state.slaughterSlice);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(slaughterGetStewardsService());
|
||||
dispatch(slaughterGetGuildsService());
|
||||
}, []);
|
||||
|
||||
const getOptionLabel = (option) => option.label;
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
wholePrice: Yup.number().when("quantity", {
|
||||
is: quantity,
|
||||
then: Yup.number().required("لطفا این فیلد را پر کنید"),
|
||||
otherwise: Yup.number(),
|
||||
}),
|
||||
slaughteSteward: Yup.string().required("لطفاً یک مورد را انتخاب کنید"),
|
||||
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: quantity ? quantity : "",
|
||||
weight: weight ? weight : "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
let req;
|
||||
if (!isGuild) {
|
||||
req = {
|
||||
steward_key: values.slaughteSteward,
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
sell_type: sellType,
|
||||
date: selectedDate1,
|
||||
amount: Number(price),
|
||||
total_amount: Number(values.wholePrice),
|
||||
};
|
||||
} else {
|
||||
req = {
|
||||
guild_key: values.slaughteSteward,
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
sell_type: sellType,
|
||||
date: selectedDate1,
|
||||
amount: Number(price),
|
||||
total_amount: Number(values.wholePrice),
|
||||
};
|
||||
}
|
||||
if (quantity) {
|
||||
dispatch(
|
||||
slaughterEditAllocateStewardService({
|
||||
steward_allocation_key: item.key,
|
||||
number_of_carcasses: Number(values.numberOfPieces),
|
||||
weight_of_carcasses: Number(values.weight),
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
slaughterGetKillhouseStewardsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetUpdatedInventoryStock({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterManageInventoryAllocationsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetKillhouseGuildsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch(slaughterAllocateStewardService(req)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
slaughterGetKillhouseStewardsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetUpdatedInventoryStock({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterManageInventoryAllocationsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetKillhouseGuildsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
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={slaughterGetStewards}
|
||||
getOptionLabel={getOptionLabel}
|
||||
sx={{ width: "100%" }}
|
||||
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={slaughterGetGuilds ? slaughterGetGuilds : []}
|
||||
getOptionLabel={getOptionLabel}
|
||||
sx={{ width: "100%" }}
|
||||
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"
|
||||
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
|
||||
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
|
||||
}
|
||||
/>
|
||||
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
id="price"
|
||||
label="قیمت هر کیلو مرغ"
|
||||
variant="outlined"
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="start">ریال</InputAdornment>
|
||||
),
|
||||
readOnly: true,
|
||||
}}
|
||||
value={price}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="numberOfPieces"
|
||||
name="numberOfPieces"
|
||||
type="number"
|
||||
label="حجم لاشه"
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,381 @@
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Popover,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { useContext, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ROUTE_SLAUGHTER_FILE } from "../../../../routes/routes";
|
||||
import PlagiarismIcon from "@mui/icons-material/Plagiarism";
|
||||
import SettingsBackupRestoreIcon from "@mui/icons-material/SettingsBackupRestore";
|
||||
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
|
||||
import { slaughterDeleteAllocatedBackRequestService } from "../../services/slaughter-delete-allocated-back-kill-request";
|
||||
import { slaughterRemoveAllocateCarService } from "../../services/slaughter-remove-allocate-car";
|
||||
import { slaughterGetActiveRequests } from "../../services/slaughter-get-active-requests";
|
||||
import { slaughterGetAllocatedCarsService } from "../../services/slaughter-get-allocated-cars";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
OPEN_MODAL,
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterEditAllocatedCar } from "../slaughter-edit-allocated-car/SlaughterEditAllocatedCar";
|
||||
import { SlaughterSubmitChickenPrice } from "../slaughter-submit-chicken-price/SlaughterSubmitChickenPrice";
|
||||
import SlaughterAssignCar from "../../../file/components/slaughter-assign-car/SlaughterAssignCar";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterAllocatedCarToRequestOperation = ({
|
||||
item,
|
||||
updateTable,
|
||||
isAllocatedCar = false,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
submitStatus,
|
||||
}) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const [openNotif, , contextDate1, , contextDate2] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
// Use prop dates if provided, otherwise use context dates
|
||||
const date1 = selectedDate1 || contextDate1;
|
||||
const date2 = selectedDate2 || contextDate2;
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
const confirmDeleteAllocatedCar = () => {
|
||||
dispatch(slaughterRemoveAllocateCarService(item.killHouseRequestKey)).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());
|
||||
// Refresh both tables
|
||||
dispatch(
|
||||
slaughterGetActiveRequests({
|
||||
isCar: true,
|
||||
selectedDate1: date1,
|
||||
selectedDate2: date2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetAllocatedCarsService({
|
||||
selectedDate1: date1,
|
||||
selectedDate2: date2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
if (updateTable) updateTable();
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleDeleteAllocatedCar = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید حذف",
|
||||
content: (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.SMALL}
|
||||
sx={{ p: 2, minWidth: "300px" }}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
آیا از حذف تخصیص این خودرو اطمینان دارید؟
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
justifyContent="space-between"
|
||||
xs={12}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => dispatch(CLOSE_MODAL())}
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={confirmDeleteAllocatedCar}
|
||||
>
|
||||
حذف
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleEditAllocatedCar = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش خودرو و کد حمل",
|
||||
content: (
|
||||
<SlaughterEditAllocatedCar
|
||||
item={item}
|
||||
updateTable={() => {
|
||||
// Refresh both tables
|
||||
dispatch(
|
||||
slaughterGetActiveRequests({
|
||||
isCar: true,
|
||||
selectedDate1: date1,
|
||||
selectedDate2: date2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetAllocatedCarsService({
|
||||
selectedDate1: date1,
|
||||
selectedDate2: date2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
if (updateTable) updateTable();
|
||||
}}
|
||||
poultryRequestKey={item?.poultryReqKey}
|
||||
killHouseKey={item?.killHouseKey}
|
||||
killRequestKey={item?.killRequestKey}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleViewFile = () => {
|
||||
navigate(ROUTE_SLAUGHTER_FILE + item.poultryReqId);
|
||||
};
|
||||
|
||||
const handleReturnAllocation = () => {
|
||||
dispatch(
|
||||
slaughterDeleteAllocatedBackRequestService({
|
||||
provinceKillRequestKey: item?.provinceKillRequestKey,
|
||||
returnAllocationQuantity: true,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات برگشت تخصیص با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleRegisterCar = () => {
|
||||
if (submitStatus === true && item?.killHousePrice === 0) {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت قیمت مرغ زنده",
|
||||
content: (
|
||||
<SlaughterSubmitChickenPrice item={item} fetchData={updateTable} />
|
||||
),
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "انجام عملیات تخصیص",
|
||||
top: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterAssignCar
|
||||
indexWeight={item.indexWeight}
|
||||
killHouseName={item.killHouseName}
|
||||
killHouseCheckKey={item.killHouseCheckKey}
|
||||
killHouseKey={item.killHouseKey}
|
||||
killRequestKey={item.killRequestKey}
|
||||
poultryRequestKey={item.poultryReqKey}
|
||||
provinceAllocationLimit={item.remainQuantity || 0}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const options = [];
|
||||
|
||||
if (!isAllocatedCar) {
|
||||
const needsPrice =
|
||||
submitStatus === true && (item?.killHousePrice || 0) === 0;
|
||||
|
||||
options.push({
|
||||
key: "register",
|
||||
label: "ثبت خودرو",
|
||||
color: needsPrice ? "error.main" : "primary.main",
|
||||
icon: AddCircleOutlineIcon,
|
||||
action: handleRegisterCar,
|
||||
});
|
||||
|
||||
options.push({
|
||||
key: "viewFile",
|
||||
label: "مشاهده پرونده",
|
||||
color: "primary.main",
|
||||
icon: PlagiarismIcon,
|
||||
action: handleViewFile,
|
||||
});
|
||||
|
||||
const returnDisabled = item?.allocatedQuantity > 0;
|
||||
options.push({
|
||||
key: "return",
|
||||
label: "برگشت تخصیص",
|
||||
color: returnDisabled ? "text.disabled" : "warning.main",
|
||||
icon: SettingsBackupRestoreIcon,
|
||||
action: handleReturnAllocation,
|
||||
disabled: returnDisabled,
|
||||
});
|
||||
}
|
||||
|
||||
if (isAllocatedCar) {
|
||||
options.push({
|
||||
key: "editAllocated",
|
||||
label: "ویرایش خودرو و کد حمل",
|
||||
color: "info.main",
|
||||
icon: EditIcon,
|
||||
action: handleEditAllocatedCar,
|
||||
});
|
||||
|
||||
options.push({
|
||||
key: "deleteAllocated",
|
||||
label: "حذف تخصیص خودرو",
|
||||
color: "error.main",
|
||||
icon: DeleteIcon,
|
||||
action: handleDeleteAllocatedCar,
|
||||
});
|
||||
}
|
||||
|
||||
const handleOptionClick = (option) => {
|
||||
if (option.disabled) {
|
||||
return;
|
||||
}
|
||||
handleClose();
|
||||
option.action();
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<IconButton
|
||||
size="small"
|
||||
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={{ minWidth: 150, p: 0.5 }}>
|
||||
{options.map((option) => {
|
||||
const IconComponent = option.icon;
|
||||
const itemColor = option.disabled ? "text.disabled" : option.color;
|
||||
return (
|
||||
<ListItemButton
|
||||
key={option.key}
|
||||
disabled={option.disabled}
|
||||
onClick={() => handleOptionClick(option)}
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
mb: 0.25,
|
||||
py: 0.5,
|
||||
"&:last-of-type": {
|
||||
mb: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ color: itemColor, minWidth: 32 }}>
|
||||
<IconComponent fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={option.label}
|
||||
primaryTypographyProps={{
|
||||
sx: {
|
||||
color: itemColor,
|
||||
fontSize: "0.82rem",
|
||||
fontWeight: 600,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,346 @@
|
||||
import { Grid, IconButton, TextField, Tooltip } from "@mui/material";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useFormik } from "formik";
|
||||
import moment from "moment";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetActiveRequests } from "../../services/slaughter-get-active-requests";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterGetAllocatedCarsService } from "../../services/slaughter-get-allocated-cars";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf";
|
||||
import { useReactToPrint } from "react-to-print";
|
||||
import { useRef } from "react";
|
||||
import SlaughterSendKillerInvoice from "../slaughter-send-killer-invoice/SlaughterSendKillerInvoice";
|
||||
import { useSystemName } from "../../../../utils/getSystemName";
|
||||
import { formatJustDate, formatTime } from "../../../../utils/formatTime";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { provincePolicyGetSLaughterSubmitBuyingPriceStatus } from "../../../province/services/province-policy-get-slaughter-buying-price-status";
|
||||
import { SlaughterSubmitChickenPrice } from "../slaughter-submit-chicken-price/SlaughterSubmitChickenPrice";
|
||||
import { SlaughterAllocatedCarToRequestOperation } from "../slaughter-allocate-car-to-request-operation/SlaughterAllocatedCarToRequestOperation";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterAllocateCarToRequests = () => {
|
||||
const componentRef = useRef();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [data, setData] = useState();
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const [allocatedDataTable, setAllocatedDataTable] = useState([]);
|
||||
const { slaughterActiveRequests, slaughterGetAllocatedCars } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
|
||||
const systemName = useSystemName();
|
||||
const dispatch = useDispatch();
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
const [submitStatus, SetSubmitStatus] = useState();
|
||||
|
||||
const fetchData = () => {
|
||||
dispatch(
|
||||
slaughterGetActiveRequests({
|
||||
isCar: true,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetAllocatedCarsService({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
provincePolicyGetSLaughterSubmitBuyingPriceStatus({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
SetSubmitStatus(r.payload.data.allow);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [selectedDate1, selectedDate2, selectedSubUser?.key]);
|
||||
|
||||
const printPDF = useReactToPrint({
|
||||
content: () => componentRef.current,
|
||||
documentTitle: "حواله خرید",
|
||||
});
|
||||
const updateTable = () => {
|
||||
fetchData();
|
||||
};
|
||||
|
||||
const setPdfOptions = (item) => {
|
||||
setData(item);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = slaughterActiveRequests?.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item.orderCode,
|
||||
item?.freezing ? "انجماد" : item?.export ? "صادرات" : "عادی",
|
||||
item?.freeSaleInProvince ? "آزاد" : "دولتی",
|
||||
item?.directBuying ? "خرید مستقیم" : "اتحادیه",
|
||||
format(new Date(item?.sendDate), "yyyy/MM/dd"),
|
||||
`${item.poultryName} (${item.poultryMobile})`,
|
||||
`${item.killHouseName} (${item.killHouseMobile})`,
|
||||
`${item.province}/${item.city}`,
|
||||
item.age,
|
||||
item.indexWeight,
|
||||
item?.totalWeight.toLocaleString(),
|
||||
item.mainQuantity.toLocaleString() + " قطعه",
|
||||
item.amount.toLocaleString() + " ﷼",
|
||||
item.allocatedQuantity.toLocaleString() + " قطعه",
|
||||
item.remainQuantity.toLocaleString() + " قطعه",
|
||||
item?.killHousePrice > 0 ? (
|
||||
<Grid container alignItems="center" gap={1} key={i}>
|
||||
{item?.killHousePrice?.toLocaleString() + " ریال"}
|
||||
{formatJustDate(item?.sendDate) === formatJustDate(new Date()) ? (
|
||||
<IconButton
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش قیمت مرغ زنده",
|
||||
content: (
|
||||
<SlaughterSubmitChickenPrice
|
||||
item={item}
|
||||
fetchData={fetchData}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon fontSize="small" />
|
||||
</IconButton>
|
||||
) : null}
|
||||
</Grid>
|
||||
) : (
|
||||
<span key={i}>0</span>
|
||||
),
|
||||
|
||||
<SlaughterAllocatedCarToRequestOperation
|
||||
key={i}
|
||||
updateTable={updateTable}
|
||||
item={item}
|
||||
submitStatus={submitStatus}
|
||||
/>,
|
||||
// <IconButton
|
||||
// key={i}
|
||||
// aria-label="delete"
|
||||
// color="primary"
|
||||
// onClick={() => navigate(ROUTE_SLAUGHTER_FILE + item.poultryReqId)}
|
||||
// >
|
||||
// <PlagiarismIcon />
|
||||
// </IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTable(d);
|
||||
}, [slaughterActiveRequests, submitStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = slaughterGetAllocatedCars
|
||||
?.filter((item) => item.vetState === "pending")
|
||||
.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item?.orderCode,
|
||||
item?.barcod,
|
||||
item?.freezing ? "انجماد" : item?.export ? "صادرات" : "عادی",
|
||||
item?.freeSaleInProvince ? "آزاد" : "دولتی",
|
||||
formatJustDate(item?.sendDate),
|
||||
formatTime(item?.killHouseCreateDate),
|
||||
`${item?.poultryName} (${item.poultryMobile})`,
|
||||
`${item?.killHouseName} (${item.killHouseMobile})`,
|
||||
item?.killer
|
||||
? `${item?.killer?.killerName} (${item?.killer?.killerMobile})`
|
||||
: "-",
|
||||
item?.driverName,
|
||||
item?.typeCar,
|
||||
item?.pelak,
|
||||
// item?.realCar
|
||||
// ? `${item?.realCar?.realTypeCar} (${
|
||||
// item?.realCar?.realPelak ? item?.realCar?.realPelak : "نامشخص"
|
||||
// }) - راننده: ${item?.realCar?.realDriverName}`
|
||||
// : "-",
|
||||
item?.acceptedRealQuantity.toLocaleString() + " قطعه",
|
||||
item?.acceptedRealWeight.toLocaleString(),
|
||||
item?.amount?.toLocaleString() + " ﷼",
|
||||
item?.trafficCode,
|
||||
item?.barAmount?.toLocaleString() + " ﷼",
|
||||
<Grid key={i} container gap={1}>
|
||||
<SlaughterAllocatedCarToRequestOperation
|
||||
key={i}
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
isAllocatedCar={true}
|
||||
selectedDate1={selectedDate1}
|
||||
selectedDate2={selectedDate2}
|
||||
/>
|
||||
|
||||
{systemName === "استان اردبیل" ? (
|
||||
<Tooltip title="خروجی PDF">
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
printPDF();
|
||||
setPdfOptions(item);
|
||||
}}
|
||||
size={"large"}
|
||||
aria-label="pdf"
|
||||
color="success"
|
||||
>
|
||||
<PictureAsPdfIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Grid>,
|
||||
];
|
||||
});
|
||||
|
||||
setAllocatedDataTable(d);
|
||||
}, [slaughterGetAllocatedCars]);
|
||||
|
||||
const [tableDataCol] = useState([
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"کشتار",
|
||||
"فروش",
|
||||
"درخواست",
|
||||
"تاریخ کشتار",
|
||||
"مرغدار",
|
||||
"خریدار",
|
||||
"استان/شهر",
|
||||
"سن",
|
||||
"میانگین وزن",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"تعداد",
|
||||
"قیمت مرغدار",
|
||||
"تخصیص به خودرو",
|
||||
"مانده قابل تخصیص",
|
||||
"قیمت کشتارگاه",
|
||||
"عملیات",
|
||||
]);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
capacity: "",
|
||||
recieveTime: "",
|
||||
recieveDate: moment(Date()).format("YYYY-MM-DD hh:mm:ss"),
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
capacity: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
recieveTime: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا وزن را وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
mt={SPACING.MEDIUM}
|
||||
>
|
||||
{data && (
|
||||
<div style={{ visibility: "hidden", position: "absolute" }}>
|
||||
<SlaughterSendKillerInvoice
|
||||
ref={componentRef}
|
||||
date={selectedDate1}
|
||||
amount={data?.quantity}
|
||||
breeder={data?.poultryName}
|
||||
buyer={data?.killHouseName}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<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>
|
||||
</Grid>
|
||||
<ResponsiveTable
|
||||
paginated
|
||||
title="در انتظار تخصیص خودرو"
|
||||
columns={tableDataCol}
|
||||
data={dataTable}
|
||||
/>
|
||||
<ResponsiveTable
|
||||
title="خودروهای تخصیص داده شده"
|
||||
paginated
|
||||
columns={[
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"کد بار",
|
||||
"کشتار",
|
||||
"فروش",
|
||||
"تاریخ کشتار",
|
||||
"تاریخ ثبت خودرو",
|
||||
"مرغدار",
|
||||
"خریدار",
|
||||
"کشتارکن اختصاصی",
|
||||
"راننده",
|
||||
"ماشین",
|
||||
"پلاک",
|
||||
"تعداد",
|
||||
"وزن (کیلوگرم)",
|
||||
"قیمت مرغ زنده",
|
||||
"کد حمل و نقل",
|
||||
"قیمت مرغ زندهی بار",
|
||||
"عملیات",
|
||||
]}
|
||||
data={allocatedDataTable}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,595 @@
|
||||
import React, { useContext, useEffect, useState, useCallback } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetProductsService } from "../../services/slaughter-inventory-gets";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import {
|
||||
slaughterAllocateStewardService,
|
||||
slaughterEditAllocateStewardService,
|
||||
} from "../../services/slaughter-allocate-steward";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { liveStockGetInventoryData } from "../../../live-stock-support/services/live-stock-get-inventory-data";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
import MonthlyDataCalendar from "../../../../components/date-picker/MonthlyDataCalendar";
|
||||
import PersianDate from "persian-date";
|
||||
import axios from "axios";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
import { LabelField } from "../../../../components/label-field/LabelField";
|
||||
|
||||
export const SlaughterAllocateForFreezing = ({
|
||||
sellerType,
|
||||
sellType,
|
||||
updateTable,
|
||||
fetchApiData,
|
||||
editData,
|
||||
remainWeight,
|
||||
priceInfo,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [productData, setProductData] = useState([]);
|
||||
const [productKey, setProductKey] = useState(null);
|
||||
const [coldHouseData, setColdHouseData] = useState([]);
|
||||
const [coldHouseKey, setColdHouseKey] = useState(null);
|
||||
const [selectedInventory, setSelectedInventory] = useState("governmental");
|
||||
const [approvedStatus, setApprovedStatus] = useState(
|
||||
priceInfo?.active === false ? false : true
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
// Calendar states
|
||||
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 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 (dateParam) => {
|
||||
try {
|
||||
const response = await axios.get("/kill-house-remain-weight/", {
|
||||
params: {
|
||||
date: dateParam,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? 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, selectedSubUser]
|
||||
);
|
||||
|
||||
const handleDateSelect = (dateInfo) => {
|
||||
if (dateInfo && dateInfo.formattedDate) {
|
||||
setSelectedCalendarDate(dateInfo.formattedDate);
|
||||
|
||||
const data = calendarDayData[dateInfo.formattedDate];
|
||||
|
||||
if (data && data.originalDay) {
|
||||
const selectedOriginalDay = data.originalDay;
|
||||
if (
|
||||
selectedDate1 &&
|
||||
moment(selectedOriginalDay).isAfter(moment(selectedDate1), "day")
|
||||
) {
|
||||
setCalendarDateError(
|
||||
"تاریخ تولید نمیتواند بعد از تاریخ انتخابی باشد"
|
||||
);
|
||||
return;
|
||||
}
|
||||
setCalendarDateError(null);
|
||||
setProductionDate(selectedOriginalDay);
|
||||
}
|
||||
|
||||
if (data && data.value1 !== undefined) {
|
||||
setSelectedDateAmount(data.value1);
|
||||
} else {
|
||||
setSelectedDateAmount(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getValidationSchema = useCallback(
|
||||
() =>
|
||||
Yup.object({
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.integer("عدد باید صحیح باشد!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!")
|
||||
.max(
|
||||
remainWeight + (editData?.realWeightOfCarcasses || 0),
|
||||
"وزن وارد شده بیش از موجودی انبار است!"
|
||||
)
|
||||
.test(
|
||||
"max-production-date-amount",
|
||||
`وزن نمیتواند بیشتر از موجودی تاریخ تولید (${
|
||||
selectedDateAmount?.toLocaleString() || 0
|
||||
} کیلوگرم) باشد!`,
|
||||
function (value) {
|
||||
if (!selectedDateAmount || selectedDateAmount === null)
|
||||
return true;
|
||||
return value <= selectedDateAmount;
|
||||
}
|
||||
),
|
||||
}),
|
||||
[remainWeight, editData, selectedDateAmount]
|
||||
);
|
||||
|
||||
const validationSchema = getValidationSchema();
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const [dateRangeError, setDateRangeError] = useState(null);
|
||||
const [calendarDateError, setCalendarDateError] = useState(null);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
weight: editData?.realWeightOfCarcasses || "",
|
||||
},
|
||||
validationSchema,
|
||||
});
|
||||
|
||||
const successSubmit = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(
|
||||
fetchSlaughterBroadcastAndProducts({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
fetchApiData();
|
||||
updateTable();
|
||||
};
|
||||
|
||||
const handleSellType = (event) => {
|
||||
const newType = event.target.value;
|
||||
setSelectedInventory(newType);
|
||||
};
|
||||
|
||||
const handleApprovedPrice = (event) => {
|
||||
const newType = event.target.value;
|
||||
setApprovedStatus(newType);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!editData) {
|
||||
dispatch(
|
||||
slaughterGetProductsService({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setProductData(r.payload.data);
|
||||
});
|
||||
|
||||
dispatch(
|
||||
liveStockGetInventoryData({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setColdHouseData(r.payload.data);
|
||||
});
|
||||
}
|
||||
fetchCalendarData(selectedDate1);
|
||||
}, [
|
||||
dispatch,
|
||||
editData,
|
||||
fetchCalendarData,
|
||||
selectedDate1,
|
||||
selectedSubUser?.key,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCalendarData(selectedDate1);
|
||||
}, [selectedDate1, fetchCalendarData, selectedSubUser?.key]);
|
||||
|
||||
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, updateCalendarData]);
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, [selectedDateAmount]);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
direction="column"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
>
|
||||
{!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 && (
|
||||
<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 && (
|
||||
<Grid xs={12} container>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="hatching"
|
||||
options={
|
||||
coldHouseData
|
||||
? coldHouseData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i.name}`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setColdHouseKey(value.data?.key);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب سردخانه" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!editData && priceInfo?.active && (
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={approvedStatus}
|
||||
onChange={handleApprovedPrice}
|
||||
>
|
||||
<FormControlLabel
|
||||
value={true}
|
||||
control={<Radio />}
|
||||
label="قیمت دولتی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value={false}
|
||||
control={<Radio />}
|
||||
label="قیمت آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{!editData && (
|
||||
<Grid my={1} xs={12}>
|
||||
<LabelField label="نوع انبار">
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="segment-type-radio-group"
|
||||
name="segmentType"
|
||||
value={selectedInventory}
|
||||
onChange={handleSellType}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="governmental"
|
||||
control={<Radio />}
|
||||
label="دولتی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="free"
|
||||
control={<Radio />}
|
||||
label="آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</LabelField>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!editData && (
|
||||
<Grid
|
||||
style={{ width: "100%" }}
|
||||
container
|
||||
xs={12}
|
||||
lg={3}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
mb={3}
|
||||
mt={2}
|
||||
gap={1}
|
||||
>
|
||||
<MonthlyDataCalendar
|
||||
onDateSelect={handleDateSelect}
|
||||
dayData={calendarDayData}
|
||||
selectedDate={selectedCalendarDate}
|
||||
maxGregorianDate={selectedDate1}
|
||||
label={`تاریخ تولید گوشت ${
|
||||
selectedDateAmount !== null
|
||||
? `(موجودی: ${selectedDateAmount?.toLocaleString()} کیلوگرم)`
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
{calendarDateError && (
|
||||
<Typography
|
||||
sx={{
|
||||
color: "#d32f2f",
|
||||
fontSize: "0.75rem",
|
||||
marginTop: "4px",
|
||||
marginRight: "14px",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{calendarDateError}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
decimalScale={0}
|
||||
allowNegative={false}
|
||||
fullWidth
|
||||
id="weight"
|
||||
disabled={remainWeight < 1}
|
||||
label="وزن لاشه"
|
||||
variant="outlined"
|
||||
value={formik.values.weight}
|
||||
error={
|
||||
remainWeight < 1
|
||||
? 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={
|
||||
remainWeight < 1
|
||||
? "موجودی انبار خالی است!"
|
||||
: selectedDateAmount && formik.values.weight > selectedDateAmount
|
||||
? `وزن نمیتواند بیشتر از موجودی تاریخ تولید (${selectedDateAmount?.toLocaleString()} کیلوگرم) باشد!`
|
||||
: formik.touched.weight && Boolean(formik.errors.weight)
|
||||
? formik.errors.weight
|
||||
: null
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
disabled={
|
||||
editData
|
||||
? !formik.isValid
|
||||
: !formik.isValid ||
|
||||
!productKey ||
|
||||
!coldHouseKey ||
|
||||
!productionDate ||
|
||||
(selectedDateAmount &&
|
||||
formik.values.weight > selectedDateAmount) ||
|
||||
(productionDate &&
|
||||
selectedDate1 &&
|
||||
moment(productionDate).isAfter(moment(selectedDate1), "day"))
|
||||
}
|
||||
onClick={() => {
|
||||
let req = {};
|
||||
if (!editData) {
|
||||
req = {
|
||||
seller_type: sellerType,
|
||||
product_key: productKey.key,
|
||||
type: "manual",
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
approved_price_status: approvedStatus === "true" ? true : false,
|
||||
quota: selectedInventory,
|
||||
sell_type: sellType,
|
||||
buyer_type: "ColdHouse",
|
||||
cold_house_key: coldHouseKey,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
allocation_type: "ColdHouse",
|
||||
date: selectedDate1,
|
||||
production_date: productionDate,
|
||||
distribution_type: "web",
|
||||
};
|
||||
} else {
|
||||
req = {
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
allocation_key: editData?.key,
|
||||
distribution_type: "web",
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Button } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterAddSteward } from "../slaughter-add-steward/SlaughterAddSteward";
|
||||
|
||||
export const SlaughterAllocateSelfSteward = ({
|
||||
stewardKey,
|
||||
guildKey,
|
||||
isGuild,
|
||||
finalSubmitDisabled,
|
||||
slaughterUpdatedInventoryStock,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
return (
|
||||
<Button
|
||||
disabled={finalSubmitDisabled}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تخصیص به مباشر",
|
||||
content: (
|
||||
<SlaughterAddSteward
|
||||
sellType={"exclusive"}
|
||||
stewardKey={stewardKey}
|
||||
guildKey={guildKey}
|
||||
isGuild={isGuild}
|
||||
totalAverageWeightOfCarcasses={
|
||||
slaughterUpdatedInventoryStock?.totalAverageWeightOfCarcasses
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تخصیص
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,602 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputAdornment,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetProductsService } from "../../services/slaughter-inventory-gets";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import {
|
||||
slaughterAllocateStewardService,
|
||||
slaughterEditAllocateStewardService,
|
||||
} from "../../services/slaughter-allocate-steward";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import {
|
||||
slaughterGetColdHousesForAllocateService,
|
||||
slaughterGetGuildsForAllocateService,
|
||||
} from "../../services/slaughter-get-guilds-for-allocate";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { ImageUpload } from "../../../../components/image-upload/ImageUpload";
|
||||
import { fixBase64 } from "../../../../utils/toBase64";
|
||||
import { provincePolicyGetUploadImageService } from "../../../province/services/province-policy-upload-image";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterAllocateToColdHouse = ({
|
||||
item,
|
||||
key,
|
||||
sellerType,
|
||||
fetchData,
|
||||
buyerType,
|
||||
allocationType,
|
||||
sellType,
|
||||
updateTable,
|
||||
fetchApiData,
|
||||
editData,
|
||||
priceInfo,
|
||||
coldHouseKey,
|
||||
coldHouseItemKey,
|
||||
remainWeight,
|
||||
killHouseAllocation,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [productData, setProductData] = useState([]);
|
||||
const [guildsData, setGuildsData] = useState([]);
|
||||
const [coldHouseData, setColdHouseData] = useState([]);
|
||||
const [productKey, setProductKey] = useState(null);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [sellGovernmental, setSellGovernmental] = useState(
|
||||
priceInfo?.active ? "true" : "false"
|
||||
);
|
||||
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 selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
setBuyerData({
|
||||
key: "",
|
||||
item: "",
|
||||
buyerType: "",
|
||||
allocationType: "",
|
||||
});
|
||||
};
|
||||
|
||||
const handleChangeSellGovernmental = (event) => {
|
||||
setSellGovernmental(event.target.value);
|
||||
if (event.target.value === "false") {
|
||||
formik.setFieldValue("price", "");
|
||||
}
|
||||
};
|
||||
|
||||
const [buyerData, setBuyerData] = useState({
|
||||
key,
|
||||
item,
|
||||
buyerType,
|
||||
allocationType,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (getRoleFromUrl() === "Steward") {
|
||||
setValue("free");
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(provincePolicyGetUploadImageService()).then((r) => {
|
||||
if (r.payload?.data) {
|
||||
setImageUploadLimit(r.payload.data.killHouseAllocation);
|
||||
}
|
||||
});
|
||||
|
||||
if (!editData) {
|
||||
dispatch(
|
||||
slaughterGetProductsService({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setProductData(r.payload.data);
|
||||
});
|
||||
if (!item) {
|
||||
if (value === "cold") {
|
||||
dispatch(
|
||||
slaughterGetColdHousesForAllocateService({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setColdHouseData(r.payload.data);
|
||||
});
|
||||
}
|
||||
dispatch(
|
||||
slaughterGetGuildsForAllocateService({
|
||||
free: value === "free" ? true : false,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setGuildsData(r.payload.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [dispatch, value, selectedSubUser?.key]);
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!")
|
||||
.max(
|
||||
editData
|
||||
? remainWeight + editData?.realWeightOfCarcasses
|
||||
: remainWeight,
|
||||
"وزن وارد شده بیش از موجودی انبار است!"
|
||||
),
|
||||
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: {
|
||||
weight: editData?.realWeightOfCarcasses || "",
|
||||
wholePrice: editData?.totalAmount || "",
|
||||
price: editData?.amount || "",
|
||||
image: editData?.image || "",
|
||||
},
|
||||
validationSchema,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (sellGovernmental === "false") {
|
||||
if (formik.values.weight && formik.values.price) {
|
||||
formik.setFieldValue(
|
||||
"wholePrice",
|
||||
formik.values.price * formik.values.weight
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (priceInfo?.active && formik.values.weight) {
|
||||
formik.setFieldValue(
|
||||
"wholePrice",
|
||||
priceInfo?.killHousePrice * formik.values.weight
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [formik.values.price, formik.values.weight, sellGovernmental]);
|
||||
|
||||
useEffect(() => {
|
||||
if (priceInfo?.active && sellGovernmental === "true") {
|
||||
formik.setFieldValue("price", priceInfo?.killHousePrice);
|
||||
}
|
||||
}, [sellGovernmental]);
|
||||
|
||||
const successSubmit = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(
|
||||
fetchSlaughterBroadcastAndProducts({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
fetchApiData && fetchApiData(1);
|
||||
updateTable && updateTable();
|
||||
fetchData && fetchData(1);
|
||||
};
|
||||
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
direction="column"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
>
|
||||
{!editData && (
|
||||
<DatePicker
|
||||
label="تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => <TextField fullWidth {...params} />}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!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 && (
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="own"
|
||||
control={<Radio />}
|
||||
label="صنوف اختصاصی"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="free"
|
||||
control={<Radio />}
|
||||
label="صنوف آزاد"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="cold"
|
||||
control={<Radio />}
|
||||
label="انتقال به سردخانه"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{!item && !editData && value !== "cold" && (
|
||||
<Grid xs={12} container>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="hatching"
|
||||
options={
|
||||
guildsData
|
||||
? guildsData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `${i?.steward ? "مباشر" : "صنف"} ${
|
||||
i?.guildsName
|
||||
} ${i?.user?.fullname} (${i?.user?.mobile})`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setBuyerData({
|
||||
item: value?.data,
|
||||
key: value?.data?.key,
|
||||
allocationType: value?.data?.steward
|
||||
? "killhouse_steward"
|
||||
: "killhouse_guild",
|
||||
buyerType: value?.data?.steward ? "Steward" : "Guild",
|
||||
});
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب مباشر / صنف" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!item && !editData && value === "cold" && (
|
||||
<Grid xs={12} container>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
style={{ minWidth: 210 }}
|
||||
disablePortal
|
||||
id="hatching"
|
||||
options={
|
||||
coldHouseData
|
||||
? coldHouseData.map((i) => {
|
||||
return {
|
||||
data: i,
|
||||
label: `سردخانه ${i?.name} (${
|
||||
i?.steward?.user?.mobile ||
|
||||
i?.killHouse?.killHouseOperator?.user?.mobile
|
||||
})`,
|
||||
};
|
||||
})
|
||||
: []
|
||||
}
|
||||
onChange={(event, value) => {
|
||||
setBuyerData({
|
||||
item: value?.data,
|
||||
key: value?.data?.key,
|
||||
allocationType: "ColdHouse",
|
||||
buyerType: "ColdHouse",
|
||||
});
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField fullWidth {...params} label="انتخاب سردخانه" />
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
id="weight"
|
||||
label="وزن لاشه"
|
||||
variant="outlined"
|
||||
value={formik.values.weight}
|
||||
error={
|
||||
(formik.touched.weight && Boolean(formik.errors.weight)) ||
|
||||
remainWeight <= 0
|
||||
}
|
||||
helperText={
|
||||
remainWeight <= 0
|
||||
? "موجودی انبار کافی نیست"
|
||||
: formik.touched.weight && formik.errors.weight
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
disabled={remainWeight < 1}
|
||||
sx={{
|
||||
"& .MuiFormHelperText-root": {
|
||||
color:
|
||||
remainWeight && formik.values.weight > remainWeight
|
||||
? "error.main"
|
||||
: undefined,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
{priceInfo?.active && (
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
row
|
||||
aria-labelledby="demo-controlled-radio-buttons-group"
|
||||
name="controlled-radio-buttons-group"
|
||||
value={sellGovernmental}
|
||||
onChange={handleChangeSellGovernmental}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="true"
|
||||
control={<Radio />}
|
||||
label="قیمت مصوب"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="false"
|
||||
control={<Radio />}
|
||||
label="قیمت آزاد"
|
||||
/>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
<NumberInput
|
||||
disabled={priceInfo?.active && sellGovernmental === "true"}
|
||||
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)) && (
|
||||
<>
|
||||
<ImageUpload
|
||||
onChange={factorPaymentHandler}
|
||||
images={profileImages}
|
||||
maxNumber={1}
|
||||
title={"بارگزاری سند"}
|
||||
/>
|
||||
{formik.touched.image && Boolean(formik.errors.image) && (
|
||||
<Typography color="error">ثبت تصویر الزامی است</Typography>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
disabled={
|
||||
editData
|
||||
? !formik.isValid
|
||||
: !formik.isValid ||
|
||||
(coldHouseKey ? false : !productKey) ||
|
||||
!buyerData?.item?.key
|
||||
}
|
||||
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,
|
||||
...(imageChanged && { image: formik.values.image }),
|
||||
};
|
||||
} else if (!editData) {
|
||||
req = {
|
||||
seller_type: sellerType,
|
||||
buyer_type: buyerData?.buyerType,
|
||||
other_cold_house_key:
|
||||
buyerData?.buyerType === "ColdHouse"
|
||||
? buyerData?.item?.key
|
||||
: null,
|
||||
guild_key:
|
||||
buyerData?.buyerType === "Guild" ? buyerData?.item?.key : null,
|
||||
steward_key:
|
||||
buyerData?.buyerType === "Steward"
|
||||
? buyerData?.item?.key
|
||||
: null,
|
||||
kill_house_key:
|
||||
buyerData?.buyerType === "KillHouse"
|
||||
? buyerData?.item?.key
|
||||
: null,
|
||||
cold_house_key: coldHouseKey || null,
|
||||
product_key: coldHouseKey ? null : productKey.key,
|
||||
type: "manual",
|
||||
allocation_type: buyerData?.allocationType,
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
sell_type: value === "cold" ? "free" : sellType,
|
||||
amount: formik.values.price,
|
||||
total_amount: formik.values.wholePrice,
|
||||
approved_price_status: sellGovernmental === "true" ? true : false,
|
||||
date: selectedDate1,
|
||||
...(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,
|
||||
total_amount: formik.values.wholePrice,
|
||||
...(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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,223 @@
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetColdHouses } from "../../services/slaughter-get-cold-houses";
|
||||
import { slaughterSubmitAllocateToFreezing } from "../../services/slaughter-submit-allocate-to-freezing";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
LOADING_END,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useFormik } from "formik";
|
||||
import { slaughterUpdateAllocationForFreezing } from "../../services/slaughter-update-allocation-for-freezing";
|
||||
import { slaughterGetProductsService } from "../../services/slaughter-inventory-gets";
|
||||
|
||||
export const SlaughterAllocateToFreezing = ({
|
||||
fetchItems,
|
||||
isEdit,
|
||||
item,
|
||||
updateTable,
|
||||
handleUpdateFreezing,
|
||||
}) => {
|
||||
const [coldHouse, setColdHouse] = useState("");
|
||||
const [coldHouses, setColdHouses] = useState([]);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [productKey, setProductKey] = useState(null);
|
||||
const [productData, setProductData] = useState([]);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (!isEdit) {
|
||||
dispatch(slaughterGetProductsService()).then((r) => {
|
||||
setProductData(r.payload.data);
|
||||
});
|
||||
dispatch(slaughterGetColdHouses()).then((r) => {
|
||||
setColdHouses(r.payload.data);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleChange = (event) => {
|
||||
setColdHouse(event.target.value);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
quantity: item?.quantity ? item?.quantity : "",
|
||||
weight: item?.weight ? item?.weight : "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
quantity: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid container gap={2} xs={12} justifyContent="center">
|
||||
{!isEdit && (
|
||||
<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>
|
||||
)}
|
||||
{!isEdit && (
|
||||
<>
|
||||
<FormControl>
|
||||
<InputLabel id="demo-simple-select-disabled-label">
|
||||
انتخاب سردخانه
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-disabled-label"
|
||||
id="demo-simple-select-disabled"
|
||||
value={coldHouse}
|
||||
label="سردخانه"
|
||||
onChange={handleChange}
|
||||
>
|
||||
{coldHouses?.map((item, i) => {
|
||||
return (
|
||||
<MenuItem
|
||||
key={i}
|
||||
value={item?.key}
|
||||
>{`سردخانه ${item.name}`}</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
label="تعداد"
|
||||
name="quantity"
|
||||
value={formik.values.quantity}
|
||||
onChange={formik.handleChange}
|
||||
error={formik.touched.quantity && Boolean(formik.errors.quantity)}
|
||||
helperText={formik.touched.quantity && formik.errors.quantity}
|
||||
required
|
||||
fullWidth
|
||||
/>
|
||||
<TextField
|
||||
label="وزن"
|
||||
name="weight"
|
||||
value={formik.values.weight}
|
||||
onChange={formik.handleChange}
|
||||
error={formik.touched.weight && Boolean(formik.errors.weight)}
|
||||
helperText={formik.touched.weight && formik.errors.weight}
|
||||
required
|
||||
fullWidth
|
||||
/>
|
||||
<Button
|
||||
disabled={
|
||||
isEdit
|
||||
? !formik.isValid
|
||||
: !coldHouse || !formik.isValid || !productKey
|
||||
}
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
if (isEdit) {
|
||||
dispatch(
|
||||
slaughterUpdateAllocationForFreezing({
|
||||
allocation_key: item?.key,
|
||||
quantity: parseInt(formik.values.quantity),
|
||||
weight: parseInt(formik.values.weight),
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
dispatch(LOADING_END());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(CLOSE_MODAL());
|
||||
fetchItems();
|
||||
updateTable();
|
||||
handleUpdateFreezing();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
slaughterSubmitAllocateToFreezing({
|
||||
cold_house_key: coldHouse,
|
||||
quantity: parseInt(formik.values.quantity),
|
||||
weight: parseInt(formik.values.weight),
|
||||
product_key: productKey?.key,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
dispatch(LOADING_END());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(CLOSE_MODAL());
|
||||
fetchItems();
|
||||
updateTable();
|
||||
handleUpdateFreezing();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,181 @@
|
||||
import { Grid, IconButton, TextField } from "@mui/material";
|
||||
import { ROUTE_SLAUGHTER_FILE } from "../../../../routes/routes";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useFormik } from "formik";
|
||||
import moment from "moment";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetActiveRequests } from "../../services/slaughter-get-active-requests";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import PlagiarismIcon from "@mui/icons-material/Plagiarism";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import SlaughterCheckRequest from "../../../file/components/slaughter-check-request/SlaughterCheckRequest";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterAllocatedCheckRequests = () => {
|
||||
const navigate = useNavigate();
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const { slaughterActiveRequests } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetActiveRequests({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}, [selectedDate1, selectedDate2, selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredData = slaughterActiveRequests?.filter(
|
||||
(item) => item.provinceKillState === "pending"
|
||||
);
|
||||
// const key = "orderCode";
|
||||
// const arrayUniqueByKey = [
|
||||
// ...new Map(filteredData?.map((item) => [item[key], item])).values(),
|
||||
// ];
|
||||
const d = filteredData?.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item.orderCode,
|
||||
item?.freezing ? "انجماد" : item?.export ? "صادرات" : "عادی",
|
||||
item?.freeSaleInProvince === false ? "دولتی" : "آزاد",
|
||||
format(new Date(item?.sendDate), "yyyy/MM/dd"),
|
||||
`${item.poultryName} (${item.poultryMobile})`,
|
||||
`${item.killHouseName} (${item.killHouseMobile})`,
|
||||
item.city,
|
||||
item.province,
|
||||
item.age,
|
||||
item.mainQuantity.toLocaleString() + " قطعه",
|
||||
item.amount.toLocaleString() + " ﷼",
|
||||
item.chickenBreed,
|
||||
item.indexWeight + " کیلوگرم",
|
||||
<IconButton
|
||||
key={i}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "انجام عملیات تخصیص",
|
||||
// right: !(window.innerWidth <= 600),
|
||||
top: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: <SlaughterCheckRequest item={item} i={i} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>,
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() => navigate(ROUTE_SLAUGHTER_FILE + item.poultryReqId)}
|
||||
>
|
||||
<PlagiarismIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTable(d);
|
||||
}, [slaughterActiveRequests]);
|
||||
|
||||
const [tableDataCol] = useState([
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"کشتار",
|
||||
"فروش",
|
||||
"تاریخ درخواست",
|
||||
"مرغدار",
|
||||
"خریدار",
|
||||
"شهر",
|
||||
"استان",
|
||||
"سن مرغ",
|
||||
"تعداد",
|
||||
"قیمت مرغ زنده",
|
||||
"نژاد",
|
||||
"میانگین وزن",
|
||||
"عملیات",
|
||||
"مشاهده",
|
||||
]);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
capacity: "",
|
||||
recieveTime: "",
|
||||
recieveDate: moment(Date()).format("YYYY-MM-DD hh:mm:ss"),
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
capacity: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
recieveTime: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا وزن را وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" gap={SPACING.SMALL} mt={SPACING.MEDIUM}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
title={"درخواست های در انتظار تایید"}
|
||||
columns={tableDataCol}
|
||||
data={dataTable}
|
||||
paginated
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,540 @@
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Pagination,
|
||||
TextField,
|
||||
Tooltip,
|
||||
tooltipClasses,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import axios from "axios";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { PageTable } from "../../../../components/page-table/PageTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import KeyboardDoubleArrowUpIcon from "@mui/icons-material/KeyboardDoubleArrowUp";
|
||||
import KeyboardDoubleArrowDownIcon from "@mui/icons-material/KeyboardDoubleArrowDown";
|
||||
import styled from "styled-components";
|
||||
import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
import { SlaughterUnpaidFeesDetails } from "../slaughter-unpaid-fees-details/SlaughterUnpaidFeesDetails";
|
||||
import { ProvinceArchiveFeeDetails } from "../../../province/components/province-archive-fee-details/ProvinceArchiveFeeDetails";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import BoxList from "../../../../components/box-list/BoxList";
|
||||
import moment from "moment";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
|
||||
export const SlaughterArchivedFees = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const [withDate, setWithDate] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const userInfo = useSelector((state) => state.userSlice);
|
||||
const [dataTableM, setDataTableM] = useState([]);
|
||||
|
||||
const [textValue, setTextValue] = useState("");
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const fetchApiData = async (page, textValue) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(
|
||||
`province_wage/?search=filter&value=${textValue}&page=${page}&page_size=${perPage}&type=archive&role=${getRoleFromUrl()}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setLoading(false);
|
||||
dispatch(LOADING_END());
|
||||
};
|
||||
|
||||
const [page, setPage] = useState(0);
|
||||
const handleChangePageM = (event, newPage) => {
|
||||
dispatch(LOADING_START());
|
||||
setPage(newPage);
|
||||
fetchApiData(newPage + 1, textValue);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page, textValue);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = async (newPerPage, page) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(
|
||||
`province_wage/?search=filter&value=${textValue}&page=${page}&page_size=${newPerPage}&type=archive&role=${getRoleFromUrl()}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}`
|
||||
);
|
||||
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setPerPage(newPerPage);
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, withDate]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`province_wage/?search=filter&value=${textValue}&type=archive&role=${getRoleFromUrl()}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(1);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "کدسفارش",
|
||||
selector: (item) => item?.provinceRequest?.orderCode,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "مرغدار (تلفن)",
|
||||
selector: (item) =>
|
||||
`${item?.provinceRequest?.poultryFullname} (${item?.provinceRequest?.poultryMobile})`,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "شهر",
|
||||
selector: (item) => `${item?.provinceRequest?.poultryCity}`,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "تاریخ کشتار",
|
||||
selector: (item) => formatJustDate(item?.provinceRequest?.sendDate),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "محل کشتار",
|
||||
selector: (item) => item?.provinceRequest?.killPlace,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
},
|
||||
{
|
||||
name: "نژاد",
|
||||
selector: (item) => item?.provinceRequest?.breed,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "تعداد (قطعه)",
|
||||
selector: (item) =>
|
||||
item?.provinceRequest?.provinceKillRequestQuantity?.toLocaleString(),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "وزن (کیلوگرم)",
|
||||
selector: (item) =>
|
||||
item?.provinceRequest?.provinceKillRequestTotalWeight?.toLocaleString(),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "میانگین وزنی (کیلوگرم)",
|
||||
selector: (item) => item?.provinceRequest?.indexWeight,
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "تعرفه اتحادیه (ریال)",
|
||||
selector: (item) => item?.provinceRequest?.wage?.toLocaleString(),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "مبلغ کل تعرفه (ریال)",
|
||||
selector: (item) => (
|
||||
<ProvinceUnpaidFeeView item={item} updateTable={updateTable} />
|
||||
),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "جزییات سفارش",
|
||||
selector: (item) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
top: true,
|
||||
title: "جزییات سفارش",
|
||||
content: <SlaughterUnpaidFeesDetails item={item} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
مشاهده
|
||||
</Button>
|
||||
),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
{
|
||||
name: "اطلاعات بایگانی",
|
||||
selector: (item) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "اطلاعات بایگانی",
|
||||
content: <ProvinceArchiveFeeDetails item={item} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
مشاهده
|
||||
</Button>
|
||||
),
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "90px",
|
||||
},
|
||||
];
|
||||
|
||||
const tableTitle = (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
width="100%"
|
||||
>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Typography>بایگانی</Typography>
|
||||
<Grid
|
||||
container
|
||||
style={{
|
||||
borderStyle: "solid",
|
||||
borderWidth: "1px",
|
||||
padding: "10px",
|
||||
borderRadius: "15px",
|
||||
borderColor: "gray",
|
||||
justifyContent: "left",
|
||||
}}
|
||||
>
|
||||
<Grid>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={withDate}
|
||||
onChange={() => setWithDate(!withDate)}
|
||||
color="primary" // Change the color to your preference
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}kill_house_wage_archive_excel/?key=${userInfo?.userProfile?.key}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
const isMobile = window.innerWidth <= 600;
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
item?.provinceRequest?.orderCode,
|
||||
`${item?.provinceRequest?.poultryFullname} (${item?.provinceRequest?.poultryMobile})`,
|
||||
`${item?.provinceRequest?.poultryCity}`,
|
||||
<ProvinceUnpaidFeeView key={i} item={item} updateTable={updateTable} />,
|
||||
<Button
|
||||
key={i}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
top: true,
|
||||
title: "جزییات سفارش",
|
||||
content: <SlaughterUnpaidFeesDetails item={item} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
مشاهده
|
||||
</Button>,
|
||||
<Button
|
||||
key={i}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "اطلاعات بایگانی",
|
||||
content: <ProvinceArchiveFeeDetails item={item} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
مشاهده
|
||||
</Button>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTableM(d);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
{isMobile ? (
|
||||
<Grid container justifyContent="center" gap={SPACING.SMALL}>
|
||||
{tableTitle}
|
||||
<BoxList
|
||||
columns={[
|
||||
"عملیات",
|
||||
"ردیف",
|
||||
"نام فارم",
|
||||
"مرغدار",
|
||||
"شهر/تعاونی",
|
||||
"تاریخ جوجه ریزی",
|
||||
"نژاد",
|
||||
"سن",
|
||||
"تعداد جوجه ریزی",
|
||||
"مانده در سالن",
|
||||
]}
|
||||
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>
|
||||
);
|
||||
};
|
||||
|
||||
const ProvinceUnpaidFeeView = ({ item, updateTable }) => {
|
||||
const isBigger =
|
||||
item?.provinceRequest.prevTotalAmount < item?.provinceRequest.totalAmount;
|
||||
const isSmaller =
|
||||
item?.provinceRequest.prevTotalAmount > item?.provinceRequest.totalAmount;
|
||||
|
||||
const prevTotalAmount = (
|
||||
<Grid container direction="column">
|
||||
<Grid>{isBigger && "افزایش یافته"}</Grid>
|
||||
<Grid>{isSmaller && "کاهش یافته"}</Grid>
|
||||
<Grid>
|
||||
مبلغ اولیه: {item?.provinceRequest?.prevTotalAmount?.toLocaleString()} ﷼
|
||||
</Grid>
|
||||
<Grid>ویرایش کننده: {item?.totalAmountEditor?.fullname}</Grid>
|
||||
<Grid>تاریخ ویرایش: {formatJustDate(item?.totalAmountEditor?.date)}</Grid>
|
||||
<Grid>سمت: {getFaUserRole(item?.totalAmountEditor?.role)}</Grid>
|
||||
<Grid>تلفن: {item?.totalAmountEditor?.mobile}</Grid>
|
||||
</Grid>
|
||||
);
|
||||
return (
|
||||
<Grid container alignItems="center" direction="column">
|
||||
{Boolean(item?.provinceRequest?.prevTotalAmount) && isBigger && (
|
||||
<Grid container alignItems="center">
|
||||
<KeyboardDoubleArrowUpIcon style={{ color: "red" }} />
|
||||
<HtmlTooltip title={prevTotalAmount}>
|
||||
<Typography style={{ color: "red" }} variant="caption">
|
||||
{item?.provinceRequest?.totalAmount?.toLocaleString()}
|
||||
</Typography>
|
||||
</HtmlTooltip>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{Boolean(item?.provinceRequest?.prevTotalAmount) && isSmaller && (
|
||||
<Grid container alignItems="center">
|
||||
<KeyboardDoubleArrowDownIcon style={{ color: "green" }} />
|
||||
<Tooltip title={prevTotalAmount}>
|
||||
<Typography style={{ color: "green" }} variant="caption">
|
||||
{item?.provinceRequest?.totalAmount?.toLocaleString()}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{!item?.provinceRequest?.prevTotalAmount && (
|
||||
<Typography color={"success"} variant="caption">
|
||||
{item?.provinceRequest?.totalAmount?.toLocaleString()}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
const HtmlTooltip = styled(({ className, ...props }) => (
|
||||
<Tooltip {...props} classes={{ popper: className }} />
|
||||
))(({ theme }) => ({
|
||||
[`& .${tooltipClasses.tooltip}`]: {
|
||||
backgroundColor: "#f5f5f9",
|
||||
color: "rgba(0, 0, 0, 0.87)",
|
||||
maxWidth: 220,
|
||||
border: "1px solid #dadde9",
|
||||
},
|
||||
}));
|
||||
@@ -0,0 +1,133 @@
|
||||
import { Card, IconButton, TextField, Typography } from "@mui/material";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import PlagiarismIcon from "@mui/icons-material/Plagiarism";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ROUTE_SLAUGHTER_FILE } from "../../../../routes/routes";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import moment from "moment/moment";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { avicultureGetRequests } from "../../../aviculture/services/aviculture-requests";
|
||||
|
||||
export const SlaughterArchivedRequests = () => {
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const { avicultureRequests } = useSelector((state) => state.avicultureSlice);
|
||||
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(avicultureGetRequests({ selectedDate1, selectedDate2 })).then(
|
||||
() => {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
);
|
||||
}, [selectedDate1, selectedDate2]);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredData = avicultureRequests?.filter(
|
||||
(item, i) => item.inspector != null
|
||||
);
|
||||
const d = filteredData?.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item.orderCode,
|
||||
formatJustDate(item?.createDate),
|
||||
formatJustDate(item?.sendDate),
|
||||
item?.process?.poultry?.poultryName,
|
||||
item?.process?.poultry?.poultryMobile,
|
||||
item?.process?.poultry?.poultryCity,
|
||||
item?.process?.poultry?.poultryProvince,
|
||||
item?.process?.poultry?.age,
|
||||
item?.process?.poultry?.poultryQuantity,
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() =>
|
||||
navigate(
|
||||
ROUTE_SLAUGHTER_FILE + item?.process?.poultry?.poultryRequestId
|
||||
)
|
||||
}
|
||||
>
|
||||
<PlagiarismIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTable(d);
|
||||
}, [avicultureRequests]);
|
||||
|
||||
const [tableDataCol] = useState([
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"تاریخ ثبت درخواست",
|
||||
"تاریخ درخواست",
|
||||
"مرغدار",
|
||||
"تلفن مرغدار",
|
||||
"شهر",
|
||||
"استان",
|
||||
"سن مرغ",
|
||||
"تعداد",
|
||||
"مشاهده",
|
||||
]);
|
||||
return (
|
||||
<Card>
|
||||
<AdvancedTable
|
||||
name={
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<Typography>درخواست های بایگانی شده</Typography>
|
||||
</Grid>
|
||||
<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>
|
||||
</Grid>
|
||||
}
|
||||
expandable
|
||||
columns={tableDataCol}
|
||||
data={dataTable}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,109 @@
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useState, useEffect } from "react";
|
||||
import { slaughterGetKillHouseLockInfoService } from "../../services/slaughter-get-kill-house-lock-info";
|
||||
import lockDollarIcon from "../../../../assets/images/lock-dollar.svg";
|
||||
import lockAnbarIcon from "../../../../assets/images/lock-anbar.svg";
|
||||
|
||||
export const SlaughterBalanceStatusButton = () => {
|
||||
const userRoles = useSelector((state) => state.userSlice.role);
|
||||
const [lockInfo, setLockInfo] = useState(null);
|
||||
|
||||
const hasOnlyKillHouseRole = userRoles && userRoles.includes("KillHouse");
|
||||
|
||||
useEffect(() => {
|
||||
if (hasOnlyKillHouseRole) {
|
||||
const fetchLockInfo = async () => {
|
||||
try {
|
||||
const data = await slaughterGetKillHouseLockInfoService();
|
||||
setLockInfo(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching lock info:", error);
|
||||
setLockInfo(null);
|
||||
}
|
||||
};
|
||||
fetchLockInfo();
|
||||
}
|
||||
}, [hasOnlyKillHouseRole, userRoles]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: { xs: "fit-content" },
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 0.25,
|
||||
px: { xs: 1, md: 2 },
|
||||
height: { xs: "36px", md: "46px" },
|
||||
borderRadius: { xs: "8px", md: "12px" },
|
||||
cursor: "pointer",
|
||||
transition: "all 0.3s ease",
|
||||
border: "0.25px solid rgba(151, 151, 151, 0.3)",
|
||||
"&:hover": {
|
||||
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
||||
},
|
||||
}}
|
||||
style={{
|
||||
background:
|
||||
"linear-gradient(90deg, #FFFFFF 0%, #FFF4F4 78.85%, #FFE2E2 100%)",
|
||||
}}
|
||||
>
|
||||
{lockInfo?.wageLock && (
|
||||
<Box
|
||||
component="img"
|
||||
src={lockDollarIcon}
|
||||
alt="dollar"
|
||||
sx={{
|
||||
width: { xs: "22px", md: "30px" },
|
||||
height: { xs: "22px", md: "30px" },
|
||||
marginLeft: { xs: "8px", md: "8px" },
|
||||
}}
|
||||
title="به علت بدهی"
|
||||
/>
|
||||
)}
|
||||
{lockInfo?.wareHouseLock && (
|
||||
<Box
|
||||
component="img"
|
||||
src={lockAnbarIcon}
|
||||
alt="anbar"
|
||||
sx={{
|
||||
width: { xs: "22px", md: "30px" },
|
||||
height: { xs: "22px", md: "30px" },
|
||||
marginLeft: { xs: "12px", md: "12px" },
|
||||
marginRight: { xs: "12px", md: "16px" },
|
||||
}}
|
||||
title="به علت پر بودن انبار"
|
||||
/>
|
||||
)}
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
color:
|
||||
lockInfo?.wageLock === true
|
||||
? "rgba(235, 87, 87, 1)"
|
||||
: "rgba(0, 0, 0, 1)",
|
||||
fontWeight: "medium",
|
||||
fontSize: { xs: "14px", md: "18px" },
|
||||
marginLeft: { xs: "auto", sm: 0 },
|
||||
}}
|
||||
>
|
||||
{(lockInfo?.wage || 0).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
color:
|
||||
lockInfo?.wageLock === true
|
||||
? "rgba(235, 87, 87, 1)"
|
||||
: "rgba(0, 0, 0, 1)",
|
||||
fontWeight: "medium",
|
||||
fontSize: { xs: "10px", md: "12px" },
|
||||
marginLeft: "2px",
|
||||
marginTop: { xs: "1px", md: "2px" },
|
||||
}}
|
||||
>
|
||||
ریال
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,878 @@
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Pagination,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
// import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
// import { vetFarmGetAllocatedService } from "../../services/vet-farm-get-allocated";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import CancelIcon from "@mui/icons-material/Delete";
|
||||
import moment from "moment/moment";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import axios from "axios";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
// import { getFaUserRole } from "../../../../utils/getFaUserRole";
|
||||
import { PageTable } from "../../../../components/page-table/PageTable";
|
||||
import { SimpleTable } from "../../../../components/simple-table/SimpleTable";
|
||||
import { VetFarmCancelBar } from "../../../vet-farm/components/vet-farm-cancel-bar/VetFarmCancelBar";
|
||||
import { VetFarmEditTrafficCode } from "../../../vet-farm/components/vet-farm-edit-traffic-code/VetFarmEditTrafficCode";
|
||||
import { VetFarmDeletedBars } from "../../../vet-farm/components/vet-farm-deleted-bars/VetFarmDeletedBars";
|
||||
import { ProvinceBarDifference } from "../../../province/components/province-bar-difference/ProvinceBarDifference";
|
||||
import { CheckCleanceCode } from "../../../../components/check-clearance-code/ChechClearanceCode";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SlaughterBarDashboardService } from "../../services/slaughter-bar-dashbored";
|
||||
import { SlaughterEnterNoneReciept } from "../slaughter-enter-none-receipt/SlaughterEnterNoneReciept";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterBars = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
|
||||
const handleTabChange = (event, newValue) => {
|
||||
setSelectedTab(newValue);
|
||||
};
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [dataTableM, setDataTableM] = useState([]);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(
|
||||
`kill_house_request_bar_management/?check&search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setLoading(false);
|
||||
dispatch(LOADING_END());
|
||||
};
|
||||
|
||||
const [page, setPage] = useState(0);
|
||||
const handleChangePageM = (event, newPage) => {
|
||||
dispatch(LOADING_START());
|
||||
setPage(newPage);
|
||||
fetchApiData(newPage + 1, textValue);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = async (newPerPage, page) => {
|
||||
setLoading(true);
|
||||
const response = await axios.get(
|
||||
`kill_house_request_bar_management/?check&search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${newPerPage}`
|
||||
);
|
||||
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
setPerPage(newPerPage);
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
// const updateTable = () => {
|
||||
// fetchApiData(1);
|
||||
// };
|
||||
const btnDisabled = !(
|
||||
getRoleFromUrl() === "ProvinceOperator" || getRoleFromUrl() === "CityVet"
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "کدبار",
|
||||
selector: (item) => {
|
||||
return item.barCode;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
name: "خریدار",
|
||||
selector: (item) => {
|
||||
return `${item.killhouseUser?.name} (${item.killhouseUser?.killHouseOperator?.user?.mobile})`;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "کشتارکن اختصاصی",
|
||||
selector: (item) => {
|
||||
return item?.killer
|
||||
? `${item?.killer?.name} (${item?.killer?.killHouseOperator?.user?.mobile})`
|
||||
: "-";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "ماشین",
|
||||
selector: (item) => {
|
||||
return `${item.addCar.driver.typeCar} ${item.addCar.driver.pelak}`;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
name: "راننده",
|
||||
selector: (item) => {
|
||||
return `${item.addCar.driver.driverName} (${item.addCar.driver.driverMobile})`;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "کد بهداشتی حمل و نقل",
|
||||
selector: (item) => {
|
||||
return item?.trafficCode;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "قیمت مرغ زندهی بار",
|
||||
selector: (item) => {
|
||||
return item?.amount?.toLocaleString() + " ﷼";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
// width: "80px",
|
||||
},
|
||||
{
|
||||
name: "نژاد",
|
||||
selector: (item) => {
|
||||
return item.poultryRequest.chickenBreed;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "50px",
|
||||
},
|
||||
{
|
||||
name: "تعداد اولیه",
|
||||
selector: (item) => {
|
||||
return item.quantity?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "50px",
|
||||
},
|
||||
{
|
||||
name: "وزن اولیه بار (کیلوگرم)",
|
||||
selector: (item) => {
|
||||
return item?.weightInfo?.weight?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
{
|
||||
name: "میانگین وزن اولیه (کیلوگرم)",
|
||||
selector: (item) => {
|
||||
return item?.weightInfo?.indexWeight?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
{
|
||||
name: "قیمت مرغدار",
|
||||
selector: (item) => {
|
||||
return item?.poultryRequest?.amount?.toLocaleString() + " ﷼";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "قیمت کشتارگاه",
|
||||
selector: (item) => {
|
||||
return item?.weightInfo?.killHousePrice?.toLocaleString() + " ﷼";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "مرغدار",
|
||||
selector: (item) => {
|
||||
return `${item.poultryRequest?.poultry?.unitName} (${item.poultryRequest.poultry?.user?.mobile})`;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "دامپزشک فارم",
|
||||
selector: (item) => {
|
||||
return item?.vetFarm?.vet?.user?.fullname
|
||||
? item?.vetFarm?.vet?.user?.fullname +
|
||||
`(${item?.vetFarm?.vet?.user?.mobile})`
|
||||
: "فاقد دامپزشک";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "100px",
|
||||
},
|
||||
{
|
||||
name: "کدرهگیری سامانه قرنطینه",
|
||||
selector: (item) => {
|
||||
return (
|
||||
<>
|
||||
{getRoleFromUrl() === "VetFarm" ||
|
||||
getRoleFromUrl() === "ProvinceOperator" ||
|
||||
getRoleFromUrl() === "CityVet" ||
|
||||
getRoleFromUrl() === "VetSupervisor" ? (
|
||||
<>
|
||||
{item?.registerar?.date
|
||||
? `${format(
|
||||
new Date(item?.registerar?.date),
|
||||
"yyyy/MM/dd"
|
||||
)} ${item?.registerar?.name}`
|
||||
: ""}
|
||||
</>
|
||||
) : item?.clearanceCode ? (
|
||||
item?.clearanceCode && (
|
||||
<CheckCleanceCode clearanceCode={item?.clearanceCode} />
|
||||
)
|
||||
) : (
|
||||
"-"
|
||||
)}
|
||||
</>
|
||||
);
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "200px",
|
||||
},
|
||||
{
|
||||
name: "محل کشتار",
|
||||
selector: (item) => {
|
||||
return `${item.killPlace}`;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "شهر",
|
||||
selector: (item) => {
|
||||
return item.poultryRequest.poultry.address.city.name;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "تاریخ کشتار",
|
||||
selector: (item) => {
|
||||
return item?.poultryRequest.sendDate
|
||||
? format(new Date(item?.poultryRequest.sendDate), "yyyy/MM/dd")
|
||||
: "-";
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "80px",
|
||||
},
|
||||
{
|
||||
name: "کدسفارش کشتار",
|
||||
selector: (item) => {
|
||||
return item?.poultryRequest.orderCode;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
{
|
||||
name: "تعداد نهایی",
|
||||
selector: (item) => {
|
||||
return item.acceptedRealQuantity?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "50px",
|
||||
},
|
||||
{
|
||||
name: "وزن نهایی بار (کیلوگرم)",
|
||||
selector: (item) => {
|
||||
return item?.acceptedRealWeight?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
{
|
||||
name: "میانگین وزن نهایی (کیلوگرم)",
|
||||
selector: (item) => {
|
||||
return item?.weightInfo?.finalIndexWeight?.toLocaleString();
|
||||
},
|
||||
sortable: true,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
{
|
||||
name: "وضعیت",
|
||||
selector: (item) => {
|
||||
let state = "";
|
||||
if (item.vetState === "accepted") {
|
||||
state = "تایید تخلیه";
|
||||
} else if (item.vetState === "pending") {
|
||||
state = "در انتظار تخلیه";
|
||||
}
|
||||
return state;
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "90px",
|
||||
},
|
||||
{
|
||||
name: "عملیات",
|
||||
selector: (item) => {
|
||||
return (
|
||||
<Grid key={item.barCode}>
|
||||
<Tooltip title="لغو بار">
|
||||
<IconButton
|
||||
disabled={btnDisabled}
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "لغو بار",
|
||||
content: (
|
||||
<VetFarmCancelBar
|
||||
updateTable={updateTable}
|
||||
killHouseRequestKey={item.key}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<CancelIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
);
|
||||
},
|
||||
sortable: false,
|
||||
wrap: true,
|
||||
allowOverflow: true,
|
||||
center: true,
|
||||
width: "70px",
|
||||
},
|
||||
];
|
||||
|
||||
const handleDateChange1 = (date) => {
|
||||
setSelectedDate1(date);
|
||||
};
|
||||
|
||||
const handleDateChange2 = (date) => {
|
||||
setSelectedDate2(date);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage, selectedSubUser?.key]);
|
||||
|
||||
const [textValue, setTextValue] = useState("");
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
dispatch(
|
||||
SlaughterBarDashboardService({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
textValue,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}, [dispatch, selectedDate1, selectedDate2, selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`kill_house_request_bar_management/?check&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${1}&page_size=${perPage}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(
|
||||
SlaughterBarDashboardService({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
textValue,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(1);
|
||||
};
|
||||
|
||||
const tableTitle = (
|
||||
<Grid
|
||||
container
|
||||
alignItems="start"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Typography>مدیریت بارها</Typography>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
handleDateChange1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
handleDateChange2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}bar_excel/?start=${selectedDate1}&end=${selectedDate2}&key=${userKey}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button disabled={!data[0]?.killhouseUser?.key} color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
|
||||
const getItemState = (item) => {
|
||||
let state = "";
|
||||
if (item.vetState === "accepted") {
|
||||
state = "تایید تخلیه";
|
||||
} else if (item.vetState === "pending") {
|
||||
state = "در انتظار تخلیه";
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const columnNames = columns.map((column) => column.name);
|
||||
const isMobile = window.innerWidth <= 600;
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
item.barCode,
|
||||
`${item.killhouseUser?.name} (${item.killhouseUser?.killHouseOperator?.user?.mobile})`,
|
||||
`${item.addCar.driver.typeCar} ${item.addCar.driver.pelak}`,
|
||||
`${item.addCar.driver.driverName} (${item.addCar.driver.driverMobile})`,
|
||||
<VetFarmEditTrafficCode
|
||||
key={i}
|
||||
updateTable={updateTable}
|
||||
killHouseRequestKey={item.key}
|
||||
trafficCode={item?.trafficCode}
|
||||
isEditable={
|
||||
getRoleFromUrl() === "VetFarm" ||
|
||||
getRoleFromUrl() === "ProvinceOperator" ||
|
||||
getRoleFromUrl() === "KillHouseVet" ||
|
||||
getRoleFromUrl() === "KillHouse" ||
|
||||
getRoleFromUrl() === "CityVet" ||
|
||||
getRoleFromUrl() === "VetSupervisor"
|
||||
}
|
||||
/>,
|
||||
item.poultryRequest.chickenBreed,
|
||||
item.quantity?.toLocaleString(),
|
||||
item?.weightInfo?.weight?.toLocaleString(),
|
||||
item?.weightInfo?.indexWeight?.toLocaleString(),
|
||||
`${item.poultryRequest?.poultry?.unitName} (${item.poultryRequest.poultry?.user?.mobile})`,
|
||||
item?.vetFarm?.vet?.user?.fullname
|
||||
? item?.vetFarm?.vet?.user?.fullname +
|
||||
`(${item?.vetFarm?.vet?.user?.mobile})`
|
||||
: "فاقد دامپزشک",
|
||||
<>
|
||||
{getRoleFromUrl() === "VetFarm" ||
|
||||
getRoleFromUrl() === "ProvinceOperator" ||
|
||||
getRoleFromUrl() === "CityVet" ||
|
||||
getRoleFromUrl() === "VetSupervisor" ? (
|
||||
<>
|
||||
{item?.registerar?.date
|
||||
? `${format(new Date(item?.registerar?.date), "yyyy/MM/dd")} ${
|
||||
item?.registerar?.name
|
||||
}`
|
||||
: ""}
|
||||
</>
|
||||
) : item?.clearanceCode ? (
|
||||
item?.clearanceCode
|
||||
) : (
|
||||
"-"
|
||||
)}
|
||||
</>,
|
||||
`${item.killPlace}`,
|
||||
item.poultryRequest.poultry.address.city.name,
|
||||
item?.poultryRequest.sendDate
|
||||
? format(new Date(item?.poultryRequest.sendDate), "yyyy/MM/dd")
|
||||
: "-",
|
||||
item?.poultryRequest.orderCode,
|
||||
getItemState(item),
|
||||
<Grid key={item.barCode}>
|
||||
<Tooltip title="لغو بار">
|
||||
<IconButton
|
||||
disabled={btnDisabled}
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "لغو بار",
|
||||
content: (
|
||||
<VetFarmCancelBar
|
||||
updateTable={updateTable}
|
||||
killHouseRequestKey={item.key}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<CancelIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTableM(d);
|
||||
}, [data]);
|
||||
|
||||
const tabs = (
|
||||
<Tabs
|
||||
scrollButtons="auto"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
value={selectedTab}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
<Tab label="اطلاعات بارها" value={0} />
|
||||
<Tab label="بارهای حذف شده" value={1} />
|
||||
<Tab label="اختلاف کشتار" value={2} />
|
||||
<Tab label="عدم وصول" value={3} />
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" flexWrap="nowrap" mt={SPACING.SMALL}>
|
||||
<Grid container justifyContent="center" mb={SPACING.MEDIUM}>
|
||||
{tabs}
|
||||
</Grid>
|
||||
|
||||
{selectedTab === 0 && (
|
||||
<Grid
|
||||
container
|
||||
mt={SPACING.MEDIUM}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={[
|
||||
"تعداد بار",
|
||||
"تعداداولیه بار",
|
||||
"وزن اولیه بار",
|
||||
"میانگین وزن اولیه",
|
||||
"تعداد بار های دارای کد قرنطینه",
|
||||
"تعداد نهایی بار",
|
||||
"وزن نهایی بار",
|
||||
"میانگین وزن نهایی ",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.count?.toLocaleString(),
|
||||
dashboardData?.firstQuantity?.toLocaleString(),
|
||||
dashboardData?.firstWeight?.toLocaleString(),
|
||||
dashboardData?.firstIndexWeight?.toLocaleString(),
|
||||
dashboardData?.clearanceCodeCount?.toLocaleString(),
|
||||
dashboardData?.acceptedRealQuantity?.toLocaleString(),
|
||||
dashboardData?.acceptedRealWeight?.toLocaleString(),
|
||||
dashboardData?.finalIndexWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
{isMobile ? (
|
||||
<Grid container justifyContent="center" gap={SPACING.SMALL}>
|
||||
{tableTitle}
|
||||
<SimpleTable 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}
|
||||
/>
|
||||
)}
|
||||
{/* <AdvancedTable
|
||||
name={
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<Typography>مدیریت بارها</Typography>
|
||||
</Grid>
|
||||
<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>
|
||||
{getRoleFromUrl() === "ProvinceOperator" && (
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${axios.defaults.baseURL}bar_excel/?start=${selectedDate1}&end=${selectedDate2}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Grid>
|
||||
}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"کدبار",
|
||||
"دامپزشک فارم",
|
||||
"ماشین",
|
||||
"راننده",
|
||||
// "کد بهداشتی",
|
||||
"خریدار",
|
||||
"محل کشتار",
|
||||
"مرغدار",
|
||||
"شهر",
|
||||
"تاریخ کشتار",
|
||||
"کدسفارش کشتار",
|
||||
"نژاد",
|
||||
"تعداد",
|
||||
"کد بهداشتی حمل و نقل",
|
||||
"کدرهگیری سامانه قرنطینه",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
data={dataTable}
|
||||
/> */}
|
||||
</Grid>
|
||||
)}
|
||||
{selectedTab === 1 && (
|
||||
<Grid mt={SPACING.MEDIUM}>
|
||||
<VetFarmDeletedBars />
|
||||
</Grid>
|
||||
)}
|
||||
{selectedTab === 2 && (
|
||||
<Grid mt={SPACING.MEDIUM}>
|
||||
<ProvinceBarDifference />
|
||||
</Grid>
|
||||
)}
|
||||
{selectedTab === 3 && (
|
||||
<Grid mt={SPACING.MEDIUM}>
|
||||
<SlaughterEnterNoneReciept />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
// const DisabledWrap = ({ children, checked }) => {
|
||||
// return <Grid style={{ opacity: !checked ? 0.5 : 1 }}>{children}</Grid>;
|
||||
// };
|
||||
@@ -0,0 +1,136 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import { Button, IconButton, Popover } from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteAllocatedService } from "../../services/salughter-delete-allocated";
|
||||
import { SlaughterAllocateToGuild } from "../slaughter-allocate-to-guild/SlaughterAllocateToGuild";
|
||||
|
||||
export const SlaughterColdHouseBarsOperations = ({
|
||||
fetchApiData,
|
||||
item,
|
||||
fetchData,
|
||||
updateTable,
|
||||
priceInfo,
|
||||
remainWeight,
|
||||
}) => {
|
||||
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 [openNotif] = useContext(AppContext);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<IconButton
|
||||
disabled={item?.registrationCode}
|
||||
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}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "20px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Grid container direction="column" gap={1}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش تخصیص",
|
||||
content: (
|
||||
<SlaughterAllocateToGuild
|
||||
updateTable={fetchData}
|
||||
fetchApiData={fetchApiData}
|
||||
sellerType={"ColdHouse"}
|
||||
sellType="exclusive"
|
||||
coldHouseItemKey={item?.key}
|
||||
priceInfo={priceInfo}
|
||||
editData={item}
|
||||
remainWeight={remainWeight}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item?.registrationCode}
|
||||
variant="outlined"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
slaughterDeleteAllocatedService({
|
||||
steward_allocation_key: item.key,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
fetchApiData(1);
|
||||
fetchData();
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
حذف
|
||||
</Button>
|
||||
</Grid>
|
||||
</div>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,414 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import axios from "axios";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { SlaughterColdHouseBarsOperations } from "../slaughter-cold-house-bars-operations/SlaughterColdHouseBarsOperations";
|
||||
import { getKillhouseApprovedPriceState } from "../../../province/services/get-approved-price-state";
|
||||
import { slaughterInventoryFinalSubmitService } from "../../services/slaughter-inventory-final-submit";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { SlaughterAllocateToColdHouse } from "../slaughter-allocate-to-coldhouse/SlaughterAllocateToColdHouse";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
export const SlaughterColdHouseBars = ({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
title,
|
||||
type,
|
||||
withDate,
|
||||
coldHouseKey,
|
||||
getDashboardsData,
|
||||
remainWeight,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const { priceInfo } = useSelector((state) => state.slaughterSlice);
|
||||
|
||||
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 fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`steward-allocation/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&page=${page}&page_size=${perPage}&cold_house=true&type=${type}&cold_house_key=${coldHouseKey}`
|
||||
);
|
||||
dispatch(
|
||||
getKillhouseApprovedPriceState({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
const getLastItem = (item) => {
|
||||
if (item?.systemRegistrationCode) {
|
||||
return [
|
||||
<IconButton
|
||||
key={item}
|
||||
disabled={true}
|
||||
aria-label="disabled-button"
|
||||
color="primary"
|
||||
>
|
||||
<TuneIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
<SlaughterColdHouseBarsOperations
|
||||
key={item}
|
||||
fetchData={updateTable}
|
||||
fetchApiData={getDashboardsData}
|
||||
item={item}
|
||||
priceInfo={priceInfo}
|
||||
remainWeight={remainWeight}
|
||||
/>,
|
||||
];
|
||||
}
|
||||
};
|
||||
const getLastItemTitle = () => {
|
||||
if (type === "output") {
|
||||
return ["عملیات"];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
const isOut = title === "بارهای خارج شده";
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
let registrationCodeStatus;
|
||||
switch (item?.receiverState) {
|
||||
case "pending":
|
||||
registrationCodeStatus = "در انتظار تایید";
|
||||
break;
|
||||
case "accepted":
|
||||
registrationCodeStatus = "تایید شده";
|
||||
break;
|
||||
|
||||
case "rejected":
|
||||
registrationCodeStatus = "رد شده";
|
||||
break;
|
||||
default:
|
||||
registrationCodeStatus = "-";
|
||||
}
|
||||
|
||||
console.log(item);
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
formatJustDate(item?.date),
|
||||
isOut
|
||||
? item?.toGuilds
|
||||
? "سردخانه به صنف"
|
||||
: item?.otherColdHouse
|
||||
? "سردخانه به سردخانه"
|
||||
: item?.toStewards
|
||||
? "سردخانه به مباشر"
|
||||
: "-"
|
||||
: `${item?.killHouse ? "کشتارگاه" : "سردخانه"} به سردخانه`,
|
||||
isOut
|
||||
? item?.toGuilds
|
||||
? `${item?.toGuilds?.guildsName} ( ${item?.toGuilds?.user?.fullname} ${item?.toGuilds?.user?.mobile})`
|
||||
: item?.otherColdHouse
|
||||
? item?.otherColdHouse?.steward
|
||||
? `${item?.otherColdHouse?.steward?.user?.fullname} (${item?.otherColdHouse?.steward?.user?.mobile})`
|
||||
: `${item?.otherColdHouse?.killHouse?.name} (${item?.otherColdHouse?.killHouse?.killHouseOperator?.user?.fullname} ${item?.otherColdHouse?.killHouse?.killHouseOperator?.user?.mobile})`
|
||||
: `${item?.toStewards?.name} (${item?.toStewards?.user?.fullname}${item?.toStewards?.user?.mobile})`
|
||||
: item?.killHouse
|
||||
? `${item.toColdHouse?.name} (${item.toColdHouse?.killHouse?.killHouseOperator?.user?.mobile})`
|
||||
: `${item?.otherColdHouse?.name} ${item?.otherColdHouse?.killHouse?.killHouseOperator?.user?.mobile}`,
|
||||
item?.sellType === "exclusive" ? "اختصاصی" : "آزاد",
|
||||
item?.amount?.toLocaleString() + " ریال",
|
||||
item?.totalAmount?.toLocaleString() + " ریال",
|
||||
// item?.realNumberOfCarcasses?.toLocaleString(),
|
||||
item?.realWeightOfCarcasses?.toLocaleString(),
|
||||
item?.loggedRegistrationCode?.toLocaleString(),
|
||||
item?.systemRegistrationCode === true
|
||||
? "کد احراز ارسال شده"
|
||||
: "در انتظار ارسال کد احراز",
|
||||
|
||||
registrationCodeStatus,
|
||||
// item?.receiverRealNumberOfCarcasses?.toLocaleString(),
|
||||
// item?.receiverRealWeightOfCarcasses?.toLocaleString(),
|
||||
...getLastItem(item),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [
|
||||
dispatch,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
withDate,
|
||||
selectedSubUser?.key,
|
||||
]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`steward-allocation/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&page=${1}&page_size=${perPage}&cold_house=true&type=${type}&cold_house_key=${coldHouseKey}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت توزیع/ فروش سرد خانه",
|
||||
content: (
|
||||
<SlaughterAllocateToColdHouse
|
||||
updateTable={getDashboardsData}
|
||||
sellerType={"ColdHouse"}
|
||||
sellType="exclusive"
|
||||
fetchApiData={fetchApiData}
|
||||
coldHouseKey={coldHouseKey}
|
||||
remainWeight={remainWeight}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت توزیع/ فروش
|
||||
</Button>
|
||||
|
||||
{type === "output" && (
|
||||
<Button
|
||||
disabled={!tableData.length}
|
||||
variant="outlined"
|
||||
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(
|
||||
slaughterInventoryFinalSubmitService({
|
||||
steward_allocation_list: data.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 {
|
||||
updateTable();
|
||||
fetchApiData(1);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تایید نهایی (یکجا)
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
{/* <a
|
||||
href={`${axios.defaults.baseURL}0/hatching_excel/`}
|
||||
rel="noreferrer"
|
||||
> */}
|
||||
<Button
|
||||
color="success"
|
||||
onClick={() => {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "فایل اکسل در حال دانلود می باشد، این علمیات ممکن است زمان بر باشد لطفا صبر کنید.",
|
||||
severity: "success",
|
||||
});
|
||||
const link = `${
|
||||
axios.defaults.baseURL
|
||||
}cold_house_excel/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&key=${userKey}&type=${type}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&cold_house_key=${coldHouseKey}&cold_house=true`;
|
||||
window.location.href = link;
|
||||
}}
|
||||
>
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
{/* </a> */}
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ثبت",
|
||||
"نوع تخصیص",
|
||||
"مشخصات خریدار",
|
||||
"نوع فروش",
|
||||
"قیمت هر کیلو",
|
||||
"قیمت کل",
|
||||
// "حجم تخصیصی",
|
||||
"وزن تخصیصی",
|
||||
"کد احراز",
|
||||
"وضعیت کد احراز",
|
||||
"وضعیت",
|
||||
// "حجم تایید شده",
|
||||
// "وزن تایید شده",
|
||||
...getLastItemTitle(),
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title={title}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,118 @@
|
||||
// import { Button, IconButton, Popover, Tooltip } from "@mui/material";
|
||||
// import { useContext, useState } from "react";
|
||||
// import TuneIcon from "@mui/icons-material/Tune";
|
||||
// import { Grid } from "../../../../components/grid/Grid";
|
||||
// import DeleteIcon from "@mui/icons-material/Delete";
|
||||
// import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
// import { slaughterDeleteDailyListService } from "../../services/slaughter-add-daily-list";
|
||||
// import { useDispatch } from "react-redux";
|
||||
// import { AppContext } from "../../../../contexts/AppContext";
|
||||
|
||||
// export const SlaughterDailyListOperation = ({ item, updateTable }) => {
|
||||
// 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 [openNotif] = useContext(AppContext);
|
||||
// return (
|
||||
// <div>
|
||||
// <IconButton
|
||||
// aria-describedby={id}
|
||||
// variant="contained"
|
||||
// color="primary"
|
||||
// onClick={handleClick}
|
||||
// >
|
||||
// <TuneIcon />
|
||||
// </IconButton>
|
||||
// <Popover
|
||||
// anchorOrigin={{
|
||||
// vertical: "top",
|
||||
// horizontal: "center",
|
||||
// }}
|
||||
// transformOrigin={{
|
||||
// vertical: "top",
|
||||
// horizontal: "left",
|
||||
// }}
|
||||
// id={id}
|
||||
// open={open}
|
||||
// anchorEl={anchorEl}
|
||||
// onClose={handleClose}
|
||||
// >
|
||||
// <div style={{ padding: "20px" }}>
|
||||
// <Grid container direction="column">
|
||||
// <Tooltip title={"حذف"} placement="left-start">
|
||||
// <IconButton
|
||||
// aria-label="delete"
|
||||
// color="error"
|
||||
// onClick={() => {
|
||||
// handleClose();
|
||||
// dispatch(
|
||||
// OPEN_MODAL({
|
||||
// title: "آیا مطمئن هستید؟",
|
||||
// content: (
|
||||
// <Grid container spacing={2}>
|
||||
// <Grid item>
|
||||
// <Button
|
||||
// variant="contained"
|
||||
// color="error"
|
||||
// onClick={() => {
|
||||
// dispatch(
|
||||
// slaughterDeleteDailyListService(item?.key)
|
||||
// ).then((r) => {
|
||||
// if (r.payload.error) {
|
||||
// openNotif({
|
||||
// vertical: "top",
|
||||
// horizontal: "center",
|
||||
// msg: r.payload.error,
|
||||
// severity: "error",
|
||||
// });
|
||||
// } else {
|
||||
// updateTable();
|
||||
// dispatch(CLOSE_MODAL());
|
||||
// openNotif({
|
||||
// vertical: "top",
|
||||
// horizontal: "center",
|
||||
// msg: r.payload.data.result,
|
||||
// severity: "success",
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }}
|
||||
// >
|
||||
// تایید
|
||||
// </Button>
|
||||
// </Grid>
|
||||
// <Grid item>
|
||||
// <Button
|
||||
// onClick={() => {
|
||||
// dispatch(CLOSE_MODAL());
|
||||
// }}
|
||||
// >
|
||||
// لغو
|
||||
// </Button>
|
||||
// </Grid>
|
||||
// </Grid>
|
||||
// ),
|
||||
// })
|
||||
// );
|
||||
// }}
|
||||
// >
|
||||
// <DeleteIcon />
|
||||
// </IconButton>
|
||||
// </Tooltip>
|
||||
// </Grid>
|
||||
// </div>
|
||||
// </Popover>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
@@ -0,0 +1,713 @@
|
||||
import React, { useContext, useEffect, useRef, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetProductsService } from "../../services/slaughter-inventory-gets";
|
||||
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 { ImageUpload } from "../../../../components/image-upload/ImageUpload";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
IconButton,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { SlaughterAddDailyList } from "../slaughter-add-daily-list/SlaughterAddDailyList";
|
||||
import {
|
||||
slaughterDeleteDailyListService,
|
||||
slaughterGetPriceService,
|
||||
submitBatchAllocationsService,
|
||||
} from "../../services/slaughter-add-daily-list";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
import moment from "moment";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { fixBase64 } from "../../../../utils/toBase64";
|
||||
import { provincePolicyGetUploadImageService } from "../../../province/services/province-policy-upload-image";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterDailyList = () => {
|
||||
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 [rowImages, setRowImages] = useState([]);
|
||||
const [uploadPolicy, setUploadPolicy] = useState({
|
||||
killHouseAllocation: true,
|
||||
});
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const priceRefs = useRef([]);
|
||||
const weightRefs = useRef([]);
|
||||
const imageRefs = 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);
|
||||
imageRefs.current = imageRefs.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 (uploadPolicy?.killHouseAllocation || rowImages[index]) {
|
||||
if (imageRefs.current[index]) {
|
||||
imageRefs.current[index].focus();
|
||||
}
|
||||
} else {
|
||||
moveToNextField(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const moveToNextField = (currentIndex) => {
|
||||
if (priceState?.active) {
|
||||
let nextIndex = currentIndex + 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 = currentIndex + 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 fetchUploadPolicy = () => {
|
||||
dispatch(
|
||||
provincePolicyGetUploadImageService({
|
||||
role_key: checkPathStartsWith("slaughter") ? selectedSubUser?.key : "",
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload?.data) {
|
||||
setUploadPolicy(r.payload.data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchPriceStatus = async () => {
|
||||
dispatch(
|
||||
slaughterGetPriceService({
|
||||
role: getRoleFromUrl(),
|
||||
role_key: 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("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&page=1&page_size=10000`
|
||||
);
|
||||
setrendered(true);
|
||||
setData(response.data.results || []);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
};
|
||||
|
||||
const handleRowImageChange = (images, index) => {
|
||||
const newRowImages = [...rowImages];
|
||||
newRowImages[index] = images[0]
|
||||
? {
|
||||
...images[0],
|
||||
base64: fixBase64(images[0]?.data_url),
|
||||
}
|
||||
: null;
|
||||
setRowImages(newRowImages);
|
||||
|
||||
if (
|
||||
(uploadPolicy?.killHouseAllocation && images[0]) ||
|
||||
!uploadPolicy?.killHouseAllocation
|
||||
) {
|
||||
moveToNextField(index);
|
||||
}
|
||||
};
|
||||
|
||||
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() + " ریال",
|
||||
<div style={{ width: 150 }} key={i}>
|
||||
<ImageUpload
|
||||
onChange={(images) => handleRowImageChange(images, i)}
|
||||
images={rowImages[i] ? [rowImages[i]] : []}
|
||||
maxNumber={1}
|
||||
title={"بارگزاری سند"}
|
||||
required={uploadPolicy?.killHouseAllocation}
|
||||
inputRef={(el) => (imageRefs.current[i] = el)}
|
||||
/>
|
||||
{uploadPolicy?.killHouseAllocation && !rowImages[i] && (
|
||||
<Typography variant="caption" color="error">
|
||||
تصویر الزامی است
|
||||
</Typography>
|
||||
)}
|
||||
</div>,
|
||||
|
||||
<IconButton key={i} color="error">
|
||||
<DeleteIcon onClick={() => handleDeleteItem(item.key)} />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
setFilteredData(d);
|
||||
}, [data, prices, weights, priceState, rowImages, uploadPolicy]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData();
|
||||
fetchPriceStatus();
|
||||
fetchUploadPolicy();
|
||||
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 filteredData = data
|
||||
?.map((item, i) => {
|
||||
const price = priceState?.active ? getPriceByRole() : prices[i];
|
||||
const weight = weights[i];
|
||||
|
||||
if (!price || !weight) return null;
|
||||
|
||||
if (uploadPolicy?.killHouseAllocation && !rowImages[i]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let d = {
|
||||
seller_type: "KillHouse",
|
||||
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?.guild?.steward
|
||||
? "killhouse_steward"
|
||||
: "killhouse_guild",
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: weight,
|
||||
sell_type: "free",
|
||||
amount: price,
|
||||
total_amount: price * weight,
|
||||
approved_price_status: priceState?.active,
|
||||
date: moment(new Date()).format("YYYY-MM-DD"),
|
||||
};
|
||||
|
||||
if (rowImages[i]) {
|
||||
d.image = rowImages[i]?.base64;
|
||||
}
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(d).filter(([_, value]) => value !== null)
|
||||
);
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (filteredData.length === 0) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "لطفا حداقل یک رکورد معتبر با عکس وارد کنید",
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(submitBatchAllocationsService(filteredData)).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([]);
|
||||
setRowImages([]);
|
||||
fetchApiData(1);
|
||||
fetchPriceStatus();
|
||||
fetchUploadPolicy();
|
||||
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 ||
|
||||
(uploadPolicy?.killHouseAllocation &&
|
||||
data.some(
|
||||
(_, i) =>
|
||||
prices[i] &&
|
||||
weights[i] &&
|
||||
(!rowImages[i] || !rowImages[i].base64)
|
||||
))
|
||||
: 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
|
||||
sx={{ display: "flex", alignItems: "center", gap: 0.5 }}
|
||||
>
|
||||
{item[8]}
|
||||
</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,239 @@
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import {
|
||||
Autocomplete,
|
||||
Button,
|
||||
TextField,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
} from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterEditAllocatedCarService } from "../../services/slaughter-edit-allocated-car";
|
||||
import { useSlaughterHouseCars } from "../../../file/hooks/useSlaughterHouseCars";
|
||||
import { PropTypes } from "prop-types";
|
||||
|
||||
export const SlaughterEditAllocatedCar = ({
|
||||
item,
|
||||
updateTable,
|
||||
poultryRequestKey,
|
||||
killHouseKey,
|
||||
killRequestKey,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
// Get available cars
|
||||
const slaughterHouseCars = useSlaughterHouseCars(
|
||||
poultryRequestKey,
|
||||
killHouseKey,
|
||||
killRequestKey
|
||||
);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
car: null,
|
||||
trafficCode: item?.trafficCode || "",
|
||||
amount: item?.barAmount || "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
car: Yup.object().nullable(),
|
||||
trafficCode: Yup.string(),
|
||||
amount: Yup.number().positive("قیمت باید عدد مثبت باشد").nullable(),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
// Set initial car if available
|
||||
useEffect(() => {
|
||||
if (slaughterHouseCars && item) {
|
||||
const currentCar = slaughterHouseCars.find(
|
||||
(car) => car.key === item.carKey
|
||||
);
|
||||
if (currentCar) {
|
||||
formik.setFieldValue("car", currentCar);
|
||||
}
|
||||
}
|
||||
}, [slaughterHouseCars, item]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
// Check if at least one field has a value
|
||||
if (
|
||||
!formik.values.car &&
|
||||
!formik.values.trafficCode &&
|
||||
!formik.values.amount
|
||||
) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "لطفا حداقل یکی از فیلدها را پر کنید",
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Build request object
|
||||
const requestData = {
|
||||
key: item?.killHouseRequestKey,
|
||||
};
|
||||
|
||||
// If user is updating car or traffic code, send all 3 parameters together
|
||||
if (formik.values.car || formik.values.trafficCode) {
|
||||
if (formik.values.car?.key && formik.values.car.key !== item?.carKey) {
|
||||
requestData.car_key = formik.values.car.key;
|
||||
}
|
||||
|
||||
if (
|
||||
formik.values.trafficCode &&
|
||||
formik.values.trafficCode !== item?.trafficCode
|
||||
) {
|
||||
requestData.traffic_code = formik.values.trafficCode;
|
||||
}
|
||||
|
||||
if (formik.values.amount && formik.values.amount !== item?.barAmount) {
|
||||
requestData.amount = formik.values.amount;
|
||||
}
|
||||
}
|
||||
// If user is updating only amount, send only amount
|
||||
else if (formik.values.amount) {
|
||||
requestData.amount = formik.values.amount;
|
||||
}
|
||||
|
||||
dispatch(slaughterEditAllocatedCarService(requestData)).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());
|
||||
if (updateTable) updateTable();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={SPACING.SMALL}
|
||||
sx={{
|
||||
width: {
|
||||
xs: "300px",
|
||||
md: "400px",
|
||||
},
|
||||
p: 2,
|
||||
}}
|
||||
>
|
||||
<FormControl fullWidth>
|
||||
<Autocomplete
|
||||
options={slaughterHouseCars || []}
|
||||
getOptionLabel={(car) => {
|
||||
if (car) {
|
||||
const carType = car.type === "exclusive" ? "اختصاصی" : "اجاره ای";
|
||||
return `${car.driverName} (${car.driverMobile}) ${car.typeCar} پلاک ${car.pelak} (${carType})`;
|
||||
}
|
||||
return "";
|
||||
}}
|
||||
value={formik.values.car}
|
||||
onChange={(e, car) => {
|
||||
formik.setFieldValue("car", car);
|
||||
if (car?.healthCode) {
|
||||
formik.setFieldValue("trafficCode", car.healthCode);
|
||||
}
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="انتخاب خودرو و راننده (اختیاری)"
|
||||
error={formik.touched.car ? Boolean(formik.errors.car) : null}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<FormHelperText>
|
||||
{formik.touched.car && Boolean(formik.errors.car)
|
||||
? formik.errors.car
|
||||
: null}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth>
|
||||
<TextField
|
||||
id="trafficCode"
|
||||
label="کد حمل و نقل (اختیاری)"
|
||||
value={formik.values.trafficCode}
|
||||
error={
|
||||
formik.touched.trafficCode
|
||||
? Boolean(formik.errors.trafficCode)
|
||||
: null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.trafficCode && Boolean(formik.errors.trafficCode)
|
||||
? formik.errors.trafficCode
|
||||
: null
|
||||
}
|
||||
variant="outlined"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormControl fullWidth>
|
||||
<TextField
|
||||
id="amount"
|
||||
name="amount"
|
||||
label="قیمت (اختیاری)"
|
||||
type="number"
|
||||
value={formik.values.amount}
|
||||
error={formik.touched.amount ? Boolean(formik.errors.amount) : null}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.amount && Boolean(formik.errors.amount)
|
||||
? formik.errors.amount
|
||||
: null
|
||||
}
|
||||
variant="outlined"
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSubmit}
|
||||
disabled={
|
||||
!formik.values.car &&
|
||||
!formik.values.trafficCode &&
|
||||
!formik.values.amount
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
ثبت تغییرات
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
SlaughterEditAllocatedCar.propTypes = {
|
||||
item: PropTypes.object.isRequired,
|
||||
updateTable: PropTypes.func,
|
||||
poultryRequestKey: PropTypes.string,
|
||||
killHouseKey: PropTypes.string,
|
||||
killRequestKey: PropTypes.string,
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import { useContext, useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { slaughterGetInventoryStock } from "../../services/salughter-get-inventory-stock";
|
||||
import { slaughterEditStockService } from "../../services/slaughter-edit-stock";
|
||||
|
||||
const NumberValidationSchema = Yup.object().shape({
|
||||
firstNumber: Yup.number()
|
||||
.required("حجم لاشه ها الزامی می باشد")
|
||||
.min(0, "Number must be greater than or equal to 0"),
|
||||
secondNumber: Yup.number()
|
||||
.required("موجودی وزن لاشه ها الزامی می باشد")
|
||||
.min(0, "Number must be greater than or equal to 0"),
|
||||
});
|
||||
|
||||
export const SlaughterEditStock = ({ inventoryKey, aveWeightOfCarcasses }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1] = useContext(AppContext);
|
||||
|
||||
const { inventorySelectedKillHouse } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
firstNumber: "",
|
||||
secondNumber: "",
|
||||
},
|
||||
validationSchema: NumberValidationSchema,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
slaughterEditStockService({
|
||||
key: inventoryKey,
|
||||
updated_number_of_carcasses: Number(values.firstNumber),
|
||||
updated_weight_of_carcasses: Number(values.secondNumber),
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(
|
||||
slaughterGetInventoryStock({
|
||||
date: selectedDate1,
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
})
|
||||
);
|
||||
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",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let quantity;
|
||||
if (aveWeightOfCarcasses) {
|
||||
quantity = formik.values.secondNumber / aveWeightOfCarcasses;
|
||||
} else {
|
||||
quantity = formik.values.secondNumber / 2;
|
||||
}
|
||||
formik.setFieldValue("firstNumber", Number(quantity).toFixed());
|
||||
}, [formik.values.secondNumber]);
|
||||
|
||||
return (
|
||||
<Grid container direction="column">
|
||||
<form
|
||||
onSubmit={formik.handleSubmit}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: SPACING.LARGE,
|
||||
}}
|
||||
>
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
id="secondNumber"
|
||||
name="secondNumber"
|
||||
label="موجودی وزن لاشه ها (افت 25٪)"
|
||||
type="number"
|
||||
value={formik.values.secondNumber}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.secondNumber && Boolean(formik.errors.secondNumber)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.secondNumber && formik.errors.secondNumber
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
id="firstNumber"
|
||||
name="firstNumber"
|
||||
label="حجم لاشه ها"
|
||||
type="number"
|
||||
value={formik.values.firstNumber}
|
||||
disabled={true}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.firstNumber && Boolean(formik.errors.firstNumber)
|
||||
}
|
||||
helperText={formik.touched.firstNumber && formik.errors.firstNumber}
|
||||
/>
|
||||
|
||||
<Button type="submit" fullWidth variant="contained" color="primary">
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Box, Grid, Tab, Tabs } from "@mui/material";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useState } from "react";
|
||||
import { SlaughterManageBars } from "../slaughter-manage-bars/SlaughterManageBars";
|
||||
import { EnterAggregateLoadInformation } from "../enter-aggregate-load-information/EnterAggregateLoadInformation";
|
||||
import { EnterLoadInformation } from "../enter-load-information/EnterLoadInformation";
|
||||
import { SlaughterEnterNoneReciept } from "../slaughter-enter-none-receipt/SlaughterEnterNoneReciept";
|
||||
|
||||
export const SalughterEnterBarInfo = () => {
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
const handleChangeTab = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
mt={SPACING.MEDIUM}
|
||||
width="100%"
|
||||
>
|
||||
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChangeTab}
|
||||
aria-label="basic tabs example"
|
||||
>
|
||||
<Tab label="وارد کردن اطلاعات بار" />
|
||||
<Tab label="وارد کردن تک سندی بار" />
|
||||
<Tab label="بارهای تکمیل شده" />
|
||||
<Tab label="عدم وصول" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
{value === 0 && <EnterLoadInformation />}
|
||||
{value === 1 && <EnterAggregateLoadInformation />}
|
||||
{value === 2 && <SlaughterManageBars />}
|
||||
{value === 3 && <SlaughterEnterNoneReciept />}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
Stack,
|
||||
Divider,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { format } from "date-fns-jalali";
|
||||
|
||||
export const SlaughterEnterInformationModal = ({ handleSubmit, item }) => {
|
||||
const validationSchema = Yup.object({
|
||||
message: Yup.string().required("پیام الزامی است"),
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
message: "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
handleSubmit(values);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container gap={SPACING.SMALL} direction="column">
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
sx={{ p: 2, minWidth: 300 }}
|
||||
>
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xs={6}>
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">کدبار:</Typography>
|
||||
<Typography variant="body2">{item?.barCode || "-"}</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">تاریخ کشتار:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.poultryRequest.sendDate
|
||||
? format(
|
||||
new Date(item?.poultryRequest.sendDate),
|
||||
"yyyy/MM/dd"
|
||||
)
|
||||
: "-"}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">خریدار:</Typography>
|
||||
<Typography variant="body2">{`${item.killhouseUser?.name}(${item.killhouseUser?.killHouseOperator?.user?.mobile})`}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">مرغدار:</Typography>
|
||||
<Typography variant="body2">{`${item.poultryRequest?.poultry?.unitName}`}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2"> کد سفارش:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.poultryRequest.orderCode}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">تعداد اولیه:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item.quantity?.toLocaleString()} (قطعه)
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">وزن :</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.weightInfo?.weight?.toLocaleString()} (کیلوگرم)
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Divider sx={{ mt: 1, mb: 2 }} />
|
||||
|
||||
<TextField
|
||||
name="message"
|
||||
label="پیام (اجباری)"
|
||||
multiline
|
||||
rows={4}
|
||||
value={formik.values.message}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.message && Boolean(formik.errors.message)}
|
||||
helperText={formik.touched.message && formik.errors.message}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={!formik.isValid || formik.isSubmitting}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,145 @@
|
||||
import { IconButton, Popover, Tooltip } from "@mui/material";
|
||||
import { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { SlaughterEnterBarWeight } from "../../../file/components/slaughter-enter-bar-weight/SlaughterEnterBarWeight";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ReceiptLongIcon from "@mui/icons-material/ReceiptLong";
|
||||
import { SlaughterEnterInformationModal } from "../slaughter-enter-information-modal/SlaughterEnterInformationModal";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterUpdateNoneRecieptService } from "../../services/slaughter-update-none-recipt";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
|
||||
export const SlaughterEnterInformationOperation = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
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 handleSubmit = (values) => {
|
||||
dispatch(
|
||||
slaughterUpdateNoneRecieptService({
|
||||
non_receipt: true,
|
||||
main_non_receipt: true,
|
||||
non_receipt_message: values.message,
|
||||
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 {
|
||||
handleClose();
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات عدم وصول با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<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}
|
||||
>
|
||||
<Grid style={{ padding: "20px" }} container direction="column">
|
||||
<Tooltip title="ورود اطلاعات بار" placement="right">
|
||||
<IconButton
|
||||
color="primary"
|
||||
disabled={
|
||||
item?.documentStatus === "بدون مشکل" ||
|
||||
item?.documentStatus === "بدون مشکل فاقد کیفیت"
|
||||
}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "انجام عملیات",
|
||||
top: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterEnterBarWeight
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={"عدم وصول"} placement="right">
|
||||
<IconButton
|
||||
disabled={item?.allocatedQuantity > 0}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "عدم وصول",
|
||||
content: (
|
||||
<SlaughterEnterInformationModal
|
||||
handleSubmit={handleSubmit}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
>
|
||||
<ReceiptLongIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,473 @@
|
||||
import { useContext, useEffect, useState, useMemo, useCallback } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import axios from "axios";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { Button, TextField, Tooltip } from "@mui/material";
|
||||
import { VetFarmEditTrafficCode } from "../../../vet-farm/components/vet-farm-edit-traffic-code/VetFarmEditTrafficCode";
|
||||
import { format } from "date-fns-jalali";
|
||||
import { SlaughterNoneRecieptOperation } from "../slaughter-none-reciept-operation/SlaughterNoneRecieptOperation";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import moment from "moment";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
// Constants
|
||||
const ROLES = {
|
||||
PROVINCE_OPERATOR: "ProvinceOperator",
|
||||
SUPER_ADMIN: "SuperAdmin",
|
||||
ADMIN_X: "AdminX",
|
||||
SUPPORTER: "Supporter",
|
||||
VET_SUPERVISOR: "VetSupervisor",
|
||||
VET_FARM: "VetFarm",
|
||||
CITY_VET: "CityVet",
|
||||
};
|
||||
|
||||
const KILL_TYPES = {
|
||||
FREEZING: "انجماد",
|
||||
EXPORT: "صادرات",
|
||||
NORMAL: "عادی",
|
||||
};
|
||||
|
||||
const SALE_TYPES = {
|
||||
FREE: "آزاد",
|
||||
GOVERNMENT: "دولتی",
|
||||
};
|
||||
|
||||
const NON_RECEIPT_STATES = {
|
||||
ACCEPTED: "تایید شده",
|
||||
REJECTED: "رد شده",
|
||||
PENDING: "درانتظار تایید",
|
||||
};
|
||||
|
||||
const DEFAULT_PER_PAGE = 10;
|
||||
const DEFAULT_PAGE = 1;
|
||||
|
||||
// Helper functions
|
||||
const formatDate = (date) => {
|
||||
if (!date) return "-";
|
||||
return format(new Date(date), "yyyy/MM/dd");
|
||||
};
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
return value ? `${value.toLocaleString()} ﷼` : "-";
|
||||
};
|
||||
|
||||
const formatNumber = (value) => {
|
||||
return value ? value.toLocaleString() : "-";
|
||||
};
|
||||
|
||||
const formatUserInfo = (name, mobile) => {
|
||||
return name && mobile ? `${name} (${mobile})` : "-";
|
||||
};
|
||||
|
||||
const getKillType = (item) => {
|
||||
if (item?.poultryRequest?.freezing) return KILL_TYPES.FREEZING;
|
||||
if (item?.poultryRequest?.export) return KILL_TYPES.EXPORT;
|
||||
return KILL_TYPES.NORMAL;
|
||||
};
|
||||
|
||||
const getSaleType = (item) => {
|
||||
return item?.poultryRequest?.freeSaleInProvince
|
||||
? SALE_TYPES.FREE
|
||||
: SALE_TYPES.GOVERNMENT;
|
||||
};
|
||||
|
||||
const getNonReceiptState = (item) => {
|
||||
if (item?.nonReceiptState === "accepted") return NON_RECEIPT_STATES.ACCEPTED;
|
||||
if (item?.nonReceiptState === "rejected") return NON_RECEIPT_STATES.REJECTED;
|
||||
return NON_RECEIPT_STATES.PENDING;
|
||||
};
|
||||
|
||||
const formatCheckerInfo = (checker, mobile) => {
|
||||
return checker && mobile ? `${checker}(${mobile})` : "-";
|
||||
};
|
||||
|
||||
const buildApiUrl = (params) => {
|
||||
const { textValue, role, date1, date2, page, perPage, roleKey } = params;
|
||||
const baseUrl = "non-receipt-request/";
|
||||
const queryParams = new URLSearchParams({
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
role: role || "",
|
||||
date1: date1 || "",
|
||||
date2: date2 || "",
|
||||
page: page || DEFAULT_PAGE,
|
||||
page_size: perPage || DEFAULT_PER_PAGE,
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseUrl}?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const buildExcelUrl = (params) => {
|
||||
const { baseURL, role, roleKey, userKey, textValue, date1, date2 } = params;
|
||||
const queryParams = new URLSearchParams({
|
||||
role: role || "",
|
||||
key: userKey || "",
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
date1: date1 || "",
|
||||
date2: date2 || "",
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseURL}non_receipt_request_excel/?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const isTrafficCodeEditable = (role, item) => {
|
||||
const adminRoles = [
|
||||
ROLES.PROVINCE_OPERATOR,
|
||||
ROLES.SUPER_ADMIN,
|
||||
ROLES.ADMIN_X,
|
||||
ROLES.SUPPORTER,
|
||||
ROLES.VET_SUPERVISOR,
|
||||
];
|
||||
|
||||
if (adminRoles.includes(role)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const vetRoles = [ROLES.VET_FARM, ROLES.CITY_VET];
|
||||
return (
|
||||
item.trash !== true &&
|
||||
item.assignmentStateArchive === "pending" &&
|
||||
!item?.clearanceCode &&
|
||||
vetRoles.includes(role)
|
||||
);
|
||||
};
|
||||
|
||||
export const SlaughterEnterNoneReciept = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
// Redux
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// State
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(DEFAULT_PER_PAGE);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(DEFAULT_PAGE);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
|
||||
// Memoized values
|
||||
const currentRole = useMemo(() => getRoleFromUrl(), []);
|
||||
const roleKey = useMemo(
|
||||
() => (checkPathStartsWith("slaughter") ? selectedSubUser?.key || "" : ""),
|
||||
[selectedSubUser?.key]
|
||||
);
|
||||
|
||||
// Fetch API data
|
||||
const fetchApiData = useCallback(
|
||||
async (pageNumber = page) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const url = buildApiUrl({
|
||||
textValue,
|
||||
role: currentRole,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
page: pageNumber || DEFAULT_PAGE,
|
||||
perPage,
|
||||
roleKey,
|
||||
});
|
||||
|
||||
const response = await axios.get(url);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
currentRole,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
roleKey,
|
||||
page,
|
||||
dispatch,
|
||||
]
|
||||
);
|
||||
|
||||
// Update table callback
|
||||
const updateTable = useCallback(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
setPage(DEFAULT_PAGE);
|
||||
}, [fetchApiData]);
|
||||
|
||||
// Handlers
|
||||
const handlePageChange = (newPage) => {
|
||||
fetchApiData(newPage);
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (newPerRows) => {
|
||||
setPerPage(newPerRows);
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
await fetchApiData(DEFAULT_PAGE);
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleDateChange1 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate1(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDateChange2 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate2(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleExcelDownload = useCallback(() => {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "فایل اکسل در حال دانلود می باشد، این علمیات ممکن است زمان بر باشد لطفا صبر کنید.",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
const excelUrl = buildExcelUrl({
|
||||
baseURL: axios.defaults.baseURL,
|
||||
role: currentRole,
|
||||
roleKey,
|
||||
userKey,
|
||||
textValue,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
});
|
||||
|
||||
window.location.href = excelUrl;
|
||||
}, [
|
||||
openNotif,
|
||||
currentRole,
|
||||
roleKey,
|
||||
userKey,
|
||||
textValue,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
]);
|
||||
|
||||
// Initial data fetch and refetch when filters change
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
setPage(DEFAULT_PAGE);
|
||||
}, [selectedDate1, selectedDate2, perPage, roleKey, selectedSubUser?.key]);
|
||||
|
||||
// Transform data to table format
|
||||
useEffect(() => {
|
||||
const transformedData = data?.map((item, i) => {
|
||||
const rowNumber =
|
||||
page === DEFAULT_PAGE ? i + 1 : i + perPage * (page - 1) + 1;
|
||||
|
||||
return [
|
||||
rowNumber,
|
||||
<ShowImage
|
||||
key={`empty-${i}`}
|
||||
src={item?.assignmentInfo?.imageWithoutBar}
|
||||
/>,
|
||||
<ShowImage
|
||||
key={`full-${i}`}
|
||||
src={item?.assignmentInfo?.imageWithBar}
|
||||
/>,
|
||||
item?.barCode || "-",
|
||||
<VetFarmEditTrafficCode
|
||||
key={`traffic-${i}`}
|
||||
updateTable={fetchApiData}
|
||||
killHouseRequestKey={item.key}
|
||||
trafficCode={item?.trafficCode}
|
||||
isEditable={isTrafficCodeEditable(currentRole, item)}
|
||||
/>,
|
||||
formatCurrency(item?.amount),
|
||||
formatDate(item?.poultryRequest?.sendDate),
|
||||
formatUserInfo(
|
||||
item.killhouseUser?.name,
|
||||
item.killhouseUser?.killHouseOperator?.user?.mobile
|
||||
),
|
||||
item?.killer
|
||||
? formatUserInfo(
|
||||
item.killer?.name,
|
||||
item.killer?.killHouseOperator?.user?.mobile
|
||||
)
|
||||
: "-",
|
||||
formatUserInfo(
|
||||
item.poultryRequest?.poultry?.unitName,
|
||||
item.poultryRequest?.poultry?.user?.mobile
|
||||
),
|
||||
item?.poultryRequest?.age || "-",
|
||||
formatNumber(item.quantity),
|
||||
formatNumber(item?.weightInfo?.weight),
|
||||
formatCurrency(item?.poultryRequest?.amount),
|
||||
formatCurrency(item?.weightInfo?.killHousePrice),
|
||||
`${item.addCar?.driver?.typeCar || ""} ${
|
||||
item.addCar?.driver?.pelak || ""
|
||||
}`.trim() || "-",
|
||||
formatUserInfo(
|
||||
item.addCar?.driver?.driverName,
|
||||
item.addCar?.driver?.driverMobile
|
||||
),
|
||||
formatNumber(item.vetAcceptedRealQuantity),
|
||||
formatNumber(item.vetAcceptedRealWeight),
|
||||
item?.poultryRequest?.orderCode || "-",
|
||||
getKillType(item),
|
||||
getSaleType(item),
|
||||
getNonReceiptState(item),
|
||||
item?.nonReceiptMessage || "-",
|
||||
formatJustDate(item?.nonReceiptCheckDate) || "-",
|
||||
formatCheckerInfo(
|
||||
item?.nonReceiptChecker,
|
||||
item?.nonReceiptCheckerMobile
|
||||
),
|
||||
item?.message || "-",
|
||||
<SlaughterNoneRecieptOperation
|
||||
key={`operation-${i}`}
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(transformedData || []);
|
||||
}, [data, page, perPage, currentRole, fetchApiData, updateTable]);
|
||||
|
||||
// Table columns
|
||||
const tableColumns = [
|
||||
"ردیف",
|
||||
"بارنامه خالی",
|
||||
"بارنامه پر",
|
||||
"کدبار",
|
||||
"کد بهداشتی حمل و نقل",
|
||||
"قیمت مرغ زندهی بار",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"کشتارکن اختصاصی",
|
||||
"مرغدار",
|
||||
"سن مرغ",
|
||||
"تعداد اولیه",
|
||||
"وزن اولیه بار (کیلوگرم)",
|
||||
"قیمت مرغدار",
|
||||
"قیمت کشتارگاه",
|
||||
"ماشین",
|
||||
"راننده",
|
||||
"تحویلی دامپزشک (قطعه)",
|
||||
"وزن تحویلی دامپزشک (کیلوگرم)",
|
||||
"کدسفارش کشتار",
|
||||
"نوع کشتار",
|
||||
"نوع فروش",
|
||||
"وضعیت عدم وصول",
|
||||
"توضیحات کشتارگاه",
|
||||
"تاریخ (تایید / رد)",
|
||||
"بررسی کننده",
|
||||
"توضیحات بررسی کننده",
|
||||
"عملیات",
|
||||
];
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="center">
|
||||
<Grid
|
||||
container
|
||||
alignItems="start"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
style={{ width: "160px" }}
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={handleDateChange1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
style={{ width: "160px" }}
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={handleDateChange2}
|
||||
/>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
value={textValue}
|
||||
/>
|
||||
<Button type="submit" endIcon={<RiSearchLine />}>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<Button color="success" onClick={handleExcelDownload}>
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={tableColumns}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="عدم وصول"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { IconButton, Popover, Tooltip } from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterSubmitExport } from "../slaughter-submit-export/SlaughterSubmitExport";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterDeleteFreeBuyService } from "../../services/slaughter-delete-free-buy";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
|
||||
export const SlaughterExportOptions = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<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}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "20px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Grid container direction="column">
|
||||
<Tooltip title="ویرایش" placement="right">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ویرایش درخواست صادرات",
|
||||
content: (
|
||||
<SlaughterSubmitExport
|
||||
updateTable={updateTable}
|
||||
edit
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="حذف">
|
||||
<IconButton
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(slaughterDeleteFreeBuyService(item.key)).then(
|
||||
(r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{/* <Tooltip title="خروجی اکسل" placement="left">
|
||||
<a
|
||||
href={`${axios.defaults.baseURL}bar_for_each_persion_excel/?code=${item.barCode}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={20} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip> */}
|
||||
</Grid>
|
||||
</div>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,383 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import moment from "moment";
|
||||
import axios from "axios";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Button, Tab, Tabs, TextField, Tooltip } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { slaughterGetExportAllowState } from "../../services/slaughter-get-export-allow-state";
|
||||
import { SlaughterSubmitExport } from "../slaughter-submit-export/SlaughterSubmitExport";
|
||||
import { formatJustDate, formatTime } from "../../../../utils/formatTime";
|
||||
import { SlaughterExportOptions } from "../slaughter-export-options/SlaughterExportOptions";
|
||||
import { EnterAuthCodeDirectBuy } from "../enter-auth-code-direct-buy/EnterAuthCodeDirectBuy";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterExport = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [exportData, setExportData] = useState();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetExportAllowState({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setExportData(r.payload.data);
|
||||
});
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
|
||||
const handleTabChange = (event, newValue) => {
|
||||
setActiveTab(newValue);
|
||||
};
|
||||
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
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 [tableDataArchive, setTableDataArchive] = useState([]);
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`kill_request/?export=true&type=${
|
||||
activeTab === 0 ? "pending" : "archive"
|
||||
}&search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedSubUser?.key, selectedDate1, selectedDate2, perPage, activeTab]);
|
||||
|
||||
const getItemState = (item) => {
|
||||
let state = "";
|
||||
if (item.exportState === "pending") {
|
||||
state = "در انتظار تایید";
|
||||
} else if (item.exportState === "rejected") {
|
||||
state = "رد شده";
|
||||
} else if (item.exportState === "accepted") {
|
||||
state = "تایید شده";
|
||||
} else if (item.exportState === "deleted") {
|
||||
state = "حذف شده";
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
formatJustDate(item?.createDate),
|
||||
formatJustDate(item.reciveDate),
|
||||
`${item.killHouse.name} (${item.killHouse.killHouseOperator.user.mobile})`,
|
||||
item?.slaughterHouse
|
||||
? item?.slaughterHouse?.name
|
||||
: item?.killHouse?.name,
|
||||
item?.exportCountry,
|
||||
`${item?.poultry?.userprofile?.fullName} (${item?.poultry?.userprofile?.mobile})`,
|
||||
item.killCapacity,
|
||||
item.IndexWeight,
|
||||
(item.IndexWeight * item.killCapacity)?.toLocaleString(),
|
||||
<>
|
||||
{item?.inputDirectBuyingCode ? (
|
||||
item?.inputDirectBuyingCode
|
||||
) : (
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت کد احراز",
|
||||
content: (
|
||||
<EnterAuthCodeDirectBuy
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت کداحراز
|
||||
</Button>
|
||||
)}
|
||||
</>,
|
||||
getItemState(item),
|
||||
|
||||
activeTab === 0 ? (
|
||||
<SlaughterExportOptions
|
||||
key={i}
|
||||
updateTable={updateTable}
|
||||
item={item}
|
||||
/>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
|
||||
const a = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
formatJustDate(item?.createDate),
|
||||
formatJustDate(item.reciveDate),
|
||||
`${item.killHouse.name} (${item.killHouse.killHouseOperator.user.mobile})`,
|
||||
item?.slaughterHouse
|
||||
? item?.slaughterHouse?.name
|
||||
: item?.killHouse?.name,
|
||||
item?.exportCountry,
|
||||
`${item?.poultry?.userprofile?.fullName} (${item?.poultry?.userprofile?.mobile})`,
|
||||
item.killCapacity,
|
||||
item.IndexWeight,
|
||||
(item.IndexWeight * item.killCapacity)?.toLocaleString(),
|
||||
getItemState(item),
|
||||
item?.acceptRejectDate ? formatTime(item?.acceptRejectDate) : "-",
|
||||
item?.directBuyingMessage,
|
||||
];
|
||||
});
|
||||
|
||||
setTableDataArchive(a);
|
||||
}, [data]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`kill_request/?export=true&type=${
|
||||
activeTab === 0 ? "pending" : "archive"
|
||||
}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${1}&page_size=${perPage}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" flexWrap="nowrap" mt={SPACING.SMALL}>
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
my={SPACING.SMALL}
|
||||
>
|
||||
<Tabs
|
||||
scrollButtons="auto"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
<Tab label="درخواست های جدید" />
|
||||
<Tab label="بایگانی" />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
mt={SPACING.MEDIUM}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap={2}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={!exportData?.exportStatus}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ثبت درخواست صادرات",
|
||||
content: <SlaughterSubmitExport updateTable={updateTable} />,
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت درخواست صادرات
|
||||
</Button>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
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>
|
||||
{activeTab === 1 && (
|
||||
<Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}export_kill_house_excel/?date1=${selectedDate1}&date2=${selectedDate2}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&key=${userKey}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</form>
|
||||
|
||||
{activeTab === 0 ? (
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ثبت درخواست",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"محل کشتار",
|
||||
"کشور مقصد",
|
||||
"مرغدار (تلفن)",
|
||||
"تعداد درخواست (قطعه)",
|
||||
"میانگین وزنی (کیلوگرم)",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"کد احراز",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="صادرات"
|
||||
/>
|
||||
) : (
|
||||
<ResponsiveTable
|
||||
data={tableDataArchive}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ثبت درخواست",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"محل کشتار",
|
||||
"کشور مقصد",
|
||||
"مرغدار (تلفن)",
|
||||
"تعداد درخواست (قطعه)",
|
||||
"میانگین وزنی (کیلوگرم)",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"وضعیت",
|
||||
"تاریخ تایید/رد",
|
||||
"دلیل رد",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="بایگانی صادرات"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,285 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import { slaughterFactorsService } from "../../services/slaughter-factors";
|
||||
import PaymentIcon from "@mui/icons-material/Payment";
|
||||
import { Button, IconButton, TextField, Typography } from "@mui/material";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterPayFactor } from "../slaughter-pay-factor/SlaughterPayFactor";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { slaughterDeleteFactorService } from "../../services/slaughter-delete-factor";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment/moment";
|
||||
|
||||
export const SlaughterFactorsComponent = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
const { slaughterFactors } = useSelector((state) => state.slaughterSlice);
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const [archiveDataTable, setArchiveDataTable] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = slaughterFactors
|
||||
?.filter((item) => item.state === "pending")
|
||||
.map((item) => {
|
||||
let state;
|
||||
switch (item.state) {
|
||||
case "pending":
|
||||
state = "در انتظار پرداخت";
|
||||
break;
|
||||
case "paid":
|
||||
state = "پرداخت شده";
|
||||
break;
|
||||
case "unpaid":
|
||||
state = "پرداخت نشده";
|
||||
break;
|
||||
default:
|
||||
state = "در انتظار پرداخت";
|
||||
}
|
||||
return [
|
||||
item?.killRequest?.slaughterHouse?.name
|
||||
? item?.killRequest?.slaughterHouse?.name
|
||||
: item?.killRequest?.killHouse?.name,
|
||||
formatJustDate(item?.createDate),
|
||||
item?.killRequest?.IndexWeight,
|
||||
item.killRequest.oldChickenBreed
|
||||
? item.killRequest.oldChickenBreed
|
||||
: item?.killRequest?.chickenBreed,
|
||||
item.killRequest.chickenBreed,
|
||||
item.killRequest.provinceQuantity
|
||||
? item.killRequest.provinceQuantity.toLocaleString()
|
||||
: item.killRequest.killCapacity?.toLocaleString(),
|
||||
item.killRequest.provinceQuantity
|
||||
? item.killRequest.killCapacity?.toLocaleString()
|
||||
: 0,
|
||||
item?.amount.toLocaleString() + " ﷼",
|
||||
item?.minimumAmount.toLocaleString() + " ﷼",
|
||||
state,
|
||||
<IconButton
|
||||
disabled={item.state === "paid"}
|
||||
key="ee"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "پرداخت فاکتور",
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: <SlaughterPayFactor factorKey={item.key} />,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<PaymentIcon />
|
||||
</IconButton>,
|
||||
<IconButton
|
||||
disabled={item.paidState === "paid"}
|
||||
key="ee"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "لغو سفارش",
|
||||
content: (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
width="100%"
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<Grid>
|
||||
<Typography>
|
||||
در صورت لغو فاکتور درخواست اولیه شما هم لغو می گردد.
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterDeleteFactorService({
|
||||
state: "cancel",
|
||||
factor_key: item.key,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
slaughterFactorsService({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "سفارش با موفقیت لغو شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
لغو سفارش
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
setDataTable(d);
|
||||
|
||||
const c = slaughterFactors
|
||||
?.filter((item) => item.state === "paid" || item.state === "unpaid")
|
||||
.map((item) => {
|
||||
let state;
|
||||
switch (item.state) {
|
||||
case "pending":
|
||||
state = "در انتظار پرداخت";
|
||||
break;
|
||||
case "paid":
|
||||
state = "پرداخت شده";
|
||||
break;
|
||||
case "unpaid":
|
||||
state = "پرداخت نشده";
|
||||
break;
|
||||
default:
|
||||
state = "در انتظار پرداخت";
|
||||
}
|
||||
return [
|
||||
item?.killRequest?.slaughterHouse?.name
|
||||
? item?.killRequest?.slaughterHouse?.name
|
||||
: item?.killRequest?.killHouse?.name,
|
||||
formatJustDate(item?.createDate),
|
||||
item?.killRequest?.IndexWeight,
|
||||
item.killRequest.oldChickenBreed
|
||||
? item.killRequest.oldChickenBreed
|
||||
: item?.killRequest?.chickenBreed,
|
||||
item.killRequest.chickenBreed,
|
||||
item.killRequest.provinceQuantity
|
||||
? item.killRequest.provinceQuantity.toLocaleString()
|
||||
: item.killRequest.killCapacity?.toLocaleString(),
|
||||
item.killRequest.provinceQuantity
|
||||
? item.killRequest.killCapacity?.toLocaleString()
|
||||
: 0,
|
||||
item?.amount.toLocaleString() + " ﷼",
|
||||
item?.minimumAmount.toLocaleString() + " ﷼",
|
||||
state,
|
||||
];
|
||||
});
|
||||
setArchiveDataTable(c);
|
||||
}, [slaughterFactors]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(slaughterFactorsService({ selectedDate1, selectedDate2 }));
|
||||
}, [selectedDate1, selectedDate2]);
|
||||
|
||||
return (
|
||||
<Grid container flex={1}>
|
||||
<Grid width="100%">
|
||||
<AdvancedTable
|
||||
name={
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<Typography>فاکتور همراه با ثبت درخواست کشتار</Typography>
|
||||
</Grid>
|
||||
<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>
|
||||
</Grid>
|
||||
}
|
||||
columns={[
|
||||
"کاربر",
|
||||
"تاریخ درخواست",
|
||||
"وزن",
|
||||
"نژاد درخواستی",
|
||||
"نژاد تایید شده",
|
||||
"تعداد درخواستی",
|
||||
"تعداد تایید شده",
|
||||
"مبلغ پیش فاکتور",
|
||||
"حداقل پرداختی (70%)",
|
||||
"وضعیت",
|
||||
"پرداخت",
|
||||
"لغو سفارش",
|
||||
]}
|
||||
data={dataTable}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid width="100%">
|
||||
<AdvancedTable
|
||||
name="بایگانی"
|
||||
columns={[
|
||||
"کاربر",
|
||||
"تاریخ درخواست",
|
||||
"وزن",
|
||||
"نژاد درخواستی",
|
||||
"نژاد تایید شده",
|
||||
"تعداد درخواستی",
|
||||
"تعداد تایید شده",
|
||||
"مبلغ پیش فاکتور",
|
||||
"حداقل پرداختی (70%)",
|
||||
"وضعیت",
|
||||
]}
|
||||
data={archiveDataTable}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,130 @@
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import PaymentIcon from "@mui/icons-material/Payment";
|
||||
import { IconButton, TextField, Typography } from "@mui/material";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterPayFactor } from "../slaughter-pay-factor/SlaughterPayFactor";
|
||||
import { slaughterFinalFactorsService } from "../../services/slaughter-final-factors";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import moment from "moment/moment";
|
||||
|
||||
export const SlaughterFinalFactorsComponent = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { slaughterFinalFactors } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
const [dataFinalFactorsTable, setDataFinalFactorsTable] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const c = slaughterFinalFactors?.map((item) => {
|
||||
let state;
|
||||
switch (item.paidState) {
|
||||
case "pending":
|
||||
state = "در انتظار پرداخت";
|
||||
break;
|
||||
case "paid":
|
||||
state = "پرداخت شده";
|
||||
break;
|
||||
default:
|
||||
state = "در انتظار پرداخت";
|
||||
}
|
||||
return [
|
||||
item?.factorBarCode,
|
||||
state,
|
||||
item?.factorFee.toLocaleString() + " ﷼",
|
||||
item?.totalPrice.toLocaleString() + " ﷼",
|
||||
item?.totalWeight,
|
||||
<IconButton
|
||||
disabled={item.paidState === "paid"}
|
||||
key="ee"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "پرداخت فاکتور",
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterPayFactor
|
||||
factorKey={item.key}
|
||||
isFinalFactor={true}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<PaymentIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
setDataFinalFactorsTable(c);
|
||||
}, [slaughterFinalFactors]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(slaughterFinalFactorsService({ selectedDate1, selectedDate2 }));
|
||||
}, [selectedDate1, selectedDate2]);
|
||||
|
||||
return (
|
||||
<Grid container flex={1}>
|
||||
<Grid width="100%">
|
||||
<AdvancedTable
|
||||
name={
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<Grid>
|
||||
<Typography>فاکتور نهایی</Typography>
|
||||
</Grid>
|
||||
<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>
|
||||
</Grid>
|
||||
}
|
||||
columns={[
|
||||
"کدبار",
|
||||
"وضعیت",
|
||||
"قیمت هرکیلو",
|
||||
"قابل پرداخت",
|
||||
"وزن",
|
||||
"پرداخت",
|
||||
]}
|
||||
data={dataFinalFactorsTable}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,144 @@
|
||||
import { Button, IconButton, Popover } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { DRAWER, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteInventoryFreeBarService } from "../../services/slaughter-delete-inventory-free-bar";
|
||||
import { SlaughterSubmitFreeBar } from "../slaughter-submit-free-bar/SlaughterSubmitFreeBar";
|
||||
import { SlaughterSubmitRealInventoryFreeBar } from "../slaughter-submit-real-inventory-free-bar/SLaughterSubmitRealInverntoryFreeBar";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
|
||||
export const SlaughterFreeBarsAlivesOperations = ({
|
||||
item,
|
||||
updateTable,
|
||||
barState,
|
||||
type,
|
||||
}) => {
|
||||
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 ableToSeeDelete = () => {
|
||||
if (type === "carcass" || item?.buyType !== "live") {
|
||||
return true;
|
||||
} else {
|
||||
if (!barState && !item.weightOfCarcasses) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const isAbleToSee =
|
||||
item?.registerType === "automatic"
|
||||
? false
|
||||
: item.weightOfCarcasses && !barState && item?.buyType === "live";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
disabled={isAbleToSee}
|
||||
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}
|
||||
>
|
||||
<div style={{ padding: "20px" }}>
|
||||
<Grid container direction="column">
|
||||
{barState === "entered" && item?.registerType === "automatic" && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ویرایش بار آزاد",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBar
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
)}
|
||||
{(barState === "entered"
|
||||
? item?.registerType !== "automatic"
|
||||
: true) && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت اطلاعات لاشه ورودی به انبار",
|
||||
content: (
|
||||
<SlaughterSubmitRealInventoryFreeBar
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
IsEdit={barState === "entered"}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
{barState === "entered" ? "ویرایش" : "ورود به انبار"}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{ableToSeeDelete() && item?.registerType !== "automatic" && (
|
||||
<Button
|
||||
color="error"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
slaughterDeleteInventoryFreeBarService(item.key)
|
||||
).then(() => {
|
||||
updateTable();
|
||||
dispatch(fetchSlaughterBroadcastAndProducts());
|
||||
});
|
||||
}}
|
||||
>
|
||||
حذف
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,178 @@
|
||||
import {
|
||||
IconButton,
|
||||
Popover,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
Typography,
|
||||
ListItemIcon,
|
||||
} from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { DRAWER, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteInventoryFreeBarService } from "../../services/slaughter-delete-inventory-free-bar";
|
||||
import { SlaughterSubmitFreeBar } from "../slaughter-submit-free-bar/SlaughterSubmitFreeBar";
|
||||
import { SlaughterSubmitRealInventoryFreeBar } from "../slaughter-submit-real-inventory-free-bar/SLaughterSubmitRealInverntoryFreeBar";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
||||
import Inventory2OutlinedIcon from "@mui/icons-material/Inventory2Outlined";
|
||||
import DeleteOutlineOutlinedIcon from "@mui/icons-material/DeleteOutlineOutlined";
|
||||
|
||||
export const SlaughterFreeBarsOperations = ({
|
||||
item,
|
||||
updateTable,
|
||||
barState,
|
||||
type,
|
||||
}) => {
|
||||
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 ableToSeeUpdate = () => {
|
||||
if (item?.buyType === "live") {
|
||||
return !item.weightOfCarcasses && !barState;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const ableToSeeDelete = () => {
|
||||
if (type === "carcass" || item?.buyType !== "live") {
|
||||
return true;
|
||||
} else {
|
||||
if (!barState && !item.weightOfCarcasses) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const isAbleToSee =
|
||||
item?.registerType === "automatic"
|
||||
? false
|
||||
: item.weightOfCarcasses && !barState && item?.buyType === "live";
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
disabled={isAbleToSee}
|
||||
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 }}>
|
||||
{(ableToSeeUpdate() || item?.registerType === "automatic") && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
sx={{ color: "primary.main" }}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ویرایش بار آزاد",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBar
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "inherit" }}>
|
||||
<EditOutlinedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2">ویرایش</Typography>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
{barState && item?.registerType === "manual" && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
sx={{ color: "success.main" }}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت اطلاعات لاشه ورودی به انبار",
|
||||
content: (
|
||||
<SlaughterSubmitRealInventoryFreeBar
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
IsEdit={barState === "entered"}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "inherit" }}>
|
||||
<Inventory2OutlinedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2">
|
||||
{barState === "entered" ? "ویرایش" : "ورود به انبار"}
|
||||
</Typography>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
|
||||
{ableToSeeDelete() && item?.registerType !== "automatic" && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton
|
||||
sx={{ color: "error.main" }}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
slaughterDeleteInventoryFreeBarService(item.key)
|
||||
).then(() => {
|
||||
updateTable();
|
||||
dispatch(fetchSlaughterBroadcastAndProducts());
|
||||
});
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 36, color: "inherit" }}>
|
||||
<DeleteOutlineOutlinedIcon fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<Typography variant="body2" color="inherit">
|
||||
حذف
|
||||
</Typography>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
</List>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,215 @@
|
||||
import { Tooltip } from "@mui/material";
|
||||
import { Button, TextField } 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 { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { slaughterGetFreeBuyRequests } from "../../services/slaughter-get-free-buy-requests";
|
||||
|
||||
export const SlaughterFreeBuyArchive = () => {
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const dispatch = useDispatch();
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
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 handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
try {
|
||||
const response = await dispatch(
|
||||
slaughterGetFreeBuyRequests({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
value: textValue || "",
|
||||
type: "archive",
|
||||
page: page,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
if (response.payload?.data) {
|
||||
setData(response.payload.data.results);
|
||||
setTotalRows(response.payload.data.count);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page, textValue);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
try {
|
||||
const response = await dispatch(
|
||||
slaughterGetFreeBuyRequests({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
value: textValue || "",
|
||||
type: "archive",
|
||||
})
|
||||
);
|
||||
if (response.payload?.data) {
|
||||
setData(response.payload.data.results);
|
||||
setTotalRows(response.payload.data.count);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const getItemState = (item) => {
|
||||
let state = "";
|
||||
if (item.directBuyingState === "pending") {
|
||||
state = "در انتظار تایید";
|
||||
} else if (item.directBuyingState === "rejected") {
|
||||
state = "رد شده";
|
||||
} else if (item.directBuyingState === "accepted") {
|
||||
state = "تایید شده";
|
||||
} else if (item.directBuyingState === "deleted") {
|
||||
state = "حذف شده";
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage, textValue, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
formatJustDate(item?.createDate),
|
||||
formatJustDate(item.reciveDate),
|
||||
`${item.killHouse.name} (${item.killHouse.killHouseOperator.user.mobile})`,
|
||||
item?.slaughterHouse
|
||||
? item?.slaughterHouse?.name
|
||||
: item?.killHouse?.name,
|
||||
`${item?.poultry?.userprofile?.fullName} (${item?.poultry?.userprofile?.mobile})`,
|
||||
`${item.chickenBreed ? item.chickenBreed : "-"}`,
|
||||
item.killCapacity,
|
||||
item.IndexWeight,
|
||||
(item.IndexWeight * item.killCapacity)?.toLocaleString(),
|
||||
item?.inputDirectBuyingCode,
|
||||
getItemState(item),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" gap={SPACING.SMALL} alignItems="start">
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL} p="5px">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
<Grid container gap={2}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
<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="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}direct_purchase_archive_excel/?date1=${selectedDate1}&date2=${selectedDate2}&role=${getRoleFromUrl()}&key=${userKey}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ثبت درخواست",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"محل کشتار",
|
||||
"مرغدار (تلفن)",
|
||||
"نژاد",
|
||||
"تعداد درخواست (قطعه)",
|
||||
"میانگین وزنی (کیلوگرم)",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"کداحراز",
|
||||
"وضعیت",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="بایگانی خرید مستقیم"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,776 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import moment from "moment";
|
||||
import axios from "axios";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SlaughterFreeBarsOperations } from "../slaughter-free-bars-operations/SlaughterFreeBarsOperations";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { SlaughterSubmitFreeBar } from "../slaughter-submit-free-bar/SlaughterSubmitFreeBar";
|
||||
import { SlaughterHouseVetBarsOperation } from "../../../slaughter-house-vet/components/slaughter-house-vet-bars-operation/SlaughterHouseVetBarsOperation";
|
||||
import { RiFileExcel2Fill } from "react-icons/ri";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
import { vetFarmGetOutProvinceDashboard } from "../../../vet-farm/services/vet-farm-get-out-province-dashboard";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { CheckCleanceCode } from "../../../../components/check-clearance-code/ChechClearanceCode";
|
||||
import { slaughterDeleteInventoryFreeBarService } from "../../services/slaughter-delete-inventory-free-bar";
|
||||
import { slaughterReturnEnteredFreeBarService } from "../../services/slaughter-return-entered-free-bar";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import UndoIcon from "@mui/icons-material/Undo";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterFreeBuyBars = ({ isBarManagemen }) => {
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const [tableDataArchive, setTableDataArchive] = useState([]);
|
||||
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 [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
const handleTabChange = (event, newValue) => {
|
||||
setActiveTab(newValue);
|
||||
};
|
||||
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const getDashboardData = () => {
|
||||
dispatch(
|
||||
vetFarmGetOutProvinceDashboard({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
search: "filter",
|
||||
role: getRoleFromUrl(),
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
value: textValue,
|
||||
type: activeTab === 0 ? "live" : "carcass",
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const { inventorySelectedKillHouse } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetProfile({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`kill_house_free_bar/?type=${
|
||||
activeTab === 0 ? "live" : "carcass"
|
||||
}&search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}&date_type=buy`
|
||||
);
|
||||
getDashboardData();
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
setPage(1);
|
||||
fetchApiData(1);
|
||||
getDashboardData();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.registerType === "automatic" ? "سیستمی" : "دستی",
|
||||
item?.barCode || "-",
|
||||
formatJustDate(item.createDate),
|
||||
`${item?.killHouse?.name} (${item?.killHouse?.killHouseOperator?.user?.mobile})`,
|
||||
item?.exclusiveKiller
|
||||
? `${item?.exclusiveKiller?.name} (${item?.exclusiveKiller?.killHouseOperator?.user?.mobile})`
|
||||
: "-",
|
||||
item.buyType === "live" ? "مرغ زنده" : "لاشه",
|
||||
item.poultryName,
|
||||
`${item.province}/${item.city}`,
|
||||
<CheckCleanceCode
|
||||
key={item?.key}
|
||||
clearanceCode={item?.barClearanceCode}
|
||||
/>,
|
||||
item.car || "-",
|
||||
item?.driverName || "-",
|
||||
|
||||
item?.driverMobile || "-",
|
||||
formatJustDate(item.date),
|
||||
|
||||
item.numberOfCarcasses.toLocaleString(),
|
||||
item.weightOfCarcasses.toLocaleString(),
|
||||
<ShowImage key={i} src={item.barImage} />,
|
||||
<>
|
||||
{getRoleFromUrl() === "KillHouse" ? (
|
||||
<SlaughterFreeBarsOperations
|
||||
key={item.key}
|
||||
item={item}
|
||||
inventoryKey={item?.key}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={item?.killHouseVetState !== "pending"}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید / رد",
|
||||
content: (
|
||||
<SlaughterHouseVetBarsOperation
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تایید / رد
|
||||
</Button>
|
||||
)}
|
||||
</>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
|
||||
const getInformation = (item) => {
|
||||
if (getRoleFromUrl() === "AdminX" || getRoleFromUrl() === "SuperAdmin") {
|
||||
return [
|
||||
<Tooltip
|
||||
key={item}
|
||||
title="بازگشت بار"
|
||||
placement="top"
|
||||
disableHoverListener={
|
||||
!(
|
||||
item?.weightOfCarcasses &&
|
||||
item?.enteredMessage === "ورود به انبار مجازی"
|
||||
)
|
||||
}
|
||||
>
|
||||
<span>
|
||||
<IconButton
|
||||
color="primary"
|
||||
size="small"
|
||||
disabled={
|
||||
!(
|
||||
item?.weightOfCarcasses &&
|
||||
item?.enteredMessage === "ورود به انبار مجازی"
|
||||
)
|
||||
}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "بازگشت بار",
|
||||
content: (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="body2" color="red">
|
||||
آیا از بازگشت بار از انبار اطمینان دارید؟
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
mt={2}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterReturnEnteredFreeBarService({
|
||||
key: item.key,
|
||||
return_entered_bar: true,
|
||||
})
|
||||
).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",
|
||||
});
|
||||
updateTable();
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}}
|
||||
variant="contained"
|
||||
color="error"
|
||||
fullWidth
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
onClick={() => dispatch(CLOSE_MODAL())}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<UndoIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</span>
|
||||
</Tooltip>,
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const a = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.registerType === "automatic" ? "سیستمی" : "دستی",
|
||||
item?.barCode || "-",
|
||||
formatJustDate(item.createDate),
|
||||
formatJustDate(item.registerDate) || "-",
|
||||
`${item?.killHouse?.name} (${item?.killHouse?.killHouseOperator?.user?.mobile})`,
|
||||
item?.exclusiveKiller
|
||||
? `${item?.exclusiveKiller?.name} (${item?.exclusiveKiller?.killHouseOperator?.user?.mobile})`
|
||||
: "-",
|
||||
item.buyType === "live" ? "مرغ زنده" : "لاشه",
|
||||
|
||||
item.poultryName,
|
||||
`${item.province}/${item.city}`,
|
||||
<CheckCleanceCode
|
||||
key={i}
|
||||
bar_key={item?.key}
|
||||
register_type={item?.registerType}
|
||||
clearanceCode={item?.barClearanceCode}
|
||||
/>,
|
||||
item.car || "-",
|
||||
item?.driverName || "-",
|
||||
item?.driverMobile || "-",
|
||||
item.quantity.toLocaleString(),
|
||||
item.liveWeight.toLocaleString(),
|
||||
formatJustDate(item.date),
|
||||
|
||||
item.numberOfCarcasses.toLocaleString(),
|
||||
item.weightOfCarcasses.toLocaleString(),
|
||||
item?.poultry?.age,
|
||||
item.weightOfCarcasses ? "ورود به انبار" : "در انتظار ورود به انبار",
|
||||
<ShowImage key={i} src={item.barImage} />,
|
||||
...getInformation(item),
|
||||
<>
|
||||
{getRoleFromUrl() === "KillHouse" ? (
|
||||
<SlaughterFreeBarsOperations
|
||||
key={item.key}
|
||||
item={item}
|
||||
inventoryKey={item?.key}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
) : (
|
||||
isBarManagemen &&
|
||||
getRoleFromUrl() === "AdminX" && (
|
||||
<Tooltip title="حذف بار" placement="top">
|
||||
<IconButton
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "حذف بار",
|
||||
content: (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography variant="body2" color="red">
|
||||
آیا از حذف بار اطمینان دارید؟
|
||||
</Typography>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
mt={2}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterDeleteInventoryFreeBarService(
|
||||
item.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",
|
||||
});
|
||||
updateTable();
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}}
|
||||
variant="contained"
|
||||
color="error"
|
||||
fullWidth
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
onClick={() => dispatch(CLOSE_MODAL())}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<DeleteIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)
|
||||
)}
|
||||
</>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableDataArchive(a);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage, activeTab, selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`kill_house_free_bar/?type=${
|
||||
activeTab === 0 ? "live" : "carcass"
|
||||
}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${1}&page_size=${perPage}&date_type=buy`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
getDashboardData();
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const getLastItem = () => {
|
||||
let item = [];
|
||||
if (isBarManagemen && getRoleFromUrl() === "AdminX") {
|
||||
item = ["حذف"];
|
||||
} else if (isBarManagemen) {
|
||||
item = [];
|
||||
} else {
|
||||
item = ["عملیات"];
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
const information = () => {
|
||||
if (getRoleFromUrl() === "AdminX" || getRoleFromUrl() === "SuperAdmin") {
|
||||
return ["بازگشت از انبار"];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
const LiveBars = (
|
||||
<ResponsiveTable
|
||||
data={tableDataArchive}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نوع بار",
|
||||
"کد بار",
|
||||
"تاریخ خرید",
|
||||
"تاریخ ثبت در سامانه",
|
||||
"خریدار",
|
||||
"کشتارکن",
|
||||
"محصول",
|
||||
"فروشنده",
|
||||
"استان/شهر",
|
||||
"کدقرنطینه",
|
||||
"پلاک ماشین",
|
||||
"نام راننده",
|
||||
"تلفن راننده",
|
||||
"حجم زنده",
|
||||
"وزن زنده (کیلوگرم)",
|
||||
"تاریخ ورود به انبار",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه (کیلوگرم)",
|
||||
"سن مرغ",
|
||||
"وضعیت",
|
||||
"بارنامه",
|
||||
...information(),
|
||||
...getLastItem(),
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="بار زنده خرید خارج استان"
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
flexWrap="nowrap"
|
||||
mt={SPACING.SMALL}
|
||||
xs={12}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
my={SPACING.SMALL}
|
||||
>
|
||||
<Tabs
|
||||
scrollButtons="auto"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
<Tab label="زنده" />
|
||||
<Tab label="لاشه" />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
mt={SPACING.MEDIUM}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap={2}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
{getRoleFromUrl() === "KillHouse" &&
|
||||
!isBarManagemen &&
|
||||
inventorySelectedKillHouse && (
|
||||
<Button
|
||||
// disabled={!slaughterGetInventoryStockData}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ثبت اطلاعات خرید",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBar
|
||||
selectedDate={selectedDate1}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت اطلاعات خرید
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
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()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&key=${userKey}&date1=${selectedDate1}&date2=${selectedDate2}&type=${
|
||||
activeTab === 0 ? "live" : "carcass"
|
||||
}&search=filter&value=${textValue}&date_type=buy`;
|
||||
window.location.href = link;
|
||||
}}
|
||||
>
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
{/* </a> */}
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</form>
|
||||
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
{activeTab === 0 ? (
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
columns={[
|
||||
"تعداد کل بارهای زنده",
|
||||
"حجم کل بارهای زنده",
|
||||
"وزن کل بارهای زنده",
|
||||
"تعداد کل بارها وارد شده به انبار",
|
||||
"حجم کل بارهای زنده وارد شده به انبار",
|
||||
"وزن کل بارهای زنده وارد شده به انبار",
|
||||
"وزن لاشه بارهای وارد شده به انبار",
|
||||
"تعداد کل بارها وارد نشده به انبار",
|
||||
"حجم کل بارهای زنده وارد نشده به انبار",
|
||||
"وزن کل بارهای زنده وارد نشده به انبار",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.totalBars?.toLocaleString(),
|
||||
dashboardData?.totalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.totalBarsLiveWeight?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBars?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsLiveWeight?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsWeightOfCarcasses?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBars?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBarsLiveWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
customColors={[
|
||||
{
|
||||
name: "وزن لاشه بارهای وارد شده به انبار",
|
||||
color: "green",
|
||||
},
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
) : (
|
||||
<Grid container xs={12}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
customWidth={"85vw"}
|
||||
columns={["تعداد کل بارها", "حجم لاشه", "وزن لاشه"]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.totalBars?.toLocaleString(),
|
||||
dashboardData?.totalBarsNumberOfCarcasses?.toLocaleString(),
|
||||
dashboardData?.totalBarsWeightOfCarcasses?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{activeTab === 0 ? (
|
||||
<>{LiveBars}</>
|
||||
) : (
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={
|
||||
isBarManagemen
|
||||
? [
|
||||
"ردیف",
|
||||
"نوع بار",
|
||||
"کد بار",
|
||||
"تاریخ خرید",
|
||||
"خریدار",
|
||||
"کشتارکن",
|
||||
"محصول",
|
||||
"فروشنده",
|
||||
"استان/شهر",
|
||||
"کدقرنطینه",
|
||||
"پلاک ماشین",
|
||||
"نام راننده",
|
||||
"تلفن راننده",
|
||||
"تاریخ ورود به انبار",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه (کیلوگرم)",
|
||||
"بارنامه",
|
||||
]
|
||||
: [
|
||||
"ردیف",
|
||||
"نوع بار",
|
||||
"کد بار",
|
||||
"تاریخ خرید",
|
||||
"خریدار",
|
||||
"کشتارکن",
|
||||
"محصول",
|
||||
"فروشنده",
|
||||
"استان/شهر",
|
||||
"کدقرنطینه",
|
||||
"پلاک ماشین",
|
||||
"نام راننده",
|
||||
"تلفن راننده",
|
||||
"تاریخ ورود به انبار",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه (کیلوگرم)",
|
||||
"بارنامه",
|
||||
"عملیات",
|
||||
]
|
||||
}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="بار لاشه خرید خارج استان"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,324 @@
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Popover,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
} from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import DoneOutlineIcon from "@mui/icons-material/DoneOutline";
|
||||
import DoNotDisturbIcon from "@mui/icons-material/DoNotDisturb";
|
||||
import { useDispatch } from "react-redux";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterSubmitFreeBuy } from "../slaughter-submit-free-buy/SlaughterSubmitFreeBuy";
|
||||
import { slaughterDeleteFreeBuyService } from "../../services/slaughter-delete-free-buy";
|
||||
import { useContext, useState } from "react";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { ProviceRejectFreeBuy } from "../province-reject-free-buy/ProvinceRejectFreeBuy";
|
||||
import { ProvinceAcceptDirectBuy } from "../../../province/components/province-accept-direct-buy/ProvinceAcceptDirectBuy";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt";
|
||||
import SmsIcon from "@mui/icons-material/Sms";
|
||||
import { slaughterEditFreeBuyService } from "../../services/slaughter-edit-free-buy";
|
||||
import { slaughterResendDirectBuyingSmsService } from "../../services/slaughter-resend-direct-buying-sms";
|
||||
|
||||
export const SlaughterFreeBuyOperations = ({
|
||||
item,
|
||||
updateTable,
|
||||
poultryCodeMandatory,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
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 showOnlyDelete = poultryCodeMandatory && !item?.inputDirectBuyingCode;
|
||||
|
||||
const handleApproveRequest = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید فروش مستقیم",
|
||||
content: (
|
||||
<ProvinceAcceptDirectBuy item={item} updateTable={updateTable} />
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleRejectRequest = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "رد درخواست فروش آزاد",
|
||||
content: <ProviceRejectFreeBuy item={item} updateTable={updateTable} />,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleFinalAccept = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "آیا مطمئن هستید؟",
|
||||
content: (
|
||||
<Grid container>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterEditFreeBuyService({
|
||||
role: getRoleFromUrl(),
|
||||
kill_request_key: item?.key,
|
||||
final_accept: true,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r?.payload?.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r?.payload?.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(CLOSE_MODAL());
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ویرایش خرید مستقیم",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBuy edit={item} updateTable={updateTable} />
|
||||
),
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleResendSms = () => {
|
||||
dispatch(
|
||||
slaughterResendDirectBuyingSmsService({
|
||||
key: item?.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",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
dispatch(slaughterDeleteFreeBuyService(item.key)).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
content: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const options = [];
|
||||
|
||||
if (
|
||||
!showOnlyDelete &&
|
||||
(getRoleFromUrl() === "ProvinceOperator" ||
|
||||
getRoleFromUrl() === "SuperAdmin" ||
|
||||
getRoleFromUrl() === "AdminX")
|
||||
) {
|
||||
options.push({
|
||||
key: "approve",
|
||||
label: "تایید درخواست",
|
||||
color: "success.main",
|
||||
icon: <DoneOutlineIcon fontSize="small" />,
|
||||
action: handleApproveRequest,
|
||||
});
|
||||
|
||||
options.push({
|
||||
key: "reject",
|
||||
label: "رد درخواست",
|
||||
color: "warning.main",
|
||||
icon: <DoNotDisturbIcon fontSize="small" />,
|
||||
action: handleRejectRequest,
|
||||
});
|
||||
}
|
||||
|
||||
if (getRoleFromUrl() === "KillHouse" && !item?.finalAccept) {
|
||||
options.push({
|
||||
key: "finalAccept",
|
||||
label: "تایید نهایی",
|
||||
color: "primary.main",
|
||||
icon: <ThumbUpAltIcon fontSize="small" />,
|
||||
action: handleFinalAccept,
|
||||
});
|
||||
|
||||
options.push({
|
||||
key: "edit",
|
||||
label: "ویرایش",
|
||||
color: "info.main",
|
||||
icon: <EditIcon fontSize="small" />,
|
||||
action: handleEdit,
|
||||
});
|
||||
}
|
||||
|
||||
if (showOnlyDelete && item?.finalAccept) {
|
||||
options.push({
|
||||
key: "resendSms",
|
||||
label: "ارسال مجدد پیامک",
|
||||
color: "info.main",
|
||||
icon: <SmsIcon fontSize="small" />,
|
||||
action: handleResendSms,
|
||||
});
|
||||
}
|
||||
|
||||
options.push({
|
||||
key: "delete",
|
||||
label: "حذف",
|
||||
color: "error.main",
|
||||
icon: <DeleteIcon fontSize="small" />,
|
||||
action: handleDelete,
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<IconButton
|
||||
size="small"
|
||||
disabled={
|
||||
item?.directBuyingState === "accepted" ||
|
||||
(!showOnlyDelete &&
|
||||
(getRoleFromUrl() === "KillHouse" && item?.finalAccept
|
||||
? true
|
||||
: item?.directBuyingState !== "pending"))
|
||||
}
|
||||
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={{ width: 130, p: 0.5 }}>
|
||||
{options.map((option) => (
|
||||
<ListItemButton
|
||||
key={option.key}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
option.action();
|
||||
}}
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
mb: 0.25,
|
||||
py: 0.5,
|
||||
color: option.color,
|
||||
"&:last-of-type": {
|
||||
mb: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ color: option.color, minWidth: 32 }}>
|
||||
{option.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={option.label}
|
||||
primaryTypographyProps={{
|
||||
sx: {
|
||||
color: option.color,
|
||||
fontSize: "0.82rem",
|
||||
fontWeight: 600,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
))}
|
||||
</List>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,410 @@
|
||||
import { useCallback } from "react";
|
||||
import { Button, 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 { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { formatJustDate, formatTime } from "../../../../utils/formatTime";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
// import { EnterAuthCodeDirectBuy } from "../enter-auth-code-direct-buy/EnterAuthCodeDirectBuy";
|
||||
import { SlaughterFreeBuyOperations } from "../slaughter-free-buy-operations/SlaughterFreeBuyOperations";
|
||||
import { SlaughterSubmitFreeBuy } from "../slaughter-submit-free-buy/SlaughterSubmitFreeBuy";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { paymentGetDeadLines } from "../../services/payment-get-deadlines";
|
||||
import EditVerificationDirectBuy from "../edit-verification-direct-buy/EditVerificationDirectBuy";
|
||||
import SlaughterBuyPdfKillRequest from "../../../province/components/province-settlement-pdf-kill-request/ProvinceSettlementPdfKillRequest";
|
||||
import { slaughterGetFreeBuyDashboardService } from "../../services/slaughter-free-buy-dashboard";
|
||||
import { slaughterGetFreeBuyRequests } from "../../services/slaughter-get-free-buy-requests";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterFreeBuy = () => {
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const [poultryCodeMandatory, setPoultryCodeMandatory] = useState(false);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
paymentGetDeadLines({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((response) => {
|
||||
setPoultryCodeMandatory(response.payload.data?.poultryCodeMandatory);
|
||||
});
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
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 handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const getDashboardData = () => {
|
||||
dispatch(
|
||||
slaughterGetFreeBuyDashboardService({
|
||||
direct_buying: true,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
role: getRoleFromUrl(),
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchApiData = useCallback(
|
||||
async (pageNumber = page) => {
|
||||
try {
|
||||
const response = await dispatch(
|
||||
slaughterGetFreeBuyRequests({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
value: textValue || "",
|
||||
page: pageNumber,
|
||||
page_size: perPage,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
if (response.payload?.data) {
|
||||
getDashboardData();
|
||||
setData(response.payload.data.results);
|
||||
setTotalRows(response.payload.data.count);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
},
|
||||
[
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
page,
|
||||
textValue,
|
||||
dispatch,
|
||||
selectedSubUser?.key,
|
||||
]
|
||||
);
|
||||
|
||||
const updateTable = useCallback(() => {
|
||||
fetchApiData(1);
|
||||
}, [fetchApiData]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [fetchApiData]);
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page, textValue);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
try {
|
||||
const response = await dispatch(
|
||||
slaughterGetFreeBuyRequests({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
value: textValue || "",
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
if (response.payload?.data) {
|
||||
setData(response.payload.data.results);
|
||||
setTotalRows(response.payload.data.count);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const getItemState = (item) => {
|
||||
let state = "";
|
||||
if (item.finalAccept === false) {
|
||||
state = "در انتظار ارسال به استان";
|
||||
} else if (poultryCodeMandatory && !item?.inputDirectBuyingCode) {
|
||||
state = "در انتظار ورود کد احراز";
|
||||
} else if (item?.directBuyingState === "rejected") {
|
||||
state = "رد شده";
|
||||
} else if (item?.directBuyingState === "accepted") {
|
||||
state = "تایید شده";
|
||||
} else if (item?.directBuyingState === "deleted") {
|
||||
state = "حذف شده";
|
||||
} else {
|
||||
state = "در انتظار تایید استان";
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.createDate ? formatTime(item?.createDate) : "-",
|
||||
item?.reciveDate ? formatJustDate(item?.reciveDate) : "-",
|
||||
`${item.killHouse.name} (${item.killHouse.killHouseOperator.user.mobile})`,
|
||||
item?.freeDirectBuying ? "آزاد" : "دولتی",
|
||||
item?.slaughterHouse
|
||||
? item?.slaughterHouse?.name
|
||||
: item?.killHouse?.name,
|
||||
`${item?.poultry?.userprofile?.fullName} (${item?.poultry?.userprofile?.mobile})`,
|
||||
item.poultryHatching?.chickenAge || "-",
|
||||
`${item.chickenBreed ? item.chickenBreed : "-"}`,
|
||||
item.killCapacity?.toLocaleString(),
|
||||
item.IndexWeight,
|
||||
(item.IndexWeight * item.killCapacity)?.toLocaleString(),
|
||||
item?.amount?.toLocaleString(),
|
||||
|
||||
<Grid key={i}>
|
||||
{item?.directBuyingState === "pending" &&
|
||||
item?.finalAccept === true &&
|
||||
(getRoleFromUrl() === "KillHouse" ||
|
||||
getRoleFromUrl() === "AdminX" ||
|
||||
getRoleFromUrl() === "SuperAdmin" ||
|
||||
getRoleFromUrl() === "ProvinceOperator") &&
|
||||
poultryCodeMandatory ? (
|
||||
<EditVerificationDirectBuy
|
||||
updateTable={fetchApiData}
|
||||
kill_request_key={item?.key}
|
||||
inputDirectBuyingCode={item?.inputDirectBuyingCode}
|
||||
/>
|
||||
) : (
|
||||
<Typography variant="body2">
|
||||
{item?.inputDirectBuyingCode || "-"}
|
||||
</Typography>
|
||||
)}
|
||||
</Grid>,
|
||||
item?.paymentDeadlineDate
|
||||
? formatJustDate(item?.paymentDeadlineDate)
|
||||
: "-",
|
||||
getItemState(item),
|
||||
item?.directBuyingState === "pending"
|
||||
? "-"
|
||||
: item?.automaticAccept
|
||||
? "سیستم"
|
||||
: "اپراتور",
|
||||
item?.inputDirectBuyingCode ||
|
||||
(!item?.freeDirectBuying && item?.directBuyingState === "accepted") ? (
|
||||
<SlaughterBuyPdfKillRequest pdf_key={item?.key} />
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
|
||||
<SlaughterFreeBuyOperations
|
||||
key={`ops-${i}`}
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
poultryCodeMandatory={poultryCodeMandatory}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Grid container gap={SPACING.SMALL} alignItems="center">
|
||||
<Grid container xs={12} px={1} gap={2}>
|
||||
<Grid container alignSelf="start">
|
||||
{/* {getRoleFromUrl() === "KillHouse" && ( */}
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ثبت خرید مستقیم",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBuy
|
||||
updateTable={updateTable}
|
||||
fetchApiData={fetchApiData}
|
||||
/>
|
||||
),
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت خرید مستقیم
|
||||
</Button>
|
||||
{/* )} */}
|
||||
</Grid>
|
||||
<Grid container xs={12} justifyContent="start" alignItems="center">
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
mb={SPACING.SMALL}
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
<Grid container gap={2}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a
|
||||
href={`${
|
||||
axios.defaults.baseURL
|
||||
}direct_purchase_excel/?date1=${selectedDate1}&date2=${selectedDate2}&role=${getRoleFromUrl()}&key=${userKey}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key || ""}`
|
||||
: ""
|
||||
}`}
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid container mt={2} mb={4} isDashboard sx={{ width: "100%" }}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={[
|
||||
"تعداد بارها",
|
||||
"تعداد درخواست دولتی",
|
||||
"تعداد درخواست آزاد",
|
||||
"تعداد بارهای دولتی",
|
||||
"تعداد بارهای آزاد",
|
||||
"تعداد درخواست (قطعه)",
|
||||
"میانگین وزنی",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"میانگین قیمت فروش مرغدار",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.lenKillRequest?.toLocaleString(),
|
||||
dashboardData?.freeDirectBuyingFalseQuantity?.toLocaleString(),
|
||||
dashboardData?.freeDirectBuyingTrueQuantity?.toLocaleString(),
|
||||
dashboardData?.lenKillRequestHasntFreeDirectBuying?.toLocaleString(),
|
||||
dashboardData?.lenKillRequestHasFreeDirectBuying?.toLocaleString(),
|
||||
dashboardData?.quantity?.toLocaleString(),
|
||||
dashboardData?.indexWight?.toFixed(1),
|
||||
Math.round(
|
||||
dashboardData?.quantity * dashboardData?.indexWight
|
||||
)?.toLocaleString(),
|
||||
Math.round(dashboardData?.amount)?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ثبت درخواست",
|
||||
"تاریخ کشتار",
|
||||
"خریدار",
|
||||
"نوع خرید",
|
||||
"محل کشتار",
|
||||
"مرغدار (تلفن)",
|
||||
"سن",
|
||||
"نژاد",
|
||||
"تعداد درخواست (قطعه)",
|
||||
"میانگین وزنی (کیلوگرم)",
|
||||
"وزن کل (کیلوگرم)",
|
||||
"قیمت فروش مرغدار (ریال)",
|
||||
"کداحراز",
|
||||
"حداکثر مهلت تسویه",
|
||||
"وضعیت",
|
||||
"تایید کننده",
|
||||
"توافق نامه",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="خرید مستقیم"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
import { IconButton, Popover, Tooltip } from "@mui/material";
|
||||
import React, { useContext, useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterDeleteAllocationForFreezing } from "../../services/slaughter-delete-allocation-for-freezing";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterAllocateToFreezing } from "../slaughter-allocate-to-freezing/SlaughterAllocateToFreezing";
|
||||
|
||||
export const SlaughterFreezingAllocationsOperations = ({
|
||||
item,
|
||||
fetchApiData,
|
||||
updateInventory,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
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}
|
||||
>
|
||||
<div style={{ padding: "20px" }}>
|
||||
<Grid container direction="column">
|
||||
<Tooltip placement="right" title="حذف انجماد">
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
|
||||
dispatch(
|
||||
slaughterDeleteAllocationForFreezing(item?.key)
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
fetchApiData();
|
||||
updateInventory();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip placement="right" title="ویرایش انجماد">
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش تخصیص به انجماد",
|
||||
content: (
|
||||
<SlaughterAllocateToFreezing
|
||||
fetchItems={fetchApiData}
|
||||
updateTable={updateInventory}
|
||||
isEdit
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,191 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { useDispatch } from "react-redux";
|
||||
import axios from "axios";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { SlaughterFreezingAllocationsOperations } from "../slaughter-freezing-allocations-operations/SlaughterFreezingAllocationsOperations";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
|
||||
export const SlaughterFreezingAllocations = ({
|
||||
updateFreezing,
|
||||
updateInventory,
|
||||
}) => {
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const [selectedDate2, setSelectedDate2] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
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 fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`cold-house-allocations/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.state === "pending"
|
||||
? "در انتظار تایید"
|
||||
: item?.state === "accepted"
|
||||
? "تایید شده"
|
||||
: "رد شده",
|
||||
formatJustDate(item?.date),
|
||||
item?.coldHouse?.name,
|
||||
item?.quantity?.toLocaleString(),
|
||||
item?.weight?.toLocaleString(),
|
||||
item?.realQuantity?.toLocaleString(),
|
||||
item?.realWeight?.toLocaleString(),
|
||||
<SlaughterFreezingAllocationsOperations
|
||||
key={i}
|
||||
item={item}
|
||||
fetchApiData={updateTable}
|
||||
updateInventory={updateInventory}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [dispatch, selectedDate1, selectedDate2, perPage, updateFreezing]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`cold-house-allocations/?role=${getRoleFromUrl()}&search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${1}&page_size=${perPage}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} size="small" />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} size="small" />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"وضعیت",
|
||||
"تاریخ ثبت",
|
||||
"سردخانه",
|
||||
"حجم",
|
||||
"وزن",
|
||||
"حجم واقعی",
|
||||
"وزن واقعی",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="تخصیص به انجماد"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,188 @@
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { Button, InputAdornment } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import {
|
||||
slaughterAllocateStewardService,
|
||||
slaughterEditAllocateStewardService,
|
||||
} from "../../services/slaughter-allocate-steward";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
export const SlaughterHouseColdHouseBarsEdit = ({
|
||||
sellerType,
|
||||
fetchData,
|
||||
sellType,
|
||||
updateTable,
|
||||
fetchApiData,
|
||||
editData,
|
||||
isColdHouse,
|
||||
priceInfo,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
weight: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.min(1, "یک مقدار مثبت وارد کنید!"),
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
weight: editData?.realWeightOfCarcasses || "",
|
||||
},
|
||||
validationSchema,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
}, []);
|
||||
|
||||
const successSubmit = () => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(fetchSlaughterBroadcastAndProducts());
|
||||
fetchApiData();
|
||||
updateTable();
|
||||
fetchData();
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
direction="column"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
gap={1}
|
||||
>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
fullWidth
|
||||
id="weight"
|
||||
label="وزن لاشه"
|
||||
variant="outlined"
|
||||
value={formik.values.weight}
|
||||
error={formik.touched.weight ? Boolean(formik.errors.weight) : null}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.weight && Boolean(formik.errors.weight)
|
||||
? formik.errors.weight
|
||||
: null
|
||||
}
|
||||
/>
|
||||
|
||||
<NumberInput
|
||||
disabled={priceInfo?.active}
|
||||
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
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
disabled={!formik.isValid}
|
||||
onClick={() => {
|
||||
let req = {};
|
||||
if (!editData) {
|
||||
req = {
|
||||
seller_type: sellerType,
|
||||
type: "manual",
|
||||
number_of_carcasses: 0,
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
sell_type: sellType,
|
||||
buyer_type: "ColdHouse",
|
||||
allocation_type: "ColdHouse",
|
||||
};
|
||||
} else {
|
||||
req = {
|
||||
weight_of_carcasses: formik.values.weight,
|
||||
allocation_key: editData?.key,
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,131 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Typography,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterEditDelegatesService } from "../../services/slaughter-get-delegates-service";
|
||||
|
||||
export const DelegatesLimitationForm = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const [hasLimitation, setHasLimitation] = useState(item?.limitation || false);
|
||||
const [governmentalValue, setGovernmentalValue] = useState(
|
||||
item?.governmentalLimitationWeight || 0
|
||||
);
|
||||
const [freeValue, setFreeValue] = useState(item?.freeLimitationWeight || 0);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitData = {
|
||||
key: item?.key,
|
||||
limitation: hasLimitation,
|
||||
governmental_limitation_weight: hasLimitation
|
||||
? Number(governmentalValue)
|
||||
: 0,
|
||||
free_limitation_weight: hasLimitation ? Number(freeValue) : 0,
|
||||
};
|
||||
|
||||
dispatch(slaughterEditDelegatesService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid container item xs={12} alignItems="center" gap={1}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
اطلاعات نماینده:
|
||||
</Typography>
|
||||
<Typography variant="h6" mb={0.75}>
|
||||
{item?.firstName || item?.first_name}{" "}
|
||||
{item?.lastName || item?.last_name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mb={1}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={hasLimitation}
|
||||
onChange={(e) => setHasLimitation(e.target.checked)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="محدودیت فروش روزانه"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{hasLimitation && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش دولتی (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={governmentalValue}
|
||||
onChange={(e) => setGovernmentalValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش آزاد (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={freeValue}
|
||||
onChange={(e) => setFreeValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={
|
||||
hasLimitation && governmentalValue === 0 && freeValue === 0
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,139 @@
|
||||
import { IconButton, Popover, Typography, Button } from "@mui/material";
|
||||
import React, { useState, useContext } from "react";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import ToggleOnIcon from "@mui/icons-material/ToggleOn";
|
||||
import ToggleOffIcon from "@mui/icons-material/ToggleOff";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterEditDelegatesService } from "../../services/slaughter-get-delegates-service";
|
||||
import { DelegatesLimitationForm } from "./DelegatesLimitationForm";
|
||||
|
||||
export const DelegatesOperations = ({ item, updateTable }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
const isActive = item?.active !== undefined ? item.active : !item?.trash;
|
||||
|
||||
const handleToggleActive = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
slaughterEditDelegatesService({
|
||||
key: item?.key,
|
||||
active: !isActive,
|
||||
})
|
||||
).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "10px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
color={isActive ? "error" : "success"}
|
||||
size="small"
|
||||
onClick={handleToggleActive}
|
||||
startIcon={
|
||||
isActive ? (
|
||||
<ToggleOffIcon fontSize="small" />
|
||||
) : (
|
||||
<ToggleOnIcon fontSize="small" />
|
||||
)
|
||||
}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
{isActive ? "غیرفعال کردن" : "فعال کردن"}
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تنظیم محدودیت فروش",
|
||||
content: (
|
||||
<DelegatesLimitationForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
size: 400,
|
||||
})
|
||||
);
|
||||
}}
|
||||
startIcon={<BlockIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
تنظیم محدودیت
|
||||
</Typography>
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,199 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetDelegatesService } from "../../services/slaughter-get-delegates-service";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { DelegatesOperations } from "./DelegatesOperations";
|
||||
|
||||
export const KillHouseDelegatesTab = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesService({
|
||||
type: "KillHouse",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.active !== undefined ? item.active : !item?.trash;
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
key={`limitation-${item?.key || i}`}
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
|
||||
const killhouseDisplay =
|
||||
item?.killHouse?.name && item?.killHouse?.mobile
|
||||
? `${item.killHouse.name} (${item.killHouse.mobile})`
|
||||
: item?.killHouse?.name
|
||||
? item.killHouse.name
|
||||
: "-";
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.firstName || item?.first_name || "-",
|
||||
item?.lastName || item?.last_name || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
killhouseDisplay,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
<Chip
|
||||
key={`status-${item?.key || i}`}
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>,
|
||||
<DelegatesOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesService({
|
||||
type: "KillHouse",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.SMALL} mb={2}>
|
||||
<form onSubmit={handleSubmit} style={{ width: "100%" }}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<ResponsiveTable
|
||||
title="نمایندگان کشتارگاهها"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"کشتارگاه",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import React, { useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { Tab, Tabs, Box } from "@mui/material";
|
||||
import { StewardDelegatesTab } from "./StewardDelegatesTab";
|
||||
import { KillHouseDelegatesTab } from "./KillHouseDelegatesTab";
|
||||
|
||||
export const SlaughterHouseDelegates = () => {
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Tabs value={value} onChange={handleChange}>
|
||||
<Tab label="مباشرین" value={0} />
|
||||
<Tab label="کشتارگاهها" value={1} />
|
||||
</Tabs>
|
||||
|
||||
<Box sx={{ width: "100%", mt: 2 }}>
|
||||
{value === 0 && <StewardDelegatesTab />}
|
||||
{value === 1 && <KillHouseDelegatesTab />}
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,199 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetDelegatesService } from "../../services/slaughter-get-delegates-service";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { DelegatesOperations } from "./DelegatesOperations";
|
||||
|
||||
export const StewardDelegatesTab = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesService({
|
||||
type: "Steward",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.active !== undefined ? item.active : !item?.trash;
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
key={`limitation-${item?.key || i}`}
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
|
||||
const stewardDisplay =
|
||||
item?.steward?.name && item?.steward?.user?.mobile
|
||||
? `${item.steward.name} (${item.steward.user.mobile})`
|
||||
: item?.steward?.name
|
||||
? item.steward.name
|
||||
: "-";
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.firstName || item?.first_name || "-",
|
||||
item?.lastName || item?.last_name || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
stewardDisplay,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
<Chip
|
||||
key={`status-${item?.key || i}`}
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>,
|
||||
<DelegatesOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesService({
|
||||
type: "Steward",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.SMALL} mb={2}>
|
||||
<form onSubmit={handleSubmit} style={{ width: "100%" }}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<ResponsiveTable
|
||||
title="نمایندگان مباشرین"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"مباشر",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,307 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { useDispatch } from "react-redux";
|
||||
import axios from "axios";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { slaughterGetDispenserDashboardService } from "../../services/slaughter-house-get-dispenser-dashboard-service";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
|
||||
export const SlaughterHouseDispenserDetails = () => {
|
||||
const { key } = useParams();
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
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 [dashboardData, setDashboardData] = useState();
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
let response;
|
||||
dispatch(LOADING_START());
|
||||
response = await axios.get(
|
||||
`dispenser-allocations/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}&dispenser_key=${key}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
// const updateTable = () => {
|
||||
// fetchApiData(page !== 0 ? page : 1);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetDispenserDashboardService({
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
key: key,
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}, [selectedDate1, selectedDate2]);
|
||||
|
||||
const getDispenserType = (item) => {
|
||||
let type = "";
|
||||
switch (item?.dispenser?.dispenserType) {
|
||||
case "inductor":
|
||||
type = "واسطه";
|
||||
break;
|
||||
case "salesman":
|
||||
type = "فروشنده";
|
||||
break;
|
||||
case "driver":
|
||||
type = `راننده - ${item?.dispenser?.car} (${item?.dispenser?.pelak})`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.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 [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
`${item?.dispenser?.user?.fullname} (${item?.dispenser?.user?.mobile})`,
|
||||
getDispenserType(item),
|
||||
item?.guilds ? item?.guilds?.guildsId : item?.steward?.guilds?.guildsId,
|
||||
formatJustDate(item.date),
|
||||
sellerType,
|
||||
sellType,
|
||||
item?.guilds
|
||||
? item?.guilds?.guildsName
|
||||
: item?.steward?.guilds?.guildsName,
|
||||
item?.guilds
|
||||
? item?.guilds?.user.fullname
|
||||
: item?.steward?.guilds?.user.fullname,
|
||||
item?.guilds
|
||||
? item?.guilds?.user.nationalId
|
||||
: item?.steward?.guilds?.user.nationalId,
|
||||
item?.guilds
|
||||
? item?.guilds?.user.mobile
|
||||
: item?.steward?.guilds?.user.mobile,
|
||||
item?.guilds
|
||||
? item?.guilds?.typeActivity
|
||||
: item?.steward?.guilds?.typeActivity,
|
||||
item?.guilds
|
||||
? item?.guilds?.areaActivity
|
||||
: item?.steward?.guilds?.areaActivity,
|
||||
item?.guilds
|
||||
? item?.guilds?.licenseNumber
|
||||
: item?.steward?.guilds?.licenseNumber,
|
||||
item?.guilds
|
||||
? item?.guilds?.user?.city?.name
|
||||
: item?.steward?.guilds?.user?.city?.name,
|
||||
item?.numberOfCarcasses,
|
||||
item?.weightOfCarcasses,
|
||||
item?.loggedRegistrationCode ? item.loggedRegistrationCode : "-",
|
||||
item?.receiverState === "accepted"
|
||||
? "تایید شده"
|
||||
: item?.receiverState === "rejected"
|
||||
? "رد شده"
|
||||
: "در انتظار تایید",
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedDate1, selectedDate2, perPage]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`dispenser-allocations/?role=${getRoleFromUrl()}&search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${1}&page_size=${perPage}&dispenser_key=${key}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} size="small" />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} size="small" />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} justifyContent="start" alignItems="center">
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
data={[
|
||||
[
|
||||
dashboardData?.numberOfAllocations?.toLocaleString(),
|
||||
dashboardData?.totalQuantity?.toLocaleString(),
|
||||
dashboardData?.totalWeight?.toLocaleString(),
|
||||
dashboardData?.numberOfStewardsAllocations?.toLocaleString(),
|
||||
dashboardData?.stewardTotalQuantity?.toLocaleString(),
|
||||
dashboardData?.stewardTotalWeight?.toLocaleString(),
|
||||
dashboardData?.numberOfGuildsAllocations?.toLocaleString(),
|
||||
dashboardData?.guildTotalQuantity?.toLocaleString(),
|
||||
dashboardData?.guildTotalWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
columns={[
|
||||
"تعداد کل تخصیصات",
|
||||
"حجم کل تخصیصات",
|
||||
"وزن کل تخصیصات",
|
||||
"تعداد مباشرین تختصیص داده شده",
|
||||
"حجم تخصیصی به مباشرین",
|
||||
"وزن تخصیصی به مباشرین",
|
||||
"تعداد اصناف تختصیص داده شده",
|
||||
"حجم تخصیصی به اصناف",
|
||||
"وزن تخصیصی به اصناف",
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"توزیع کننده",
|
||||
"نوع توزیع کننده",
|
||||
"شناسه صنف",
|
||||
"تاریخ ثبت",
|
||||
"ماهیت",
|
||||
"نوع تخصیص",
|
||||
"نام واحد صنفی",
|
||||
"نام شخص/شرکت",
|
||||
"کدملی",
|
||||
"موبایل",
|
||||
"نوع فعالیت",
|
||||
"حوزه فعالیت",
|
||||
"شماره مجوز",
|
||||
"شهرستان",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"کداحراز",
|
||||
"وضعیت",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="اطلاعات توزیع کننده"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
import React, { useContext } from "react";
|
||||
import { Button, Checkbox, FormControlLabel, FormGroup } from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterHouseEditDispenserService } from "../../services/slaughter-house-submit-dispenser-service";
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
free_sale: Yup.boolean(),
|
||||
free_guilds: Yup.boolean(),
|
||||
free_stewards: Yup.boolean(),
|
||||
});
|
||||
|
||||
export const SlaughterHouseDispensersAccessLevel = ({ updateTable, item }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
free_sale: item?.freeSale ? item?.freeSale : false,
|
||||
free_guilds: item?.freeGuilds ? item?.freeGuilds : false,
|
||||
free_stewards: item?.freeStewards ? item?.freeStewards : false,
|
||||
},
|
||||
validationSchema: validationSchema,
|
||||
onSubmit: (values) => {
|
||||
dispatch(
|
||||
slaughterHouseEditDispenserService({
|
||||
dispenser_key: item?.key,
|
||||
type: "update-acceess-level",
|
||||
free_sale: values.free_sale,
|
||||
free_guilds: values.free_guilds,
|
||||
free_stewards: values.free_stewards,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(CLOSE_MODAL());
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container xs={12} direction="column">
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
id="free_sale"
|
||||
name="free_sale"
|
||||
checked={formik.values.free_sale}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
}
|
||||
label="اجازه فروش آزاد"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
id="free_guilds"
|
||||
name="free_guilds"
|
||||
checked={formik.values.free_guilds}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
}
|
||||
label="فروش به اصناف آزاد"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
id="free_stewards"
|
||||
name="free_stewards"
|
||||
checked={formik.values.free_stewards}
|
||||
onChange={formik.handleChange}
|
||||
/>
|
||||
}
|
||||
label="فروش به مباشرین آزاد"
|
||||
/>
|
||||
</FormGroup>
|
||||
{formik.touched.free_stewards && formik.errors.free_stewards ? (
|
||||
<div style={{ color: "red" }}>{formik.errors.free_stewards}</div>
|
||||
) : null}
|
||||
<Button
|
||||
fullWidth
|
||||
color="primary"
|
||||
variant="contained"
|
||||
type="submit"
|
||||
sx={{ marginTop: 2 }}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,124 @@
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { DRAWER, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SlaughterHouseSubmitDispenser } from "../slaughter-house-submit-dispenser/SlaughterHouseSubmitDispenser";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import SubtitlesIcon from "@mui/icons-material/Subtitles";
|
||||
import { SlaughterHouseDispensersAccessLevel } from "../slaughter-house-dispensers-access-level/SlaughterHouseDispensersAccessLevel";
|
||||
|
||||
export const SlaughterHouseDispensersOperation = ({ item, updateTable }) => {
|
||||
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;
|
||||
|
||||
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}
|
||||
>
|
||||
<div style={{ padding: "10px" }}>
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
gap={1}
|
||||
alignItems="flex-start"
|
||||
style={{ width: 180 }}
|
||||
>
|
||||
<Tooltip placement="left" title="ویرایش توزیع کننده">
|
||||
<Button
|
||||
size="small"
|
||||
color="primary"
|
||||
startIcon={<EditIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ویرایش توزیع کننده",
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterHouseSubmitDispenser
|
||||
updateTable={updateTable}
|
||||
isEdit
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
ویرایش توزیع کننده
|
||||
</Typography>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip placement="left" title="تعیین سطح دسترسی توزیع کننده">
|
||||
<Button
|
||||
size="small"
|
||||
color="secondary"
|
||||
startIcon={<SubtitlesIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تعیین سطح دسترسی توزیع کننده",
|
||||
content: (
|
||||
<SlaughterHouseDispensersAccessLevel
|
||||
updateTable={updateTable}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
تعیین سطح دسترسی
|
||||
</Typography>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,252 @@
|
||||
import React from "react";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { NavLink } from "../../../../components/nav-link/NavLink";
|
||||
import LinkItem from "../../../../components/link-item/LinkItem";
|
||||
import { VscBroadcast, VscPerson } from "react-icons/vsc";
|
||||
import {
|
||||
ROUTE_ADMINX_DELEGATES_MANAGEMENT,
|
||||
ROUTE_ADMINX_DISPENSERS_INVENTORY,
|
||||
ROUTE_ADMINX_DISPENSERS_KILLHOUSES,
|
||||
ROUTE_ADMINX_DISPENSERS_MANAGEMENT,
|
||||
ROUTE_ADMINX_DISPENSERS_MANAGEMENT_V2,
|
||||
ROUTE_ADMINX_DISPENSERS_STEWARDS,
|
||||
ROUTE_ADMINX_DISPENSERS_STOCK,
|
||||
ROUTE_ADMINX_SALE_DESTRIBUTION_DETAILS,
|
||||
ROUTE_ADMINX_TRANSACTIONS,
|
||||
ROUTE_CITY_DISPENSERS_INVENTORY,
|
||||
ROUTE_CITY_REQUEST_DISTRIBUTION,
|
||||
ROUTE_CITY_REQUEST_TRANSACTIONS,
|
||||
ROUTE_PROVINCE_DISPENSERS_INVENTORY,
|
||||
ROUTE_PROVINCE_DISPENSERS_KILLHOUSES,
|
||||
ROUTE_PROVINCE_DISPENSERS_MANAGEMENT,
|
||||
ROUTE_PROVINCE_DISPENSERS_STEWARDS,
|
||||
ROUTE_PROVINCE_FINANCIAL_TRANSACTIONS,
|
||||
ROUTE_PROVINCE_SALE_DESTRIBUTION_DETAILS,
|
||||
ROUTE_PROVINCE_SUPERVISOR_DISPENSERS_INVENTORY,
|
||||
ROUTE_PROVINCE_SUPERVISOR_DISPENSERS_STOCK,
|
||||
ROUTE_PROVINCE_SUPERVISOR_REQUEST_DISTRIBUTION,
|
||||
ROUTE_PROVINCE_SUPERVISOR_REQUEST_TRANSACTIONS,
|
||||
ROUTE_PROVINCE_TRANSACTIONS,
|
||||
ROUTE_SLAUGHTER_DISPENSERS_KILLHOUSES,
|
||||
ROUTE_SLAUGHTER_DISPENSERS_MANAGEMENT,
|
||||
ROUTE_SLAUGHTER_DISPENSERS_STEWARDS,
|
||||
ROUTE_SUPER_ADMIN_DESTRIBUTION_DETAILS,
|
||||
ROUTE_SUPER_ADMIN_DISPENSERS_INVENTORY,
|
||||
ROUTE_SUPER_ADMIN_DISPENSERS_KILLHOUSES,
|
||||
ROUTE_SUPER_ADMIN_DISPENSERS_MANAGEMENT,
|
||||
ROUTE_SUPER_ADMIN_DISPENSERS_STEWARDS,
|
||||
ROUTE_SUPER_ADMIN_DISPENSERS_STOCK,
|
||||
ROUTE_SUPER_ADMIN_TRANSACTIONS,
|
||||
} from "../../../../routes/routes";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { FaMoneyBill, FaStore, FaWarehouse } from "react-icons/fa";
|
||||
import BadgeIcon from "@mui/icons-material/Badge";
|
||||
|
||||
const ROUTE_MAP = {
|
||||
management: {
|
||||
KillHouse: ROUTE_SLAUGHTER_DISPENSERS_MANAGEMENT,
|
||||
AdminX: ROUTE_ADMINX_DISPENSERS_MANAGEMENT,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DISPENSERS_MANAGEMENT,
|
||||
AdminXX: ROUTE_ADMINX_DISPENSERS_MANAGEMENT_V2,
|
||||
AdminXXX: ROUTE_ADMINX_DELEGATES_MANAGEMENT,
|
||||
default: ROUTE_PROVINCE_DISPENSERS_MANAGEMENT,
|
||||
},
|
||||
killhouses: {
|
||||
KillHouse: ROUTE_SLAUGHTER_DISPENSERS_KILLHOUSES,
|
||||
AdminX: ROUTE_ADMINX_DISPENSERS_KILLHOUSES,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DISPENSERS_KILLHOUSES,
|
||||
default: ROUTE_PROVINCE_DISPENSERS_KILLHOUSES,
|
||||
},
|
||||
stewards: {
|
||||
KillHouse: ROUTE_SLAUGHTER_DISPENSERS_STEWARDS,
|
||||
AdminX: ROUTE_ADMINX_DISPENSERS_STEWARDS,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DISPENSERS_STEWARDS,
|
||||
default: ROUTE_PROVINCE_DISPENSERS_STEWARDS,
|
||||
},
|
||||
inventory: {
|
||||
AdminX: ROUTE_ADMINX_DISPENSERS_INVENTORY,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DISPENSERS_INVENTORY,
|
||||
CityPoultry: ROUTE_CITY_DISPENSERS_INVENTORY,
|
||||
ProvinceSupervisor: ROUTE_PROVINCE_SUPERVISOR_DISPENSERS_INVENTORY,
|
||||
default: ROUTE_PROVINCE_DISPENSERS_INVENTORY,
|
||||
},
|
||||
distribution: {
|
||||
AdminX: ROUTE_ADMINX_SALE_DESTRIBUTION_DETAILS,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DESTRIBUTION_DETAILS,
|
||||
ProvinceOperator: ROUTE_PROVINCE_SALE_DESTRIBUTION_DETAILS,
|
||||
CityPoultry: ROUTE_CITY_REQUEST_DISTRIBUTION,
|
||||
ProvinceSupervisor: ROUTE_PROVINCE_SUPERVISOR_REQUEST_DISTRIBUTION,
|
||||
default: ROUTE_PROVINCE_TRANSACTIONS,
|
||||
},
|
||||
transactions: {
|
||||
AdminX: ROUTE_ADMINX_TRANSACTIONS,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_TRANSACTIONS,
|
||||
ProvinceFinancial: ROUTE_PROVINCE_FINANCIAL_TRANSACTIONS,
|
||||
CityPoultry: ROUTE_CITY_REQUEST_TRANSACTIONS,
|
||||
ProvinceSupervisor: ROUTE_PROVINCE_SUPERVISOR_REQUEST_TRANSACTIONS,
|
||||
default: ROUTE_PROVINCE_TRANSACTIONS,
|
||||
},
|
||||
stock: {
|
||||
AdminX: ROUTE_ADMINX_DISPENSERS_STOCK,
|
||||
SuperAdmin: ROUTE_SUPER_ADMIN_DISPENSERS_STOCK,
|
||||
ProvinceSupervisor: ROUTE_PROVINCE_SUPERVISOR_DISPENSERS_STOCK,
|
||||
},
|
||||
};
|
||||
|
||||
const getRoute = (routeType, role) => {
|
||||
const routeMap = ROUTE_MAP[routeType];
|
||||
return routeMap[role] || routeMap.default || null;
|
||||
};
|
||||
|
||||
const isActive = (pathname, route) => (pathname === route ? "true" : null);
|
||||
|
||||
export const SlaughterHouseDispensersOperations = () => {
|
||||
const { pathname } = useLocation();
|
||||
const role = getRoleFromUrl();
|
||||
const isKillHouse = role === "KillHouse";
|
||||
const isAdminX = role === "AdminX";
|
||||
const hasStockAccess = [
|
||||
"AdminX",
|
||||
"SuperAdmin",
|
||||
"ProvinceSupervisor",
|
||||
].includes(role);
|
||||
|
||||
const managementRoute = getRoute("management", role);
|
||||
const managementRouteV2 = getRoute("management", "AdminXX");
|
||||
const managementRouteDelegates = getRoute("management", "AdminXXX");
|
||||
const killhousesRoute = getRoute("killhouses", role);
|
||||
const stewardsRoute = getRoute("stewards", role);
|
||||
const inventoryRoute = getRoute("inventory", role);
|
||||
const distributionRoute = getRoute("distribution", role);
|
||||
const transactionsRoute = getRoute("transactions", role);
|
||||
const stockRoute = getRoute("stock", role);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
p={SPACING.SMALL}
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
justifyContent="center"
|
||||
style={{ placeContent: "baseline" }}
|
||||
>
|
||||
{isAdminX && (
|
||||
<Grid container direction="column" style={{ width: "100%" }}>
|
||||
<Grid container gap={SPACING.SMALL} justifyContent="center">
|
||||
<NavLink
|
||||
to={managementRouteDelegates}
|
||||
active={isActive(pathname, managementRouteDelegates)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<BadgeIcon fontSize="large" sx={{ color: "#244CCC" }} />}
|
||||
title="مدیریت نمایندگان"
|
||||
description="مدیریت نمایندگان"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={managementRouteV2}
|
||||
active={isActive(pathname, managementRouteV2)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscPerson size={30} color="#244CCC" />}
|
||||
title="مدیریت توزیع کنندگان دوم"
|
||||
description="مدیریت توزیع کنندگان دوم"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={managementRoute}
|
||||
active={isActive(pathname, managementRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscPerson size={30} color="#244CCC" />}
|
||||
title="مدیریت توزیع کنندگان"
|
||||
description="مدیریت توزیع کنندگان"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
{!isKillHouse && (
|
||||
<NavLink
|
||||
to={killhousesRoute}
|
||||
active={isActive(pathname, killhousesRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<FaStore size={30} color="#244CCC" />}
|
||||
title="مدیریت کشتارگاه ها"
|
||||
description="مدیریت کشتارگاه ها"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
{!isKillHouse && (
|
||||
<NavLink
|
||||
to={stewardsRoute}
|
||||
active={isActive(pathname, stewardsRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscBroadcast size={30} color="#244CCC" />}
|
||||
title="مدیریت مباشرین"
|
||||
description="مدیریت مباشرین"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid container direction="column" style={{ width: "100%" }}>
|
||||
<Grid container gap={SPACING.SMALL} justifyContent="center">
|
||||
{!isKillHouse && inventoryRoute && (
|
||||
<NavLink
|
||||
to={inventoryRoute}
|
||||
active={isActive(pathname, inventoryRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<FaStore size={30} color="#244CCC" />}
|
||||
title="توزیع/فروش کشتارگاه"
|
||||
description="توزیع/فروش کشتارگاه"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
{!isKillHouse && distributionRoute && (
|
||||
<NavLink
|
||||
to={distributionRoute}
|
||||
active={isActive(pathname, distributionRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<FaMoneyBill size={30} color="#244CCC" />}
|
||||
title=" توزیع/فروش مباشر"
|
||||
description=" توزیع/فروش مباشر"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
{!isKillHouse && transactionsRoute && (
|
||||
<NavLink
|
||||
to={transactionsRoute}
|
||||
active={isActive(pathname, transactionsRoute)}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<FaWarehouse size={30} color="#244CCC" />}
|
||||
title="مدیریت انبار صنوف"
|
||||
description="تراکنش ها"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
{hasStockAccess && stockRoute && (
|
||||
<NavLink to={stockRoute} active={isActive(pathname, stockRoute)}>
|
||||
<LinkItem
|
||||
icon={<FaWarehouse size={30} color="#244CCC" />}
|
||||
title="مانده انبار"
|
||||
description="مانده انبار"
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,264 @@
|
||||
import React, { useContext } from "react";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Button, TextField, Typography, Box } from "@mui/material";
|
||||
import PersonIcon from "@mui/icons-material/Person";
|
||||
import PublicIcon from "@mui/icons-material/Public";
|
||||
import BadgeIcon from "@mui/icons-material/Badge";
|
||||
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
|
||||
import AccountBoxIcon from "@mui/icons-material/AccountBox";
|
||||
import BusinessIcon from "@mui/icons-material/Business";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterHouseEditDispenserService } from "../../services/slaughter-house-submit-dispenser-service";
|
||||
|
||||
const InfoBox = ({ icon: Icon, label, value, iconSx }) => (
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems={iconSx ? "flex-start" : "center"}
|
||||
gap={1}
|
||||
px={1.5}
|
||||
py={0.5}
|
||||
bgcolor="#f5f5f5"
|
||||
borderRadius={1}
|
||||
>
|
||||
<Icon color="action" sx={iconSx} />
|
||||
<Box>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{label}
|
||||
</Typography>
|
||||
<Typography variant="body1">{value || "-"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const getValidationSchema = () =>
|
||||
yup.object({
|
||||
mobile: yup
|
||||
.string()
|
||||
.required("شماره همراه الزامی است")
|
||||
.matches(/^09\d{9}$/, "شماره تلفن باید با 09 شروع شود و 11 رقم باشد"),
|
||||
});
|
||||
|
||||
const DispenserForm = ({ formik, userInfo }) => {
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
{userInfo && (
|
||||
<Grid container spacing={2} xs={12} mb={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color="text.secondary"
|
||||
gutterBottom
|
||||
sx={{ mb: 1 }}
|
||||
>
|
||||
اطلاعات شخصی
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="کد ملی"
|
||||
value={formik.values.nationalId}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام پدر"
|
||||
value={userInfo.fatherName}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={CalendarTodayIcon}
|
||||
label="تاریخ تولد"
|
||||
value={userInfo.birthday}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={AccountBoxIcon}
|
||||
label="جنسیت"
|
||||
value={userInfo.gender ? "مرد" : "زن"}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="شماره شناسنامه"
|
||||
value={userInfo.nationalCode}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid container spacing={2} xs={12}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام"
|
||||
value={formik.values.first_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام خانوادگی"
|
||||
value={formik.values.last_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox icon={PublicIcon} label="شهر" value={formik.values.city} />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="نوع توزیع کننده"
|
||||
value={
|
||||
formik.values.dispenser_type === "inductor"
|
||||
? "واسطه"
|
||||
: formik.values.dispenser_type === "salesman"
|
||||
? "فروشنده"
|
||||
: formik.values.dispenser_type === "driver"
|
||||
? "راننده"
|
||||
: formik.values.dispenser_type
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{formik.values.dispenser_type === "driver" && (
|
||||
<>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="نوع خودرو"
|
||||
value={formik.values.driver_car_type}
|
||||
/>
|
||||
</Grid>
|
||||
{formik.values.pelak && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="پلاک خودرو"
|
||||
value={formik.values.pelak}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="سقف محدودیت"
|
||||
value={formik.values.limitation_amount || 0}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<TextField
|
||||
label="شماره همراه"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="mobile"
|
||||
name="mobile"
|
||||
value={formik.values.mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={Boolean(formik.errors.mobile)}
|
||||
helperText={formik.errors.mobile}
|
||||
inputProps={{ maxLength: 11 }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={!formik.isValid}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export const AllDispensersEditForm = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const nationalId = item?.user?.nationalId || item?.user?.nationalCode;
|
||||
|
||||
// Extract userInfo from item.user object
|
||||
const userInfo = item?.user
|
||||
? {
|
||||
nationalCode: item.user.nationalId || item.user.nationalCode || null,
|
||||
fatherName: item.user.fatherName || null,
|
||||
birthday: item.user.birthday || null,
|
||||
gender: item.user.gender,
|
||||
identityNo: item.user.identityNo || null,
|
||||
identitySeries: item.user.identitySeries || null,
|
||||
identitySerial: item.user.identitySerial || null,
|
||||
}
|
||||
: null;
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
first_name: item?.user?.firstName || "",
|
||||
last_name: item?.user?.lastName || "",
|
||||
mobile: item?.user?.mobile || "",
|
||||
city: item?.user?.cityName || "",
|
||||
national_id: nationalId || "",
|
||||
dispenser_type: item?.dispenserType || "inductor",
|
||||
limitation_amount: item?.limitationAmount || 0,
|
||||
driver_car_type: item?.car || "",
|
||||
pelak: item?.pelak || "",
|
||||
},
|
||||
enableReinitialize: true,
|
||||
validationSchema: getValidationSchema(),
|
||||
onSubmit: (values) => {
|
||||
const submitData = {
|
||||
key: item?.key,
|
||||
mobile: values.mobile,
|
||||
};
|
||||
|
||||
dispatch(slaughterHouseEditDispenserService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return <DispenserForm formik={formik} userInfo={userInfo} />;
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
import { IconButton, Popover, Typography, Button } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AllDispensersEditForm } from "./AllDispensersEditForm";
|
||||
|
||||
export const AllDispensersOperations = ({ item, updateTable }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<div style={{ padding: "10px" }}>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش توزیع کننده",
|
||||
content: (
|
||||
<AllDispensersEditForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
size: 620,
|
||||
})
|
||||
);
|
||||
}}
|
||||
startIcon={<EditIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
ویرایش
|
||||
</Typography>
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,162 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetDispenserService } from "../../services/slaughter-get-dispenser-service";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { AllDispensersOperations } from "./AllDispensersOperations";
|
||||
|
||||
export const AllDispensersTab = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.user?.firstName || "-",
|
||||
item?.user?.lastName || "-",
|
||||
item?.user?.mobile || "-",
|
||||
item?.user?.cityName || "-",
|
||||
<AllDispensersOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.SMALL} mb={2}>
|
||||
<form onSubmit={handleSubmit} style={{ width: "100%" }}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<ResponsiveTable
|
||||
title="کل توزیع کنندگان"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,135 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Typography,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterEditDispenserInfoService } from "../../services/slaughter-edit-dispenser-info";
|
||||
|
||||
export const DispenserInfoLimitationForm = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const [hasLimitation, setHasLimitation] = useState(item?.limitation || false);
|
||||
const [governmentalValue, setGovernmentalValue] = useState(
|
||||
|
||||
item?.governmentalLimitationWeight ||
|
||||
0
|
||||
);
|
||||
const [freeValue, setFreeValue] = useState(
|
||||
item?.freeLimitationWeight || 0
|
||||
);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitData = {
|
||||
key: item?.key,
|
||||
limitation: hasLimitation,
|
||||
governmental_limitation_weight: hasLimitation
|
||||
? Number(governmentalValue)
|
||||
: 0,
|
||||
free_limitation_weight: hasLimitation ? Number(freeValue) : 0,
|
||||
};
|
||||
|
||||
dispatch(slaughterEditDispenserInfoService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid container item xs={12} alignItems="center" gap={1}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
اطلاعات توزیع کننده:
|
||||
</Typography>
|
||||
<Typography variant="h6" mb={0.75}>
|
||||
{item?.firstName} {item?.lastName}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mb={1}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={hasLimitation}
|
||||
onChange={(e) => setHasLimitation(e.target.checked)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="محدودیت فروش روزانه"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{hasLimitation && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش دولتی (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={governmentalValue}
|
||||
onChange={(e) => setGovernmentalValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش آزاد (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={freeValue}
|
||||
onChange={(e) => setFreeValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={
|
||||
hasLimitation && governmentalValue === 0 && freeValue === 0
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { IconButton, Popover, Typography, Button } from "@mui/material";
|
||||
import React, { useState, useContext } from "react";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import ToggleOnIcon from "@mui/icons-material/ToggleOn";
|
||||
import ToggleOffIcon from "@mui/icons-material/ToggleOff";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterEditDispenserInfoService } from "../../services/slaughter-edit-dispenser-info";
|
||||
import { DispenserInfoLimitationForm } from "./DispenserInfoLimitationForm";
|
||||
|
||||
export const DispenserInfoOperations = ({ item, updateTable }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
const isActive = item?.active;
|
||||
|
||||
const handleToggleActive = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
slaughterEditDispenserInfoService({
|
||||
key: item?.key,
|
||||
active: !isActive,
|
||||
})
|
||||
).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
padding: "10px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
color={isActive ? "error" : "success"}
|
||||
size="small"
|
||||
onClick={handleToggleActive}
|
||||
startIcon={
|
||||
isActive ? (
|
||||
<ToggleOffIcon fontSize="small" />
|
||||
) : (
|
||||
<ToggleOnIcon fontSize="small" />
|
||||
)
|
||||
}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
{isActive ? "غیرفعال کردن" : "فعال کردن"}
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تنظیم محدودیت فروش",
|
||||
content: (
|
||||
<DispenserInfoLimitationForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
size: 400,
|
||||
})
|
||||
);
|
||||
}}
|
||||
startIcon={<BlockIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
تنظیم محدودیت
|
||||
</Typography>
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetDispenserInfoService } from "../../services/slaughter-get-dispenser-info";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { DispenserInfoOperations } from "./DispenserInfoOperations";
|
||||
|
||||
export const KillHouseDispensersTab = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
type: "KillHouse",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.active;
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
key={`limitation-${item?.key || i}`}
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
|
||||
const killhouseDisplay =
|
||||
item?.killHouse?.name && item?.killHouse?.mobile
|
||||
? `${item.killHouse.name} (${item.killHouse.mobile})`
|
||||
: item?.killHouse?.name
|
||||
? item.killHouse.name
|
||||
: "-";
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.firstName || "-",
|
||||
item?.lastName || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
killhouseDisplay,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
<Chip
|
||||
key={`status-${item?.key || i}`}
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>,
|
||||
<DispenserInfoOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
type: "KillHouse",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.SMALL} mb={2}>
|
||||
<form onSubmit={handleSubmit} style={{ width: "100%" }}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<ResponsiveTable
|
||||
title="توزیع کنندگان کشتارگاهها"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"کشتارگاه",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import React, { useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { Tab, Tabs, Box } from "@mui/material";
|
||||
import { AllDispensersTab } from "./AllDispensersTab";
|
||||
import { KillHouseDispensersTab } from "./KillHouseDispensersTab";
|
||||
import { StewardDispensersTab } from "./StewardDispensersTab";
|
||||
|
||||
export const SlaughterHouseDispensersV2 = () => {
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Tabs value={value} onChange={handleChange}>
|
||||
<Tab label="کل توزیع کنندگان" value={0} />
|
||||
<Tab label="توزیع کنندگان کشتارگاهها" value={1} />
|
||||
<Tab label="توزیع کنندگان مباشرین" value={2} />
|
||||
</Tabs>
|
||||
|
||||
<Box sx={{ width: "100%", mt: 2 }}>
|
||||
{value === 0 && <AllDispensersTab />}
|
||||
{value === 1 && <KillHouseDispensersTab />}
|
||||
{value === 2 && <StewardDispensersTab />}
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,199 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetDispenserInfoService } from "../../services/slaughter-get-dispenser-info";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { DispenserInfoOperations } from "./DispenserInfoOperations";
|
||||
|
||||
export const StewardDispensersTab = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
type: "Steward",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.active;
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
key={`limitation-${item?.key || i}`}
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
|
||||
const stewardDisplay =
|
||||
item?.steward?.name && item?.steward?.user?.mobile
|
||||
? `${item.steward.name} (${item.steward.user.mobile})`
|
||||
: item?.steward?.name
|
||||
? item.steward.name
|
||||
: "-";
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.firstName || "-",
|
||||
item?.lastName || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
stewardDisplay,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
<Chip
|
||||
key={`status-${item?.key || i}`}
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>,
|
||||
<DispenserInfoOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
type: "Steward",
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Grid container gap={SPACING.SMALL} mb={2}>
|
||||
<form onSubmit={handleSubmit} style={{ width: "100%" }}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<ResponsiveTable
|
||||
title="توزیع کنندگان مباشرین"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"مباشر",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,351 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch } from "react-redux";
|
||||
import axios from "axios";
|
||||
import { SlaughterHouseSubmitDispenser } from "../slaughter-house-submit-dispenser/SlaughterHouseSubmitDispenser";
|
||||
import { SlaughterHouseDispensersOperation } from "../slaughter-house-dispensers-operation/SlaughterHouseDispensersOperation";
|
||||
import { slaughterGetDispenserDashboard } from "../../services/slaughter-house-get-dispenser-dashboard";
|
||||
import {
|
||||
ROUTE_ADMINX_DISPENSER_DETAILS,
|
||||
ROUTE_PROVINCE_DISPENSER_DETAILS,
|
||||
ROUTE_SLAUGHTER_DISPENSER_DETAILS,
|
||||
ROUTE_SUPER_ADMIN_DISPENSER_DETAILS,
|
||||
} from "../../../../routes/routes";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
|
||||
export const SlaughterHouseDispensers = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
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 [value, setValue] = useState(0);
|
||||
const [dashboardData, setDashboardData] = useState();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
let response;
|
||||
dispatch(LOADING_START());
|
||||
response = await axios.get(
|
||||
`dispenser/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [value]);
|
||||
|
||||
const getDispenserType = (item) => {
|
||||
let type = "";
|
||||
switch (item?.dispenserType) {
|
||||
case "inductor":
|
||||
type = "واسطه";
|
||||
break;
|
||||
case "salesman":
|
||||
type = "فروشنده";
|
||||
break;
|
||||
case "driver":
|
||||
type = `راننده - ${item?.car} (${item?.pelak})`;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + (perPage * page) / 2 + 1,
|
||||
getDispenserType(item),
|
||||
item?.user?.fullname,
|
||||
item?.user?.mobile,
|
||||
item?.user?.city?.cityName,
|
||||
item?.killHouse?.name,
|
||||
item?.limitationAmount?.toLocaleString(),
|
||||
item?.active ? "فعال" : "غیر فعال",
|
||||
item?.allocationsInfo?.numberOfAllocations?.toLocaleString(),
|
||||
item?.allocationsInfo?.totalWeight?.toLocaleString(),
|
||||
item?.allocationsInfo?.totalQuantity?.toLocaleString(),
|
||||
item?.allocationsInfo?.numberOfTodayAllocations?.toLocaleString(),
|
||||
item?.allocationsInfo?.totalTodayQuantity?.toLocaleString(),
|
||||
item?.allocationsInfo?.totalTodayWeight?.toLocaleString(),
|
||||
value === 0 ? (
|
||||
<SlaughterHouseDispensersOperation
|
||||
key={i}
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
) : (
|
||||
<Tooltip key={i} title="جزئیات" placement="left">
|
||||
<IconButton
|
||||
color="success"
|
||||
onClick={() => {
|
||||
navigate(
|
||||
getRoleFromUrl() === "KillHouse"
|
||||
? `${ROUTE_SLAUGHTER_DISPENSER_DETAILS}/${item.key}`
|
||||
: getRoleFromUrl() === "AdminX"
|
||||
? `${ROUTE_ADMINX_DISPENSER_DETAILS}/${item.key}`
|
||||
: getRoleFromUrl() === "SuperAdmin"
|
||||
? `${ROUTE_SUPER_ADMIN_DISPENSER_DETAILS}/${item.key}`
|
||||
: `${ROUTE_PROVINCE_DISPENSER_DETAILS}/${item.key}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
<VisibilityIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data, value]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
if (value === 1) {
|
||||
dispatch(slaughterGetDispenserDashboard()).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`dispenser/?role=${getRoleFromUrl()}&search=filter&value=${textValue}&page=${1}&page_size=${perPage}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Tabs value={value} onChange={handleChange}>
|
||||
<Tab label="توزیع کنندگان" value={0} />
|
||||
<Tab label="جزئیات پخش" value={1} />
|
||||
</Tabs>
|
||||
{value === 0 && (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
title: "ثبت توزیع کننده جدید",
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterHouseSubmitDispenser
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت توزیع کننده
|
||||
</Button>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"ماهیت توزیع کننده",
|
||||
"نام و نام خانوادگی",
|
||||
"تلفن",
|
||||
"شهر",
|
||||
"نام کشتارگاه",
|
||||
"سقف محدودیت",
|
||||
"وضعیت",
|
||||
"تعداد کل تخصیصات",
|
||||
"وزن تخصیصات کل",
|
||||
"حجم کل",
|
||||
"تخصیصات امروز",
|
||||
"حجم تخصیصات امروز",
|
||||
"وزن امروز",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="مدیریت توزیع کنندگان"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{value === 1 && (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid container xs={12} justifyContent="start" alignItems="center">
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
data={[
|
||||
[
|
||||
dashboardData?.numberOfDispensers?.toLocaleString(),
|
||||
dashboardData?.numberOfAllocations?.toLocaleString(),
|
||||
dashboardData?.totalWeight?.toLocaleString(),
|
||||
dashboardData?.totalQuantity?.toLocaleString(),
|
||||
dashboardData?.numberOfTodayAllocations?.toLocaleString(),
|
||||
dashboardData?.totalTodayQuantity?.toLocaleString(),
|
||||
dashboardData?.totalTodayWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
columns={[
|
||||
"تعداد توزیع کنندگان",
|
||||
"تعداد کل تخصیصات",
|
||||
"وزن تخصیصات کل",
|
||||
"حجم کل",
|
||||
"تخصیصات امروز",
|
||||
"حجم تخصیصات امروز",
|
||||
"وزن امروز",
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid mt={2}>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
// disabled={!textValue}
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"ماهیت توزیع کننده",
|
||||
"نام و نام خانوادگی",
|
||||
"تلفن",
|
||||
"شهر",
|
||||
"نام کشتارگاه",
|
||||
"سقف محدودیت",
|
||||
"وضعیت",
|
||||
"تعداد کل تخصیصات",
|
||||
"وزن تخصیصات کل",
|
||||
"حجم کل",
|
||||
"تخصیصات امروز",
|
||||
"حجم تخصیصات امروز",
|
||||
"وزن امروز",
|
||||
"جزئیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="جزئیات پخش توزیع کنندگان"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { ImageUpload } from "../../../../components/image-upload/ImageUpload";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { fixBase64 } from "../../../../utils/toBase64";
|
||||
import { PropTypes } from "prop-types";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterNewComplaint } from "../../services/slaughter-new-complaint";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterGetRegisteredComplaints } from "../../services/slaughter-get-registered-complaints";
|
||||
import { slaughterGetComplaints } from "../../services/slaughter-get-complaints";
|
||||
|
||||
export const SlaughterHouseNewComplaint = ({ barKey, role }) => {
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const [topic, setTopic] = React.useState(10);
|
||||
|
||||
const [complaintImages, setComplaintImages] = React.useState([]);
|
||||
const [complaintImagesBase64, setComplaintImagesBase64] = React.useState([]);
|
||||
|
||||
const complaintImageHandler = (imageList, addUpdateIndex) => {
|
||||
setComplaintImages(imageList);
|
||||
setComplaintImagesBase64(imageList.map((img) => fixBase64(img.data_url)));
|
||||
};
|
||||
|
||||
const isFormValid = (topic) => {
|
||||
switch (topic) {
|
||||
case 10:
|
||||
return (
|
||||
formik2.isValid && formik.isValid && complaintImagesBase64.length
|
||||
);
|
||||
default:
|
||||
return formik.isValid && complaintImagesBase64.length;
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
setTopic(event.target.value);
|
||||
};
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
description: "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
description: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را پر کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
const formik2 = useFormik({
|
||||
initialValues: {
|
||||
looses: "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
looses: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
formik2.validateForm();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
direction="column"
|
||||
flex="1"
|
||||
height="100%"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">موضوع</InputLabel>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={topic}
|
||||
label="موضوع"
|
||||
onChange={handleChange}
|
||||
>
|
||||
<MenuItem value={10}>مغایرت درصد تلفات با واقعیت</MenuItem>
|
||||
<MenuItem value={20}>دیگر</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{topic === 10 && (
|
||||
<TextField
|
||||
id="looses"
|
||||
label="درصد تلفات"
|
||||
variant="outlined"
|
||||
sx={{ width: "100%", height: "100%" }}
|
||||
value={formik2.values.looses}
|
||||
error={
|
||||
formik2.touched.looses ? Boolean(formik2.errors.looses) : null
|
||||
}
|
||||
onChange={formik2.handleChange}
|
||||
onBlur={formik2.handleBlur}
|
||||
helperText={
|
||||
formik2.touched.looses && Boolean(formik2.errors.looses)
|
||||
? formik2.errors.looses
|
||||
: null
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="description"
|
||||
label="توضیحات"
|
||||
multiline
|
||||
rows={5}
|
||||
variant="outlined"
|
||||
sx={{ width: "100%", height: "100%" }}
|
||||
value={formik.values.description}
|
||||
error={
|
||||
formik.touched.description
|
||||
? Boolean(formik.errors.description)
|
||||
: null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.description && Boolean(formik.errors.description)
|
||||
? formik.errors.description
|
||||
: null
|
||||
}
|
||||
/>
|
||||
|
||||
<Typography>پیوست تصویر</Typography>
|
||||
<Grid mb={SPACING.SMALL}>
|
||||
<ImageUpload
|
||||
id="image"
|
||||
onChange={complaintImageHandler}
|
||||
images={complaintImages}
|
||||
maxNumber={4}
|
||||
title={"بارگذاری سند"}
|
||||
value={formik.values.image}
|
||||
error={formik.touched.image ? Boolean(formik.errors.image) : null}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.image && Boolean(formik.errors.image)
|
||||
? formik.errors.image
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
disabled={!isFormValid(topic)}
|
||||
onClick={() => {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(
|
||||
slaughterNewComplaint({
|
||||
bar_key: barKey,
|
||||
image: complaintImagesBase64,
|
||||
title: topic === 10 ? " مغایرت درصد تلفات با واقعیت" : "دیگر",
|
||||
description: formik.values.description,
|
||||
percent: formik2.values?.looses ? formik2.values?.looses : null,
|
||||
role: role,
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(LOADING_END());
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(slaughterGetComplaints());
|
||||
dispatch(slaughterGetRegisteredComplaints());
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد!",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
ثبت اطلاعات
|
||||
</Button>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
SlaughterHouseNewComplaint.propTypes = {
|
||||
barKey: PropTypes.any,
|
||||
role: PropTypes.any,
|
||||
};
|
||||
@@ -0,0 +1,311 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import {
|
||||
TextField,
|
||||
Button,
|
||||
RadioGroup,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Box,
|
||||
MenuItem,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
slaughterHouseEditDispenserService,
|
||||
slaughterHouseSubmitDispenserService,
|
||||
} from "../../services/slaughter-house-submit-dispenser-service";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { provinceGetCitiesService } from "../../../province/services/province-get-cities";
|
||||
import { CarPelak } from "../../../../components/car-pelak/CarPelak";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
|
||||
const validationSchema = Yup.object({
|
||||
mobile: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.min(11, "شماره موبایل باید 11 رقم باشد")
|
||||
.max(11, "شماره موبایل باید 11 رقم باشد")
|
||||
.matches(/^09\d{9}$/, "شماره موبایل باید با 09 شروع شود و 11 رقم باشد"),
|
||||
first_name: Yup.string().required("این فیلد اجباریست!"),
|
||||
last_name: Yup.string().required("این فیلد اجباریست!"),
|
||||
city: Yup.string().required("این فیلد اجباریست!"),
|
||||
national_id: Yup.string()
|
||||
.matches(/^\d{10}$/, "کد ملی ده رقمی است!")
|
||||
.required("این فیلد اجباریست!"),
|
||||
dispenser_type: Yup.string().required("این فیلد اجباریست!"),
|
||||
limitation_amount: Yup.number()
|
||||
.min(0, "عدد مثبت وارد کنید!")
|
||||
.required("سقف محدودیت اجباری است"),
|
||||
driver_car_type: Yup.string().when("dispenser_type", {
|
||||
is: "driver",
|
||||
then: Yup.string().required("نوع خودرو اجباری است!"),
|
||||
}),
|
||||
});
|
||||
|
||||
export const SlaughterHouseSubmitDispenser = ({
|
||||
updateTable,
|
||||
isEdit,
|
||||
item,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const { provinceGetCities } = useSelector((state) => state.provinceSlice);
|
||||
const [driverPelak, setDriverPelak] = useState([]);
|
||||
|
||||
const carPelakHandleChange = (pelak1, pelak2, pelak3, pelak4) => {
|
||||
setDriverPelak([pelak1, pelak2, pelak3, pelak4]);
|
||||
};
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(provinceGetCitiesService());
|
||||
}, []);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
mobile: item?.user?.mobile ? item?.user?.mobile : "",
|
||||
first_name: item?.user?.firstName ? item?.user?.firstName : "",
|
||||
last_name: item?.user?.lastName ? item?.user?.lastName : "",
|
||||
city: item?.user?.city?.cityName ? item?.user?.city?.cityName : "",
|
||||
national_id: item?.user?.nationalId ? item?.user?.nationalId : "",
|
||||
dispenser_type: item?.dispenserType ? item?.dispenserType : "inductor",
|
||||
limitation_amount: item?.limitation_amount ? item?.limitation_amount : 0,
|
||||
driver_car_type: item?.car ? item?.car : "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
if (!isEdit) {
|
||||
dispatch(
|
||||
slaughterHouseSubmitDispenserService({
|
||||
mobile: values.mobile,
|
||||
first_name: values.first_name,
|
||||
last_name: values.last_name,
|
||||
city: values.city,
|
||||
national_id: values.national_id,
|
||||
dispenser_type: values.dispenser_type,
|
||||
limitation_amount: values.limitation_amount,
|
||||
role: getRoleFromUrl(),
|
||||
pelak:
|
||||
values.dispenser_type === "driver"
|
||||
? driverPelak[0] +
|
||||
" " +
|
||||
driverPelak[1] +
|
||||
" " +
|
||||
driverPelak[2] +
|
||||
" " +
|
||||
driverPelak[3]
|
||||
: null,
|
||||
car: values.driver_car_type ? values.driver_car_type : null,
|
||||
})
|
||||
).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 {
|
||||
dispatch(
|
||||
slaughterHouseEditDispenserService({
|
||||
type: "update-profile",
|
||||
dispenser_key: item?.key,
|
||||
mobile: values.mobile,
|
||||
first_name: values.first_name,
|
||||
last_name: values.last_name,
|
||||
city: values.city,
|
||||
national_id: values.national_id,
|
||||
dispenser_type: values.dispenser_type,
|
||||
limitation_amount: values.limitation_amount,
|
||||
role: getRoleFromUrl(),
|
||||
pelak:
|
||||
values.dispenser_type === "driver"
|
||||
? driverPelak[0] +
|
||||
" " +
|
||||
driverPelak[1] +
|
||||
" " +
|
||||
driverPelak[2] +
|
||||
" " +
|
||||
driverPelak[3]
|
||||
: null,
|
||||
car: values.driver_car_type ? values.driver_car_type : null,
|
||||
})
|
||||
).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",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
sx={{ display: "flex", flexDirection: "column", gap: 2 }}
|
||||
>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="نام"
|
||||
name="first_name"
|
||||
value={formik.values.first_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.first_name && Boolean(formik.errors.first_name)}
|
||||
helperText={formik.touched.first_name && formik.errors.first_name}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="نام خانوادگی"
|
||||
name="last_name"
|
||||
value={formik.values.last_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.last_name && Boolean(formik.errors.last_name)}
|
||||
helperText={formik.touched.last_name && formik.errors.last_name}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="موبایل"
|
||||
name="mobile"
|
||||
value={formik.values.mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.mobile && Boolean(formik.errors.mobile)}
|
||||
helperText={formik.touched.mobile && formik.errors.mobile}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
select
|
||||
label="شهر"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="city"
|
||||
name="city"
|
||||
value={formik.values.city}
|
||||
onChange={formik.handleChange}
|
||||
error={formik.touched.city && Boolean(formik.errors.city)}
|
||||
helperText={formik.touched.city && formik.errors.city}
|
||||
>
|
||||
{provinceGetCities?.map((city) => (
|
||||
<MenuItem key={city.id} value={city.name}>
|
||||
{city.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="کد ملی"
|
||||
name="national_id"
|
||||
value={formik.values.national_id}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.national_id && Boolean(formik.errors.national_id)}
|
||||
helperText={formik.touched.national_id && formik.errors.national_id}
|
||||
/>
|
||||
<FormControl component="fieldset">
|
||||
<FormLabel component="legend">ماهیت</FormLabel>
|
||||
<RadioGroup
|
||||
name="dispenser_type"
|
||||
value={formik.values.dispenser_type}
|
||||
onChange={formik.handleChange}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="inductor"
|
||||
control={<Radio />}
|
||||
label="واسطه"
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="salesman"
|
||||
control={<Radio />}
|
||||
label="فروشنده"
|
||||
/>
|
||||
<FormControlLabel value="driver" control={<Radio />} label="راننده" />
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
{formik.values.dispenser_type === "driver" && (
|
||||
<>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="نوع خودرو"
|
||||
name="driver_car_type"
|
||||
value={formik.values.driver_car_type}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.driver_car_type &&
|
||||
Boolean(formik.errors.driver_car_type)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.driver_car_type && formik.errors.driver_car_type
|
||||
}
|
||||
/>
|
||||
<Grid item xs={12} alignItems="center" justifyContent={"center"}>
|
||||
<CarPelak
|
||||
width="100%"
|
||||
handleChange={carPelakHandleChange}
|
||||
pelakInitial={isEdit ? item?.pelak : ""}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
<TextField
|
||||
fullWidth
|
||||
label="سقف محدودیت"
|
||||
name="limitation_amount"
|
||||
type="number"
|
||||
value={formik.values.limitation_amount}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.limitation_amount &&
|
||||
Boolean(formik.errors.limitation_amount)
|
||||
}
|
||||
helperText={
|
||||
formik.touched.limitation_amount && formik.errors.limitation_amount
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="contained"
|
||||
type="submit"
|
||||
disabled={
|
||||
formik.values.dispenser_type === "driver" ? !driverPelak[1] : false
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,237 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Button, IconButton, Tooltip } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { SlaughterHouseVetBarsOperation } from "../../../slaughter-house-vet/components/slaughter-house-vet-bars-operation/SlaughterHouseVetBarsOperation";
|
||||
import SystemUpdateAltIcon from "@mui/icons-material/SystemUpdateAlt";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
import { CheckCleanceCode } from "../../../../components/check-clearance-code/ChechClearanceCode";
|
||||
import { SlaughterFreeBarsAlivesOperations } from "../slaughter-free-bars-alives-operations/SlaughterFreeBarsAlivesOperations";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterInventoryFreeBuyBarsAlives = ({
|
||||
title,
|
||||
barState,
|
||||
fetchDashboardData,
|
||||
withDate,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
searchValue,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetProfile({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(10);
|
||||
const [page, setPage] = useState(1);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
let response;
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
response = await axios.get(
|
||||
`kill_house_free_bar/?type=live&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&page=${page}&page_size=${perPage}&bar_state=${barState}&date_type=input${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ""
|
||||
}${searchValue ? `&search=filter&value=${searchValue}` : ""}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
fetchDashboardData();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [
|
||||
perPage,
|
||||
withDate,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
searchValue,
|
||||
selectedSubUser?.key,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.barCode || "-",
|
||||
item?.registerType === "automatic" ? "سیستمی" : "دستی",
|
||||
formatJustDate(item.createDate),
|
||||
`${item?.killHouse?.name} (${item?.killHouse?.killHouseOperator?.user?.mobile})`,
|
||||
item?.exclusiveKiller
|
||||
? `${item?.exclusiveKiller?.name} (${item?.exclusiveKiller?.killHouseOperator?.user?.mobile})`
|
||||
: "-",
|
||||
item.buyType === "live" ? "مرغ زنده" : "لاشه",
|
||||
item.poultryName,
|
||||
`${item.province}/${item.city}`,
|
||||
<CheckCleanceCode key={i} clearanceCode={item.barClearanceCode} />,
|
||||
item.quantity.toLocaleString(),
|
||||
item.liveWeight.toLocaleString(),
|
||||
formatJustDate(item.date),
|
||||
item.numberOfCarcasses.toLocaleString(),
|
||||
item.weightOfCarcasses.toLocaleString(),
|
||||
item?.weightLoss ? item?.weightLoss + "%" : "-",
|
||||
<ShowImage key={i} src={item.barImage} />,
|
||||
<>
|
||||
{getRoleFromUrl() === "KillHouse" ? (
|
||||
<SlaughterFreeBarsAlivesOperations
|
||||
key={item.key}
|
||||
item={item}
|
||||
inventoryKey={item?.key}
|
||||
updateTable={updateTable}
|
||||
barState={barState}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={item?.killHouseVetState !== "pending"}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید / رد",
|
||||
content: (
|
||||
<SlaughterHouseVetBarsOperation
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تایید / رد
|
||||
</Button>
|
||||
)}
|
||||
</>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
|
||||
return (
|
||||
<Grid container justifyContent="flex-end" mt={2} mb={2}>
|
||||
<Grid
|
||||
container
|
||||
mt={SPACING.MEDIUM}
|
||||
alignItems="end"
|
||||
gap={2}
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
<ResponsiveTable
|
||||
operation={
|
||||
<Grid>
|
||||
<Tooltip title="خروجی اکسل" placement="top">
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "فایل اکسل در حال دانلود می باشد، این علمیات ممکن است زمان بر باشد لطفا صبر کنید.",
|
||||
severity: "success",
|
||||
});
|
||||
const link = `${
|
||||
axios.defaults.baseURL
|
||||
}kill_house_free_bar_excel/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&key=${userKey}&type=live&bar_state=${barState}${
|
||||
withDate
|
||||
? `&date1=${selectedDate1}&date2=${selectedDate2}`
|
||||
: ""
|
||||
}`;
|
||||
window.location.href = link;
|
||||
}}
|
||||
>
|
||||
<SystemUpdateAltIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
}
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"کد بار",
|
||||
"نوع بار",
|
||||
"تاریخ خرید",
|
||||
"خریدار",
|
||||
"کشتارکن",
|
||||
"محصول",
|
||||
"فروشنده",
|
||||
"استان/شهر",
|
||||
"کدقرنطینه",
|
||||
"حجم زنده",
|
||||
"وزن زنده (کیلوگرم)",
|
||||
"تاریخ ورود به انبار",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه (کیلوگرم)",
|
||||
"درصد افت",
|
||||
"بارنامه",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title={title}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,525 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import moment from "moment";
|
||||
import axios from "axios";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Button, Checkbox, Tab, Tabs, TextField, Tooltip } from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SlaughterFreeBarsOperations } from "../slaughter-free-bars-operations/SlaughterFreeBarsOperations";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { SlaughterSubmitFreeBar } from "../slaughter-submit-free-bar/SlaughterSubmitFreeBar";
|
||||
import { SlaughterHouseVetBarsOperation } from "../../../slaughter-house-vet/components/slaughter-house-vet-bars-operation/SlaughterHouseVetBarsOperation";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
import { vetFarmGetOutProvinceDashboard } from "../../../vet-farm/services/vet-farm-get-out-province-dashboard";
|
||||
import ToggleOffOutlinedIcon from "@mui/icons-material/ToggleOffOutlined";
|
||||
import ToggleOnIcon from "@mui/icons-material/ToggleOn";
|
||||
import { SlaughterInventoryFreeBuyBarsAlives } from "../slaughter-inventory-free-buy-bars-alives/SlaughterInventoryFreeBuyBarsAlives";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterInventoryFreeBuyBars = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const handleTabChange = (event, newValue) => {
|
||||
setActiveTab(newValue);
|
||||
};
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, []);
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetProfile({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
}, [selectedSubUser?.key, dispatch]);
|
||||
|
||||
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 [withDate, setWithDate] = useState(false);
|
||||
const [searchValue, setSearchValue] = useState("");
|
||||
|
||||
const fetchApiData = async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`kill_house_free_bar/?type=${
|
||||
activeTab === 0 ? "live" : "carcass"
|
||||
}&dashboard=true&search=filter&value=${searchValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ""
|
||||
}&page=${page}&page_size=${perPage}&date_type=input`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
};
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
setPage(1);
|
||||
fetchApiData(1);
|
||||
fetchDashboardData();
|
||||
};
|
||||
|
||||
const fetchDashboardData = () => {
|
||||
dispatch(
|
||||
vetFarmGetOutProvinceDashboard({
|
||||
search: "filter",
|
||||
role: getRoleFromUrl(),
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
value: searchValue,
|
||||
type: activeTab === 0 ? "live" : "carcass",
|
||||
...(withDate && {
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
}),
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
fetchDashboardData();
|
||||
}, [
|
||||
withDate,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
activeTab,
|
||||
searchValue,
|
||||
selectedSubUser?.key,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.barCode || "-",
|
||||
formatJustDate(item.createDate),
|
||||
`${item?.killHouse?.name} (${item?.killHouse?.killHouseOperator?.user?.mobile})`,
|
||||
item?.exclusiveKiller
|
||||
? `${item?.exclusiveKiller?.name} (${item?.exclusiveKiller?.killHouseOperator?.user?.mobile})`
|
||||
: "-",
|
||||
item.buyType === "live" ? "مرغ زنده" : "لاشه",
|
||||
item.poultryName,
|
||||
`${item.province}/${item.city}`,
|
||||
item.barClearanceCode,
|
||||
item.numberOfCarcasses.toLocaleString(),
|
||||
item.weightOfCarcasses.toLocaleString(),
|
||||
<ShowImage key={i} src={item.barImage} />,
|
||||
<>
|
||||
{getRoleFromUrl() === "KillHouse" ? (
|
||||
<SlaughterFreeBarsOperations
|
||||
key={item.key}
|
||||
item={item}
|
||||
inventoryKey={item?.key}
|
||||
updateTable={updateTable}
|
||||
type="carcass"
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="outlined"
|
||||
disabled={item?.killHouseVetState !== "pending"}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید / رد",
|
||||
content: (
|
||||
<SlaughterHouseVetBarsOperation
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
تایید / رد
|
||||
</Button>
|
||||
)}
|
||||
</>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
setSearchValue(textValue);
|
||||
};
|
||||
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
|
||||
return (
|
||||
<Grid container direction="column" flexWrap="nowrap">
|
||||
<Grid container justifyContent="center" alignItems="center">
|
||||
<Tabs
|
||||
scrollButtons="auto"
|
||||
variant="scrollable"
|
||||
allowScrollButtonsMobile
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
>
|
||||
<Tab label="زنده" />
|
||||
<Tab label="لاشه" />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
{activeTab === 0 && (
|
||||
<Grid
|
||||
mt={2}
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
gap={1}
|
||||
style={{
|
||||
borderStyle: "solid",
|
||||
borderWidth: "1px",
|
||||
padding: "5px",
|
||||
borderRadius: "15px",
|
||||
borderColor: "gray",
|
||||
justifyContent: "left",
|
||||
}}
|
||||
alignItems="center"
|
||||
>
|
||||
<Checkbox
|
||||
icon={<ToggleOffOutlinedIcon />}
|
||||
checkedIcon={<ToggleOnIcon />}
|
||||
checked={withDate}
|
||||
onChange={() => {
|
||||
setWithDate(!withDate);
|
||||
fetchApiData(1);
|
||||
}}
|
||||
color="primary"
|
||||
size="large"
|
||||
/>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid
|
||||
container
|
||||
mt={SPACING.MEDIUM}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
gap={SPACING.SMALL}
|
||||
justifyContent="start"
|
||||
xs={12}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ثبت اطلاعات خرید",
|
||||
content: (
|
||||
<SlaughterSubmitFreeBar
|
||||
inventoryKey={"slaughterGetInventoryStockData?.key"}
|
||||
selectedDate={selectedDate1}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت اطلاعات خرید
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<Grid container mb={4} isDashboard xs={12}>
|
||||
{activeTab === 0 ? (
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
columns={[
|
||||
"تعداد کل بارهای زنده",
|
||||
"حجم کل بارهای زنده",
|
||||
"وزن کل بارهای زنده",
|
||||
"تعداد کل بارها وارد شده به انبار",
|
||||
"حجم کل بارهای زنده وارد شده به انبار",
|
||||
"وزن کل بارهای زنده وارد شده به انبار",
|
||||
"وزن لاشه بارهای وارد شده به انبار",
|
||||
"تعداد کل بارها وارد نشده به انبار",
|
||||
"حجم کل بارهای زنده وارد نشده به انبار",
|
||||
"وزن کل بارهای زنده وارد نشده به انبار",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.totalBars?.toLocaleString(),
|
||||
dashboardData?.totalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.totalBarsLiveWeight?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBars?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsLiveWeight?.toLocaleString(),
|
||||
dashboardData?.enteredTotalBarsWeightOfCarcasses?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBars?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBarsQuantity?.toLocaleString(),
|
||||
dashboardData?.notEnteredTotalBarsLiveWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
customColors={[
|
||||
{
|
||||
name: "وزن لاشه بارهای وارد شده به انبار",
|
||||
color: "green",
|
||||
},
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
) : (
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={["تعداد کل بارها", "حجم لاشه", "وزن لاشه"]}
|
||||
data={[
|
||||
[
|
||||
dashboardData?.totalBars?.toLocaleString(),
|
||||
dashboardData?.totalBarsNumberOfCarcasses?.toLocaleString(),
|
||||
dashboardData?.totalBarsWeightOfCarcasses?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
|
||||
{activeTab === 0 ? (
|
||||
<>
|
||||
<SlaughterInventoryFreeBuyBarsAlives
|
||||
title={"بار زنده در انتظار ورود به انبار (خارج استان)"}
|
||||
barState={"notentered"}
|
||||
fetchDashboardData={fetchDashboardData}
|
||||
searchValue={searchValue}
|
||||
withDate={withDate}
|
||||
selectedDate1={selectedDate1}
|
||||
selectedDate2={selectedDate2}
|
||||
/>
|
||||
|
||||
<SlaughterInventoryFreeBuyBarsAlives
|
||||
title={"بار زنده وارد شده به انبار (خارج استان)"}
|
||||
barState={"entered"}
|
||||
fetchDashboardData={fetchDashboardData}
|
||||
searchValue={searchValue}
|
||||
withDate={withDate}
|
||||
selectedDate1={selectedDate1}
|
||||
selectedDate2={selectedDate2}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<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>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
disabled={!withDate}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField style={{ width: "160px" }} {...params} />
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
disabled={!withDate}
|
||||
/>
|
||||
</Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<Button
|
||||
color="success"
|
||||
onClick={() => {
|
||||
const link = `${
|
||||
axios.defaults.baseURL
|
||||
}kill_house_free_bar_excel/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&key=${userKey}${
|
||||
withDate
|
||||
? `&date1=${selectedDate1}&date2=${selectedDate2}`
|
||||
: ""
|
||||
}&type=${
|
||||
activeTab === 0 ? "live" : "carcass"
|
||||
}&search=filter&value=${searchValue}&date_type=input`;
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,337 @@
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
InputLabel,
|
||||
IconButton,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import axios from "axios";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SlaughterSubmitRealInventory } from "../slaughter-submit-real-inventory/SlaughterSubmitRealInventory";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterInventoryInProvinceBars = ({ type }) => {
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [selectedDate2, setSelectedDate2] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
const [withDate, setWithDate] = useState(type === "entered" ? true : false);
|
||||
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 [quota, setQuota] = useState("all");
|
||||
|
||||
const fetchApiData = useCallback(
|
||||
async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`bars_for_kill_house/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
withDate
|
||||
? `&date1=${selectedDate1}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&date2=${selectedDate2}`
|
||||
: ``
|
||||
}&page=${page}&page_size=${perPage}&type=${type}"a=${quota}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
withDate,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
type,
|
||||
quota,
|
||||
dispatch,
|
||||
setData,
|
||||
selectedSubUser?.key,
|
||||
setTotalRows,
|
||||
]
|
||||
);
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTable = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.barCode,
|
||||
formatJustDate(item?.poultryRequest?.date),
|
||||
`${item?.poultryRequest?.poultryName} (${item?.poultryRequest?.poultryMobile}) - ${item?.poultryRequest?.poultryUserName}`,
|
||||
item?.poultryRequest?.poultryCity,
|
||||
`${item?.killhouseUser?.killer ? "کشتارکن" : "کشتارگاه"} ${
|
||||
item?.killhouseUser?.name
|
||||
} (${item?.killhouseUser?.killHouseOperator?.user?.mobile})`,
|
||||
item?.poultryRequest?.poultryReqOrderCode,
|
||||
item?.freezing ? "انجماد" : item?.export ? "صادرات" : "عادی",
|
||||
item?.killer
|
||||
? `${item?.killer?.name} (${item?.killer?.killHouseOperator?.user?.mobile})`
|
||||
: "-",
|
||||
item?.poultryRequest?.freeSaleInProvince ? "آزاد" : "دولتی",
|
||||
item?.poultryRequest?.chickenBreed,
|
||||
`${item?.addCar?.driver?.driverName}/${item?.addCar?.driver?.typeCar}`,
|
||||
item?.addCar?.driver?.healthCode
|
||||
? item?.addCar?.driver?.healthCode
|
||||
: "-",
|
||||
item?.clearanceCode ? item?.clearanceCode : "-",
|
||||
item?.acceptedRealQuantity?.toLocaleString(),
|
||||
item?.acceptedRealWeight?.toLocaleString(),
|
||||
item?.weightInfo?.state,
|
||||
item?.wareHouseAcceptedRealQuantity.toLocaleString(),
|
||||
item?.wareHouseAcceptedRealWeight.toLocaleString(),
|
||||
item?.weightInfo?.weightLoss
|
||||
? item?.weightInfo?.weightLoss?.toFixed(2) + "%"
|
||||
: 0 + "%",
|
||||
item?.weightInfo?.inputLoss
|
||||
? item?.weightInfo?.inputLoss?.toFixed(2) + "%"
|
||||
: 0 + "%",
|
||||
item?.dateOfWareHouse ? formatJustDate(item?.dateOfWareHouse) : "-",
|
||||
<Tooltip title="ورود بار به انبار" key={i}>
|
||||
<IconButton
|
||||
size={"small"}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت موجودی واقعی",
|
||||
content: (
|
||||
<SlaughterSubmitRealInventory
|
||||
updateTable={updateTable}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<SettingsIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [fetchApiData]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`bars_for_kill_house/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&page=${1}&page_size=${perPage}&type=${type}"a=${quota}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
style={{
|
||||
borderStyle: "solid",
|
||||
borderWidth: "1px",
|
||||
padding: "10px",
|
||||
borderRadius: "15px",
|
||||
borderColor: "gray",
|
||||
justifyContent: "left",
|
||||
}}
|
||||
>
|
||||
{type === "notentered" && (
|
||||
<Grid>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={withDate}
|
||||
onChange={() => setWithDate(!withDate)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<FormControl size="small" style={{ minWidth: 150 }}>
|
||||
<InputLabel>نوع فروش</InputLabel>
|
||||
<Select
|
||||
value={quota}
|
||||
onChange={(e) => setQuota(e.target.value)}
|
||||
label="نوع فروش"
|
||||
>
|
||||
<MenuItem value="all">همه</MenuItem>
|
||||
<MenuItem value="governmental">دولتی</MenuItem>
|
||||
<MenuItem value="free">آزاد</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"کدبار",
|
||||
"تاریخ کشتار",
|
||||
"مرغدار",
|
||||
"شهر مرغدار",
|
||||
"خریدار",
|
||||
"کدسفارش",
|
||||
"کشتار",
|
||||
"کشتارکن",
|
||||
"فروش",
|
||||
"نژاد",
|
||||
"راننده/نوع خودرو",
|
||||
"کدبهداشتی حمل و نقل",
|
||||
"کدرهگیری سامانه قرنطینه",
|
||||
"حجم بار (قطعه)",
|
||||
"وزن بار (کیلوگرم)",
|
||||
"وضعیت",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"درصد افت در لحظه",
|
||||
"درصد افت ورود به انبار",
|
||||
"تاریخ ورود به انبار",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title={
|
||||
type === "entered"
|
||||
? "وارد شده به انبار (کشتار داخل استان)"
|
||||
: "در انتظار ورود به انبار (کشتار داخل استان)"
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
import { VscFolderActive, 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_SLAUGHTER_INVENTORY_SELL_CARCASS_IN_PROVINCE,
|
||||
ROUTE_SLAUGHTER_INVENTORY_SELL_CARCASS_OUT_PROVINCE,
|
||||
ROUTE_SLAUGHTER_INVENTORY_STOCK,
|
||||
ROUTE_SLAUGHTER_OUT_PROVINCE_BUY,
|
||||
ROUTE_SLAUGHTER_SEGMENTATION,
|
||||
} from "../../../../routes/routes";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useEffect } from "react";
|
||||
// import moment from "moment";
|
||||
|
||||
export const SlaughterInventoryOperation = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { pathname } = useLocation();
|
||||
const { profile } = useSelector((state) => state.slaughterSlice);
|
||||
|
||||
useEffect(() => {
|
||||
if (!profile) {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(slaughterGetProfile()).then((r) => {
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
p={SPACING.SMALL}
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
justifyContent="center"
|
||||
style={{ placeContent: "baseline" }}
|
||||
>
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_INVENTORY_STOCK}
|
||||
active={pathname === ROUTE_SLAUGHTER_INVENTORY_STOCK ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="ورود به انبار"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_INVENTORY_SELL_CARCASS_IN_PROVINCE}
|
||||
active={
|
||||
pathname === ROUTE_SLAUGHTER_INVENTORY_SELL_CARCASS_IN_PROVINCE
|
||||
? "true"
|
||||
: null
|
||||
}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="فروش داخل استان"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_INVENTORY_SELL_CARCASS_OUT_PROVINCE}
|
||||
active={
|
||||
pathname === ROUTE_SLAUGHTER_INVENTORY_SELL_CARCASS_OUT_PROVINCE
|
||||
? "true"
|
||||
: null
|
||||
}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="فروش به خارج استان"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_OUT_PROVINCE_BUY}
|
||||
active={pathname === ROUTE_SLAUGHTER_OUT_PROVINCE_BUY ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscFolderActive size={30} color="#244CCC" />}
|
||||
title="خرید خارج از استان"
|
||||
description="درخواست های در انتظار عملیات وارد کردن اطلاعات بارهای دریافتی"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_SEGMENTATION}
|
||||
active={pathname === ROUTE_SLAUGHTER_SEGMENTATION ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="قطعه بندی"
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
{/* <NavLink
|
||||
to={`${ROUTE_SLAUGHTER_AGENT_SHARE}/${
|
||||
profile?.killHouse[0]?.key
|
||||
}/${moment(new Date()).format("YYYY-MM-DD")}`}
|
||||
active={
|
||||
pathname ===
|
||||
`${ROUTE_SLAUGHTER_AGENT_SHARE}/${
|
||||
profile?.killHouse[0]?.key
|
||||
}/${moment(new Date()).format("YYYY-MM-DD")}`
|
||||
? "true"
|
||||
: null
|
||||
}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="سهم بندی اتوماتیک مباشرین"
|
||||
/>
|
||||
</NavLink> */}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SlaughterShowProducts } from "../slaughter-show-products/SlaughterShowProducts";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Button } from "@mui/material";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterSubmitOperations } from "../slaughter-submit-operations/SlaughterSubmitOperations";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterInventorySummary = ({ priceInfo }) => {
|
||||
const { distributionInfo, slaughterProducts } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const updateTable = () => {
|
||||
dispatch(
|
||||
fetchSlaughterBroadcastAndProducts({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
updateTable();
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
return (
|
||||
<Grid container width="100%" gap={SPACING.SMALL} mb={2}>
|
||||
<Button
|
||||
disabled={!slaughterProducts}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
size="large"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ثبت عملیات",
|
||||
size: window.innerWidth <= 600 ? "auto" : 450,
|
||||
content: (
|
||||
<SlaughterSubmitOperations
|
||||
updateTable={updateTable}
|
||||
priceInfo={priceInfo}
|
||||
slaughterProducts={slaughterProducts}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت عملیات
|
||||
</Button>
|
||||
<SlaughterShowProducts />
|
||||
<ResponsiveTable
|
||||
title="اطلاعات پخش"
|
||||
noPagination
|
||||
isDashboard
|
||||
data={[
|
||||
[
|
||||
distributionInfo?.totalGovernmentalInputWeight?.toLocaleString(),
|
||||
distributionInfo?.totalFreeInputWeight?.toLocaleString(),
|
||||
distributionInfo?.totalGovernmentalOutputWeight?.toLocaleString(),
|
||||
distributionInfo?.totalFreeOutputWeight?.toLocaleString(),
|
||||
distributionInfo?.totalKillHouseAllocationsWeight?.toLocaleString(),
|
||||
distributionInfo?.totalKillHouseFreeSale_barCarcassesWeight?.toLocaleString(),
|
||||
distributionInfo?.segmentationsWeight?.toLocaleString(),
|
||||
distributionInfo?.coldHouseAllocationsWeight?.toLocaleString(),
|
||||
distributionInfo?.totalGovernmentalRemainWeight?.toLocaleString(),
|
||||
distributionInfo?.totalFreeRemainWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
columns={[
|
||||
"وزن دولتی (کیلوگرم)",
|
||||
"وزن آزاد (کیلوگرم)",
|
||||
"فروش دولتی (کیلوگرم)",
|
||||
"فروش آزاد (کیلوگرم)",
|
||||
"فروش و توزیع داخل استان (کیلوگرم)",
|
||||
"فروش و توزیع خارج استان (کیلوگرم)",
|
||||
"وزن قطعه بندی (کیلوگرم)",
|
||||
"وزن انجماد (کیلوگرم)",
|
||||
"مانده دولتی (کیلوگرم)",
|
||||
" مانده آزاد (کیلوگرم)",
|
||||
]}
|
||||
/>
|
||||
<ResponsiveTable
|
||||
title="تعهدات"
|
||||
noPagination
|
||||
isDashboard
|
||||
data={[
|
||||
[
|
||||
distributionInfo?.totalCommitmentSellingInProvinceGovernmentalWeight?.toLocaleString(),
|
||||
distributionInfo?.totalSellingInProvinceGovernmentalWeight?.toLocaleString(),
|
||||
distributionInfo?.totalCommitmentSellingInProvinceGovernmentalRemainWeight?.toLocaleString(),
|
||||
distributionInfo?.totalCommitmentSellingInProvinceFreeWeight?.toLocaleString(),
|
||||
distributionInfo?.totalSellingInProvinceFreeWeight?.toLocaleString(),
|
||||
distributionInfo?.totalCommitmentSellingInProvinceFreeRemainWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
columns={[
|
||||
"تعهد دولتی توزیع داخل استان",
|
||||
"توزیع دولتی داخل استان",
|
||||
"باقیمانده تعهد دولتی توزیع داخل استان",
|
||||
"تعهد آزاد توزیع داخل استان",
|
||||
"توزیع آزاد داخل استان",
|
||||
"باقیمانده تعهد آزاد توزیع داخل استان",
|
||||
]}
|
||||
allColors={{ color: "green", text: "#332a3d" }}
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
|
||||
import { Tab, Tabs } from "@mui/material";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { SlaughterShowProducts } from "../slaughter-show-products/SlaughterShowProducts";
|
||||
import { SlaughterInventoryInProvinceBars } from "../slaughter-inventory-in-province-bars/SlaughterInventoryInProvinceBars";
|
||||
import { SlaughterInventoryFreeBuyBars } from "../slaughter-inventory-free-buy-bars/SlaughterInventoryFreeBuyBars";
|
||||
import { slaughterGetBarsInfo } from "../../services/slaughter-get-distribution-info";
|
||||
import { useDispatch } from "react-redux";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
export const SlaughterInventory = () => {
|
||||
const [value, setValue] = useState("0");
|
||||
const [barsInfo, setBarsInfo] = useState([]);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetBarsInfo({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setBarsInfo(r.payload.data);
|
||||
});
|
||||
}, [dispatch, selectedSubUser?.key]);
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="end" alignItems="center">
|
||||
<Grid container width="100%" isDashboard>
|
||||
<SlaughterShowProducts />
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
mt={2}
|
||||
>
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
textColor="secondary"
|
||||
indicatorColor="secondary"
|
||||
aria-label="secondary tabs example"
|
||||
>
|
||||
<Tab value="0" label="بارهای داخل استان" />
|
||||
<Tab value="1" label="خریدهای خارج استان" />
|
||||
</Tabs>
|
||||
</Grid>
|
||||
|
||||
{value === "0" && (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center">
|
||||
<Grid container justifyContent="start" alignItems="center" xs={12}>
|
||||
<ResponsiveTable
|
||||
title="اطلاعات کلی بارها"
|
||||
noPagination
|
||||
data={[
|
||||
[
|
||||
barsInfo?.totalBars?.toLocaleString(),
|
||||
barsInfo?.totalBarsQuantity?.toLocaleString(),
|
||||
barsInfo?.totalBarsWeight?.toLocaleString(),
|
||||
barsInfo?.totalEnteredBars?.toLocaleString(),
|
||||
barsInfo?.totalEnteredBarsWeight?.toLocaleString(),
|
||||
barsInfo?.totalEnteredBarsCarcasses?.toLocaleString(),
|
||||
barsInfo?.totalEnteredBarsCarcassesWeight?.toLocaleString(),
|
||||
barsInfo?.totalNotEnteredBars?.toLocaleString(),
|
||||
barsInfo?.totalNotEnteredBarsQuantity?.toLocaleString(),
|
||||
barsInfo?.totalNotEnteredKillHouseRequestsWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
columns={[
|
||||
"تعداد کل بارها",
|
||||
"حجم کل بارها (قطعه)",
|
||||
"وزن کل بارها (کیلوگرم)",
|
||||
"تعداد کل بارهای وارد شده",
|
||||
"وزن کل بارهای وارد شده",
|
||||
"حجم کل لاشه وارد شده (قطعه)",
|
||||
"وزن کل لاشه وارد شده (کیلوگرم)",
|
||||
"تعداد کل بارهای وارد نشده",
|
||||
"حجم کل بار وارد نشده (قطعه)",
|
||||
"وزن کل بار وارد نشده (کیلوگرم)",
|
||||
]}
|
||||
allColors={{ color: "#f3bda3", text: "#332a3d" }}
|
||||
/>
|
||||
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}>
|
||||
<SlaughterInventoryInProvinceBars type="notentered" />
|
||||
</Grid>
|
||||
|
||||
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}>
|
||||
<SlaughterInventoryInProvinceBars type="entered" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
{value === "1" && (
|
||||
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}>
|
||||
<SlaughterInventoryFreeBuyBars />
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,656 @@
|
||||
import { useContext, useEffect, useState, useMemo, useCallback } from "react";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import {
|
||||
Box,
|
||||
TextField,
|
||||
Typography,
|
||||
Button,
|
||||
Tooltip,
|
||||
FormControlLabel,
|
||||
Checkbox,
|
||||
} from "@mui/material";
|
||||
import moment from "moment";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { format } from "date-fns-jalali";
|
||||
import axios from "axios";
|
||||
import { formatTime } from "../../../../utils/formatTime";
|
||||
import ShowImage from "../../../../components/show-image/ShowImage";
|
||||
import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
|
||||
import { VetFarmOperationOptions } from "../../../vet-farm/components/vet-farm-operations-options/VetFarmOperationOptions";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { VetFarmEditTrafficCode } from "../../../vet-farm/components/vet-farm-edit-traffic-code/VetFarmEditTrafficCode";
|
||||
import { vetFarmGetFinishedBarsOverview } from "../../../vet-farm/services/vet-farm-get-bars-overview";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
// Constants
|
||||
const ROLES = {
|
||||
KILL_HOUSE: "KillHouse",
|
||||
ADMIN_X: "AdminX",
|
||||
VET_FARM: "VetFarm",
|
||||
PROVINCE_OPERATOR: "ProvinceOperator",
|
||||
KILL_HOUSE_VET: "KillHouseVet",
|
||||
SUPER_ADMIN: "SuperAdmin",
|
||||
SUPPORTER: "Supporter",
|
||||
};
|
||||
|
||||
const KILL_TYPES = {
|
||||
FREEZING: "انجماد",
|
||||
EXPORT: "صادرات",
|
||||
NORMAL: "عادی",
|
||||
};
|
||||
|
||||
const ITEM_STATES = {
|
||||
WAREHOUSE: "ورود به انبار",
|
||||
REGISTERED: "ثبت اطلاعات بار",
|
||||
DELETED: "حذف شده",
|
||||
ACCEPTED: "تایید تخلیه",
|
||||
PENDING: "در انتظار تخلیه",
|
||||
};
|
||||
|
||||
const QUARANTINE_STATES = {
|
||||
CONTRADICTION: "مغایرت کد رهگیری",
|
||||
NO_CLEARANCE: "فاقد کد رهگیری",
|
||||
MERGE: "ادغام",
|
||||
NOT_APPROVED: "عدم تایید راهداری",
|
||||
};
|
||||
|
||||
const DEFAULT_PER_PAGE = 10;
|
||||
const DEFAULT_PAGE = 1;
|
||||
|
||||
// Helper functions
|
||||
const formatDate = (date) => {
|
||||
if (!date) return "-";
|
||||
return format(new Date(date), "yyyy/MM/dd");
|
||||
};
|
||||
|
||||
const formatCurrency = (value) => {
|
||||
return value ? `${value.toLocaleString()} ﷼` : "-";
|
||||
};
|
||||
|
||||
const formatNumber = (value) => {
|
||||
return value ? value.toLocaleString() : "-";
|
||||
};
|
||||
|
||||
const formatNumberFixed = (value, decimals = 2) => {
|
||||
return value ? value.toFixed(decimals).toLocaleString() : "-";
|
||||
};
|
||||
|
||||
const formatUserInfo = (name, mobile) => {
|
||||
return name && mobile ? `${name} (${mobile})` : "-";
|
||||
};
|
||||
|
||||
const getKillType = (item) => {
|
||||
if (item?.poultryRequest?.freezing) return KILL_TYPES.FREEZING;
|
||||
if (item?.poultryRequest?.export) return KILL_TYPES.EXPORT;
|
||||
return KILL_TYPES.NORMAL;
|
||||
};
|
||||
|
||||
const getItemState = (item) => {
|
||||
if (item?.wareHouseConfirmation) {
|
||||
return ITEM_STATES.WAREHOUSE;
|
||||
}
|
||||
if (item?.assignmentStateArchive !== "pending") {
|
||||
return ITEM_STATES.REGISTERED;
|
||||
}
|
||||
if (item.trash === true) {
|
||||
return ITEM_STATES.DELETED;
|
||||
}
|
||||
if (item.vetState === "accepted") {
|
||||
return ITEM_STATES.ACCEPTED;
|
||||
}
|
||||
if (item.vetState === "pending") {
|
||||
return ITEM_STATES.PENDING;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
const getQuarantineInfo = (item) => {
|
||||
if (item?.quarantineQuantity) {
|
||||
return item.quarantineQuantity;
|
||||
}
|
||||
if (item?.quarantineCodeState) {
|
||||
const stateMap = {
|
||||
contradiction: QUARANTINE_STATES.CONTRADICTION,
|
||||
noclearance: QUARANTINE_STATES.NO_CLEARANCE,
|
||||
merge: QUARANTINE_STATES.MERGE,
|
||||
};
|
||||
return stateMap[item.quarantineCodeState] || QUARANTINE_STATES.NOT_APPROVED;
|
||||
}
|
||||
return "-";
|
||||
};
|
||||
|
||||
const buildApiUrl = (params) => {
|
||||
const {
|
||||
textValue,
|
||||
role,
|
||||
date1,
|
||||
date2,
|
||||
page,
|
||||
perPage,
|
||||
roleKey,
|
||||
withoutBarDocument,
|
||||
} = params;
|
||||
const baseUrl = "kill_house_assignment_information/";
|
||||
const queryParams = new URLSearchParams({
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
role: role || "",
|
||||
date1: date1 || "",
|
||||
date2: date2 || "",
|
||||
page: page || DEFAULT_PAGE,
|
||||
page_size: perPage || DEFAULT_PER_PAGE,
|
||||
without_bar_document: withoutBarDocument ? "true" : "false",
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseUrl}?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const buildExcelUrl = (params) => {
|
||||
const { baseURL, date1, date2, role, roleKey, userKey, textValue } = params;
|
||||
const queryParams = new URLSearchParams({
|
||||
start: date1 || "",
|
||||
end: date2 || "",
|
||||
state: "completed",
|
||||
role: role || "",
|
||||
key: userKey || "",
|
||||
search: "filter",
|
||||
value: textValue || "",
|
||||
});
|
||||
|
||||
if (roleKey) {
|
||||
queryParams.append("role_key", roleKey);
|
||||
}
|
||||
|
||||
return `${baseURL}bar_excel/?${queryParams.toString()}`;
|
||||
};
|
||||
|
||||
const isTrafficCodeEditable = (role, item) => {
|
||||
if (!item?.killer?.key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const editableRoles = [
|
||||
ROLES.KILL_HOUSE,
|
||||
ROLES.ADMIN_X,
|
||||
ROLES.VET_FARM,
|
||||
ROLES.PROVINCE_OPERATOR,
|
||||
ROLES.KILL_HOUSE_VET,
|
||||
ROLES.SUPER_ADMIN,
|
||||
ROLES.SUPPORTER,
|
||||
];
|
||||
|
||||
return editableRoles.includes(role);
|
||||
};
|
||||
|
||||
const canShowDocumentCheckbox = (role) => {
|
||||
return (
|
||||
role === ROLES.SUPER_ADMIN ||
|
||||
role === ROLES.SUPPORTER ||
|
||||
role === ROLES.ADMIN_X
|
||||
);
|
||||
};
|
||||
|
||||
export const SlaughterManageBars = () => {
|
||||
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
|
||||
useContext(AppContext);
|
||||
|
||||
// Redux
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const userKey = useSelector((state) => state.userSlice.userProfile.key);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// State
|
||||
const [hasDocumentState, setHasDocumentState] = useState(false);
|
||||
const [data, setData] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
const [perPage, setPerPage] = useState(DEFAULT_PER_PAGE);
|
||||
const [textValue, setTextValue] = useState("");
|
||||
const [page, setPage] = useState(DEFAULT_PAGE);
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [dashboardData, setDashboardData] = useState([]);
|
||||
|
||||
// Memoized values
|
||||
const currentRole = useMemo(() => getRoleFromUrl(), []);
|
||||
const roleKey = useMemo(
|
||||
() => (checkPathStartsWith("slaughter") ? selectedSubUser?.key || "" : ""),
|
||||
[selectedSubUser?.key]
|
||||
);
|
||||
const showDocumentCheckbox = useMemo(
|
||||
() => canShowDocumentCheckbox(currentRole),
|
||||
[currentRole]
|
||||
);
|
||||
|
||||
// Initialize dates
|
||||
useEffect(() => {
|
||||
const currentDate = moment(new Date()).format("YYYY-MM-DD");
|
||||
setSelectedDate1(currentDate);
|
||||
setSelectedDate2(currentDate);
|
||||
}, [setSelectedDate1, setSelectedDate2]);
|
||||
|
||||
// Fetch API data
|
||||
const fetchApiData = useCallback(
|
||||
async (pageNumber = page) => {
|
||||
dispatch(LOADING_START());
|
||||
try {
|
||||
const url = buildApiUrl({
|
||||
textValue,
|
||||
role: currentRole,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
page: pageNumber || DEFAULT_PAGE,
|
||||
perPage,
|
||||
roleKey,
|
||||
withoutBarDocument: hasDocumentState,
|
||||
});
|
||||
|
||||
const response = await axios.get(url);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
dispatch(LOADING_END());
|
||||
}
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
currentRole,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
roleKey,
|
||||
hasDocumentState,
|
||||
page,
|
||||
dispatch,
|
||||
]
|
||||
);
|
||||
|
||||
// Fetch dashboard data
|
||||
const fetchDashboardData = useCallback(() => {
|
||||
dispatch(
|
||||
vetFarmGetFinishedBarsOverview({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
textValue,
|
||||
hasDocumentState,
|
||||
roleKey,
|
||||
})
|
||||
).then((r) => {
|
||||
setDashboardData(r.payload.data);
|
||||
});
|
||||
}, [
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
textValue,
|
||||
hasDocumentState,
|
||||
roleKey,
|
||||
dispatch,
|
||||
]);
|
||||
|
||||
// Handlers
|
||||
const handlePageChange = (newPage) => {
|
||||
fetchApiData(newPage);
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (newPerRows) => {
|
||||
setPerPage(newPerRows);
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
await fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
};
|
||||
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleDateChange1 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate1(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDateChange2 = (date) => {
|
||||
if (date) {
|
||||
setSelectedDate2(moment(date).format("YYYY-MM-DD"));
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeDocumentState = () => {
|
||||
setHasDocumentState(!hasDocumentState);
|
||||
};
|
||||
|
||||
// Initial data fetch
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Refetch when filters change
|
||||
useEffect(() => {
|
||||
fetchApiData(DEFAULT_PAGE);
|
||||
fetchDashboardData();
|
||||
setPage(DEFAULT_PAGE);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedDate1, selectedDate2, hasDocumentState, perPage, roleKey]);
|
||||
|
||||
// Transform data to table format
|
||||
useEffect(() => {
|
||||
const transformedData = data?.map((item, i) => {
|
||||
const rowNumber =
|
||||
page === DEFAULT_PAGE ? i + 1 : i + perPage * (page - 1) + 1;
|
||||
const textColor = item?.trash ? "red" : "black";
|
||||
|
||||
return [
|
||||
rowNumber,
|
||||
<VetFarmOperationOptions
|
||||
key={`operation-${i}`}
|
||||
item={item}
|
||||
updateTable={fetchApiData}
|
||||
isComplete
|
||||
/>,
|
||||
<Typography
|
||||
key={`state-${i}`}
|
||||
style={{ fontSize: "13px", color: textColor }}
|
||||
>
|
||||
{getItemState(item)}
|
||||
</Typography>,
|
||||
<Typography
|
||||
key={`barcode-${i}`}
|
||||
style={{ fontSize: "13px", color: textColor }}
|
||||
>
|
||||
{item.barCode}
|
||||
</Typography>,
|
||||
formatTime(item.createDate),
|
||||
getKillType(item),
|
||||
<Typography
|
||||
key={`doc-status-${i}`}
|
||||
variant="body2"
|
||||
color={item?.barDocumentStatus?.isError ? "error" : "primary"}
|
||||
>
|
||||
{item?.barDocumentStatus?.title || "-"}
|
||||
</Typography>,
|
||||
<ShowImage
|
||||
key={`image-${i}`}
|
||||
src={item?.assignmentInfo?.imageWithBar}
|
||||
/>,
|
||||
formatNumber(item.acceptedRealQuantity),
|
||||
formatNumber(item?.acceptedRealWeight),
|
||||
formatNumber(item?.weightInfo?.finalIndexWeight),
|
||||
formatUserInfo(
|
||||
item.killhouseUser?.name,
|
||||
item.killhouseUser?.killHouseOperator?.user?.mobile
|
||||
),
|
||||
item?.killer
|
||||
? formatUserInfo(
|
||||
item.killer?.name,
|
||||
item.killer?.killHouseOperator?.user?.mobile
|
||||
)
|
||||
: "-",
|
||||
formatUserInfo(
|
||||
item.poultryRequest?.poultry?.user?.fullname,
|
||||
item.poultryRequest?.poultry?.user?.mobile
|
||||
),
|
||||
item.poultryRequest?.poultry?.unitName || "-",
|
||||
item?.poultryRequest?.age || "-",
|
||||
formatNumber(item.quantity),
|
||||
formatNumber(item?.weightInfo?.weight),
|
||||
<Grid key={`traffic-${i}`}>
|
||||
<VetFarmEditTrafficCode
|
||||
updateTable={fetchApiData}
|
||||
killHouseRequestKey={item.key}
|
||||
trafficCode={item?.trafficCode}
|
||||
isEditable={isTrafficCodeEditable(currentRole, item)}
|
||||
/>
|
||||
</Grid>,
|
||||
formatCurrency(item?.amount),
|
||||
item?.clearanceCode || "-",
|
||||
getQuarantineInfo(item),
|
||||
`${item.addCar?.driver?.typeCar || ""} ${
|
||||
item.addCar?.driver?.pelak || ""
|
||||
}`.trim() || "-",
|
||||
formatUserInfo(
|
||||
item.addCar?.driver?.driverName,
|
||||
item.addCar?.driver?.driverMobile
|
||||
),
|
||||
item.poultryRequest?.chickenBreed || "-",
|
||||
formatNumber(item?.weightInfo?.indexWeight),
|
||||
formatCurrency(item?.poultryRequest?.amount),
|
||||
formatCurrency(item?.weightInfo?.killHousePrice),
|
||||
item?.vetFarm?.vet?.user?.fullname
|
||||
? `${item.vetFarm.vet.user.fullname}(${item.vetFarm.vet.user.mobile})`
|
||||
: "فاقد دامپزشک",
|
||||
item.killPlace || "-",
|
||||
item.poultryRequest?.poultry?.address?.city?.name || "-",
|
||||
formatDate(item?.poultryRequest?.sendDate),
|
||||
item?.poultryRequest?.orderCode || "-",
|
||||
formatNumber(item?.wareHouseAcceptedRealQuantity),
|
||||
formatNumber(item?.wareHouseAcceptedRealWeight),
|
||||
formatNumber(item?.weightLoss),
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(transformedData || []);
|
||||
}, [data, page, perPage, currentRole, fetchApiData]);
|
||||
|
||||
// Table columns
|
||||
const dashboardColumns = [
|
||||
"تعداد بارها",
|
||||
"حجم بارها",
|
||||
"وزن بارها",
|
||||
"میانگین وزن",
|
||||
"کمترین سن ",
|
||||
"بیشترین سن ",
|
||||
"میانگین سنی",
|
||||
"بارهای دارای کد قرنطینه",
|
||||
"حجم بارهای دارای کد قرنطینه",
|
||||
"بارهای احراز شده از قرنطینه",
|
||||
"حجم بارهای احراز شده از قرنطینه",
|
||||
"بارهای فاقد کد قرنطینه",
|
||||
"حجم بارهای فاقد کد قرنطینه",
|
||||
"بارهایی که در قرنطینه و رصدیار اختلاف دارند",
|
||||
"بارهای تکمیل شده کشتارگاه",
|
||||
"حجم نهایی در کشتارگاه",
|
||||
"وزن نهایی در کشتارگاه",
|
||||
"تعداد بار ورودی به انبار",
|
||||
"حجم لاشه های انبار",
|
||||
"وزن لاشه های انبار",
|
||||
"درصد افت بار انبار",
|
||||
];
|
||||
|
||||
const tableColumns = [
|
||||
"ردیف",
|
||||
"عملیات",
|
||||
"وضعیت",
|
||||
"کدبار",
|
||||
"تاریخ ثبت خودرو",
|
||||
"نوع کشتار",
|
||||
"وضعیت سند",
|
||||
"سند (بارنامه)",
|
||||
"تعداد نهایی",
|
||||
"وزن نهایی بار (کیلوگرم)",
|
||||
"میانگین وزن نهایی (کیلوگرم)",
|
||||
"خریدار",
|
||||
"کشتارکن اختصاصی",
|
||||
"مشخصات مرغدار",
|
||||
"نام فارم",
|
||||
"سن مرغ",
|
||||
"تعداد اولیه",
|
||||
"وزن اولیه بار (کیلوگرم)",
|
||||
"کد بهداشتی حمل و نقل",
|
||||
"قیمت مرغ زندهی بار",
|
||||
"کدرهگیری سامانه قرنطینه",
|
||||
"تعداد در قرنطینه",
|
||||
"ماشین",
|
||||
"راننده",
|
||||
"نژاد",
|
||||
"میانگین وزن اولیه (کیلوگرم)",
|
||||
"قیمت مرغدار",
|
||||
"قیمت کشتارگاه",
|
||||
"دامپزشک فارم",
|
||||
"محل کشتار",
|
||||
"شهر",
|
||||
"تاریخ کشتار",
|
||||
"کدسفارش کشتار",
|
||||
"حجم لاشه",
|
||||
"وزن لاشه",
|
||||
"درصد افت",
|
||||
];
|
||||
|
||||
// Dashboard row data
|
||||
const renderDashboardCell = (value, isBlue = false) => (
|
||||
<Typography variant="caption" style={isBlue ? { color: "blue" } : {}}>
|
||||
{formatNumber(value)}
|
||||
</Typography>
|
||||
);
|
||||
|
||||
const dashboardRow = [
|
||||
renderDashboardCell(dashboardData?.lenKillRequest, true),
|
||||
renderDashboardCell(dashboardData?.killRequestQuantity),
|
||||
renderDashboardCell(dashboardData?.killRequestWeight, true),
|
||||
<Typography key="avg-weight" variant="caption">
|
||||
{dashboardData?.avgWeight || "-"}
|
||||
</Typography>,
|
||||
renderDashboardCell(dashboardData?.minAge, true),
|
||||
renderDashboardCell(dashboardData?.maxAge),
|
||||
renderDashboardCell(dashboardData?.avgAge, true),
|
||||
renderDashboardCell(dashboardData?.lenKillRequestHasCode),
|
||||
renderDashboardCell(dashboardData?.quantityOfKillRequestHasCode, true),
|
||||
renderDashboardCell(dashboardData?.lenKillRequestHasQuarantine),
|
||||
renderDashboardCell(
|
||||
dashboardData?.quantityOfKillRequestHasQuarantine,
|
||||
true
|
||||
),
|
||||
renderDashboardCell(dashboardData?.lenKillRequestHasNotCode),
|
||||
renderDashboardCell(dashboardData?.quantityOfKillRequestHasNotCode, true),
|
||||
renderDashboardCell(dashboardData?.differenceBar),
|
||||
renderDashboardCell(dashboardData?.lenCompleteWithKillHouse, true),
|
||||
renderDashboardCell(dashboardData?.quantityFinalKillHouse),
|
||||
renderDashboardCell(dashboardData?.weightFinalKillHouse, true),
|
||||
renderDashboardCell(dashboardData?.wareHouseBars),
|
||||
renderDashboardCell(dashboardData?.wareHouseBarsQuantity, true),
|
||||
renderDashboardCell(dashboardData?.wareHouseBarsWeight),
|
||||
<Typography key="weight-lose" variant="caption" style={{ color: "blue" }}>
|
||||
{formatNumberFixed(dashboardData?.wareHouseBarsWeightLose)}
|
||||
</Typography>,
|
||||
];
|
||||
|
||||
const excelUrl = buildExcelUrl({
|
||||
baseURL: axios.defaults.baseURL,
|
||||
date1: selectedDate1,
|
||||
date2: selectedDate2,
|
||||
role: currentRole,
|
||||
roleKey,
|
||||
userKey,
|
||||
textValue,
|
||||
});
|
||||
|
||||
return (
|
||||
<Box width="100%" mt={2}>
|
||||
<Grid
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
direction="row"
|
||||
gap={SPACING.SMALL}
|
||||
>
|
||||
<Grid container justifyContent="center" gap={SPACING.SMALL} xs={12}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL} xs={12}>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="از تاریخ"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate1}
|
||||
onChange={handleDateChange1}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid style={{ width: "150px" }}>
|
||||
<DatePicker
|
||||
label="تا تاریخ"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={selectedDate2}
|
||||
onChange={handleDateChange2}
|
||||
/>
|
||||
</Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
value={textValue}
|
||||
/>
|
||||
<Button type="submit" endIcon={<RiSearchLine />}>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
{!!data?.length && (
|
||||
<Grid>
|
||||
<Tooltip title="خروجی اکسل">
|
||||
<a href={excelUrl} rel="noreferrer">
|
||||
<Button color="success">
|
||||
<RiFileExcel2Fill size={32} />
|
||||
</Button>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
)}
|
||||
{showDocumentCheckbox && (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={hasDocumentState}
|
||||
onChange={handleChangeDocumentState}
|
||||
name="document-checkbox"
|
||||
/>
|
||||
}
|
||||
label="بدون وضعیت سند"
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
<Grid container mt={2} mb={4} isDashboard xs={12}>
|
||||
<ResponsiveTable
|
||||
title="خلاصه اطلاعات"
|
||||
noPagination
|
||||
isDashboard
|
||||
columns={dashboardColumns}
|
||||
data={[dashboardRow]}
|
||||
/>
|
||||
</Grid>
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={tableColumns}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="بارهای تکمیل شده"
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
import { Button, Card, IconButton } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { slaughterGetCars } from "../../services/slaughter-get-cars";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteCar } from "../../services/slaughter-delete-car";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { SlaughterNewCar } from "../slaughter-new-car/SlaughterNewCar";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useContext } from "react";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
|
||||
export const SlaughterManageCars = () => {
|
||||
const [dataTable, setDataTable] = useState([]);
|
||||
const { slaughterHouseCars, profile } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(slaughterGetProfile());
|
||||
dispatch(slaughterGetCars());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const filteredData = slaughterHouseCars;
|
||||
const d = filteredData?.map((item, i) => {
|
||||
return [
|
||||
i + 1,
|
||||
item.typeCar,
|
||||
item.pelak,
|
||||
item.capocity,
|
||||
parseInt(item.healthCode),
|
||||
// Number(item.healthCode),
|
||||
item.driverName,
|
||||
item.driverMobile,
|
||||
// @todo make onclick delete the car
|
||||
<IconButton
|
||||
key={i}
|
||||
aria-label="delete"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(
|
||||
slaughterDeleteCar({
|
||||
id: item.id,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
if (r.error.message.includes("403")) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "امکان حذف بدلیل تخصیص بار فعال به خودرو وجود ندارد!",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است!",
|
||||
severity: "error",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
dispatch(slaughterGetCars());
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
}}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>,
|
||||
];
|
||||
});
|
||||
|
||||
setDataTable(d);
|
||||
}, [slaughterHouseCars]);
|
||||
|
||||
const [tableDataCol] = useState([
|
||||
"ردیف",
|
||||
"مدل خودرو",
|
||||
"پلاک",
|
||||
"ظرفیت",
|
||||
"کد بهداشتی",
|
||||
"نام راننده",
|
||||
"موبایل راننده",
|
||||
"حذف",
|
||||
]);
|
||||
return (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={SPACING.SMALL}
|
||||
xs={12}
|
||||
>
|
||||
<Grid>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
content: (
|
||||
<SlaughterNewCar
|
||||
cars={slaughterHouseCars}
|
||||
killHouseKey={profile?.killHouse[0]?.key}
|
||||
/>
|
||||
),
|
||||
title: "ثبت خودرو جدید",
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ثبت خودرو جدید
|
||||
</Button>
|
||||
</Grid>
|
||||
<Card sx={{ width: "100%" }}>
|
||||
<AdvancedTable columns={tableDataCol} data={dataTable} />
|
||||
</Card>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,249 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { BackButton } from "../../../../components/back-button/BackButton";
|
||||
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterManageDelegatesForm } from "./SlaughterManageDelegatesForm";
|
||||
import { SlaughterManageDelegatesOperations } from "./SlaughterManageDelegatesOperations";
|
||||
import { slaughterGetDelegatesInfoService } from "../../services/slaughter-get-delegates-info";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
const SlaughterManageDelegates = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isFirstMount = useRef(true);
|
||||
const isSteward = getRoleFromUrl() === "Steward";
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesInfoService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.trash !== undefined ? !item.trash : null;
|
||||
const statusBadge =
|
||||
isActive === null ? (
|
||||
"-"
|
||||
) : (
|
||||
<Chip
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>
|
||||
);
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
const killhouseDisplay =
|
||||
item?.killHouse?.name && item?.killHouse?.mobile
|
||||
? `${item.killHouse.name} (${item.killHouse.mobile})`
|
||||
: item?.killHouse?.name
|
||||
? item.killHouse.name
|
||||
: "-";
|
||||
|
||||
const stewardDisplay =
|
||||
item?.steward?.name && item?.steward?.user?.mobile
|
||||
? `${item.steward.name} (${item.steward.user.mobile})`
|
||||
: item?.steward?.name
|
||||
? item.steward.name
|
||||
: "-";
|
||||
|
||||
const displayValue = isSteward ? stewardDisplay : killhouseDisplay;
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.createDate ? formatJustDate(item.createDate) : "-",
|
||||
item?.firstName || "-",
|
||||
item?.lastName || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
displayValue,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
statusBadge,
|
||||
<SlaughterManageDelegatesOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstMount.current) {
|
||||
isFirstMount.current = false;
|
||||
return;
|
||||
}
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDelegatesInfoService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenModal = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت نماینده جدید",
|
||||
content: <SlaughterManageDelegatesForm updateTable={updateTableData} />,
|
||||
size: 300,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box display="flex" justifyContent="center">
|
||||
<Grid container xs={12} sm={12} md={10} lg={10}>
|
||||
<Grid item xs={12}>
|
||||
<BackButton />
|
||||
</Grid>
|
||||
<Grid container item gap={SPACING.SMALL}>
|
||||
<Button variant="contained" color="primary" onClick={handleOpenModal}>
|
||||
ثبت نماینده جدید
|
||||
</Button>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<ResponsiveTable
|
||||
title="نمایندگان"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ایجاد",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
isSteward ? "مباشر" : "کشتارگاه",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SlaughterManageDelegates;
|
||||
@@ -0,0 +1,165 @@
|
||||
import React, { useContext } from "react";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import {
|
||||
slaughterSubmitRepresentativeService,
|
||||
slaughterEditRepresentativeService,
|
||||
} from "../../services/slaughter-submit-delegate";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
|
||||
const getValidationSchema = () =>
|
||||
yup.object({
|
||||
first_name: yup.string().required("نام الزامی است"),
|
||||
last_name: yup.string().required("نام خانوادگی الزامی است"),
|
||||
mobile: yup
|
||||
.string()
|
||||
.required("شماره همراه الزامی است")
|
||||
.matches(/^09\d{9}$/, "شماره تلفن باید با 09 شروع شود و 11 رقم باشد"),
|
||||
city: yup.string().required("شهر الزامی است"),
|
||||
});
|
||||
|
||||
export const SlaughterManageDelegatesForm = ({ updateTable, item, isEdit }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
first_name: item?.first_name || item?.firstName || "",
|
||||
last_name: item?.last_name || item?.lastName || "",
|
||||
mobile: item?.mobile || "",
|
||||
city: item?.city || "",
|
||||
},
|
||||
enableReinitialize: true,
|
||||
validationSchema: getValidationSchema(),
|
||||
onSubmit: (values) => {
|
||||
const submitData = isEdit
|
||||
? {
|
||||
key: item?.key,
|
||||
first_name: values.first_name,
|
||||
last_name: values.last_name,
|
||||
mobile: values.mobile,
|
||||
city: values.city,
|
||||
}
|
||||
: {
|
||||
first_name: values.first_name,
|
||||
last_name: values.last_name,
|
||||
mobile: values.mobile,
|
||||
city: values.city,
|
||||
role: getRoleFromUrl(),
|
||||
};
|
||||
|
||||
const service = isEdit
|
||||
? slaughterEditRepresentativeService
|
||||
: slaughterSubmitRepresentativeService;
|
||||
|
||||
dispatch(service(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="نام"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="first_name"
|
||||
name="first_name"
|
||||
value={formik.values.first_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={
|
||||
formik.touched.first_name && Boolean(formik.errors.first_name)
|
||||
}
|
||||
helperText={formik.touched.first_name && formik.errors.first_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="نام خانوادگی"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="last_name"
|
||||
name="last_name"
|
||||
value={formik.values.last_name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.last_name && Boolean(formik.errors.last_name)}
|
||||
helperText={formik.touched.last_name && formik.errors.last_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="شماره همراه"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="mobile"
|
||||
name="mobile"
|
||||
value={formik.values.mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.mobile && Boolean(formik.errors.mobile)}
|
||||
helperText={formik.touched.mobile && formik.errors.mobile}
|
||||
inputProps={{ maxLength: 11 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="شهر"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="city"
|
||||
name="city"
|
||||
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}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={!formik.isValid}
|
||||
>
|
||||
{isEdit ? "ویرایش" : "ثبت"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Typography,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterEditRepresentativeService } from "../../services/slaughter-submit-delegate";
|
||||
|
||||
export const SlaughterManageDelegatesLimitationForm = ({
|
||||
item,
|
||||
updateTable,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const [hasLimitation, setHasLimitation] = useState(item?.limitation || false);
|
||||
const [governmentalValue, setGovernmentalValue] = useState(
|
||||
item?.governmentalLimitationWeight || 0
|
||||
);
|
||||
const [freeValue, setFreeValue] = useState(item?.freeLimitationWeight || 0);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitData = {
|
||||
key: item?.key,
|
||||
limitation: hasLimitation,
|
||||
governmental_limitation_weight: hasLimitation
|
||||
? Number(governmentalValue)
|
||||
: 0,
|
||||
free_limitation_weight: hasLimitation ? Number(freeValue) : 0,
|
||||
};
|
||||
|
||||
dispatch(slaughterEditRepresentativeService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid container item xs={12} alignItems="center" gap={1}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
اطلاعات نماینده:
|
||||
</Typography>
|
||||
<Typography variant="h6" mb={0.75}>
|
||||
{item?.firstName} {item?.lastName}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mb={1}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={hasLimitation}
|
||||
onChange={(e) => setHasLimitation(e.target.checked)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="محدودیت فروش روزانه"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{hasLimitation && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش دولتی (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={governmentalValue}
|
||||
onChange={(e) => setGovernmentalValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش آزاد (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={freeValue}
|
||||
onChange={(e) => setFreeValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={
|
||||
hasLimitation && governmentalValue === 0 && freeValue === 0
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,114 @@
|
||||
import { IconButton, Popover, Typography, Button, Box } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterManageDelegatesForm } from "./SlaughterManageDelegatesForm";
|
||||
import { SlaughterManageDelegatesLimitationForm } from "./SlaughterManageDelegatesLimitationForm";
|
||||
|
||||
export const SlaughterManageDelegatesOperations = ({ item, updateTable }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
padding: "10px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "8px",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش نماینده",
|
||||
content: (
|
||||
<SlaughterManageDelegatesForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
isEdit
|
||||
/>
|
||||
),
|
||||
size: 300,
|
||||
})
|
||||
);
|
||||
}}
|
||||
startIcon={<EditIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
ویرایش
|
||||
</Typography>
|
||||
</Button>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تنظیم محدودیت فروش",
|
||||
content: (
|
||||
<SlaughterManageDelegatesLimitationForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
size: 400,
|
||||
})
|
||||
);
|
||||
}}
|
||||
startIcon={<BlockIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
تنظیم محدودیت
|
||||
</Typography>
|
||||
</Button>
|
||||
</Box>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,253 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Box, Button, Grid, TextField, Chip } from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { BackButton } from "../../../../components/back-button/BackButton";
|
||||
|
||||
import { OPEN_MODAL, CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterManageDispensersForm } from "./SlaughterManageDispensersForm";
|
||||
import { slaughterGetDispenserInfoService } from "../../services/slaughter-get-dispenser-info";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { SlaughterManageDispensersOperations } from "./SlaughterManageDispensersOperations";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
const SlaughterManageDispensers = () => {
|
||||
const dispatch = useDispatch();
|
||||
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 isSteward = getRoleFromUrl() === "Steward";
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const handleTextChange = (e) => setTextValue(e.target.value);
|
||||
|
||||
const fetchApiData = async (pageNum) => {
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: pageNum,
|
||||
page_size: perPage,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (pageNum) => {
|
||||
fetchApiData(pageNum);
|
||||
setPage(pageNum);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(Number(perRows));
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
const updateTableData = () => {
|
||||
fetchApiData(page !== 0 ? page : 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data || !Array.isArray(data)) {
|
||||
setTableData([]);
|
||||
return;
|
||||
}
|
||||
const d = data.map((item, i) => {
|
||||
const isActive = item?.active !== undefined ? item.active : null;
|
||||
const statusBadge =
|
||||
isActive === null ? (
|
||||
"-"
|
||||
) : (
|
||||
<Chip
|
||||
label={isActive ? "فعال" : "غیرفعال"}
|
||||
color={isActive ? "success" : "error"}
|
||||
size="small"
|
||||
sx={{ minWidth: 80 }}
|
||||
/>
|
||||
);
|
||||
const hasLimitation = item?.limitation;
|
||||
const limitationBadge = (
|
||||
<Chip
|
||||
label={hasLimitation ? "دارد" : "ندارد"}
|
||||
color={hasLimitation ? "warning" : "default"}
|
||||
size="small"
|
||||
sx={{ minWidth: 60 }}
|
||||
/>
|
||||
);
|
||||
const killhouseDisplay =
|
||||
item?.killHouse?.name && item?.killHouse?.mobile
|
||||
? `${item.killHouse.name} (${item.killHouse.mobile})`
|
||||
: item?.killHouse?.name
|
||||
? item.killHouse.name
|
||||
: "-";
|
||||
|
||||
const stewardDisplay =
|
||||
item?.steward?.name && item?.steward?.user?.mobile
|
||||
? `${item.steward.name} (${item.steward.user.mobile})`
|
||||
: item?.steward?.name
|
||||
? item.steward.name
|
||||
: "-";
|
||||
|
||||
const displayValue = isSteward ? stewardDisplay : killhouseDisplay;
|
||||
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.createDate ? formatJustDate(item.createDate) : "-",
|
||||
item?.nationalId || "-",
|
||||
item?.firstName || "-",
|
||||
item?.lastName || "-",
|
||||
item?.mobile || "-",
|
||||
item?.city || "-",
|
||||
item?.province || "-",
|
||||
displayValue,
|
||||
limitationBadge,
|
||||
item?.governmentalLimitationWeight || 0,
|
||||
item?.freeLimitationWeight || 0,
|
||||
statusBadge,
|
||||
<SlaughterManageDispensersOperations
|
||||
key={`operations-${item?.key || i}`}
|
||||
item={item}
|
||||
updateTable={updateTableData}
|
||||
/>,
|
||||
];
|
||||
});
|
||||
setTableData(d);
|
||||
}, [data, page, perPage]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
setPage(1);
|
||||
}, [perPage, selectedSubUser?.key]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setPage(1);
|
||||
const response = await dispatch(
|
||||
slaughterGetDispenserInfoService({
|
||||
search: "filter",
|
||||
value: textValue,
|
||||
page: 1,
|
||||
page_size: perPage,
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
|
||||
if (response.payload.error) {
|
||||
console.error("Error fetching data:", response.payload.error);
|
||||
setData([]);
|
||||
setTotalRows(0);
|
||||
} else {
|
||||
setData(response.payload.data?.results || []);
|
||||
const count = Number(response.payload.data?.count) || 0;
|
||||
setTotalRows(count);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpenModal = () => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت توزیع کننده جدید",
|
||||
content: (
|
||||
<SlaughterManageDispensersForm
|
||||
onClose={() => dispatch(CLOSE_MODAL())}
|
||||
updateTable={updateTableData}
|
||||
/>
|
||||
),
|
||||
size: 300,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box display="flex" justifyContent="center">
|
||||
<Grid container xs={12} sm={12} md={10} lg={10}>
|
||||
<Grid item xs={12}>
|
||||
<BackButton />
|
||||
</Grid>
|
||||
<Grid container item gap={SPACING.SMALL}>
|
||||
<Button variant="contained" color="primary" onClick={handleOpenModal}>
|
||||
ثبت توزیع کننده جدید
|
||||
</Button>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container alignItems="center" gap={SPACING.SMALL}>
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 200 }}
|
||||
value={textValue}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</Grid>
|
||||
</form>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<ResponsiveTable
|
||||
title="توزیع کنندگان"
|
||||
columns={[
|
||||
"ردیف",
|
||||
"تاریخ ایجاد",
|
||||
"کد ملی",
|
||||
"نام",
|
||||
"نام خانوادگی",
|
||||
"شماره همراه",
|
||||
"شهر",
|
||||
"استان",
|
||||
isSteward ? "مباشر" : "کشتارگاه",
|
||||
"محدودیت فروش",
|
||||
"حداکثر فروش دولتی",
|
||||
"حداکثر فروش آزاد",
|
||||
"وضعیت",
|
||||
"عملیات",
|
||||
]}
|
||||
customWidth={"100%"}
|
||||
data={tableData}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SlaughterManageDispensers;
|
||||
@@ -0,0 +1,577 @@
|
||||
import React, {
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { useFormik } from "formik";
|
||||
import * as yup from "yup";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Button, TextField, Typography, Box } from "@mui/material";
|
||||
import PersonIcon from "@mui/icons-material/Person";
|
||||
import PublicIcon from "@mui/icons-material/Public";
|
||||
import BadgeIcon from "@mui/icons-material/Badge";
|
||||
import CalendarTodayIcon from "@mui/icons-material/CalendarToday";
|
||||
import AccountBoxIcon from "@mui/icons-material/AccountBox";
|
||||
import BusinessIcon from "@mui/icons-material/Business";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterGetDispenserUserInfoService } from "../../services/slaughter-get-dispenser-user-info";
|
||||
import { provinceGetCitiesService } from "../../../province/services/province-get-cities";
|
||||
import {
|
||||
slaughterHouseSubmitDispenserService,
|
||||
slaughterHouseEditDispenserService,
|
||||
} from "../../services/slaughter-house-submit-dispenser-service";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
const InfoBox = ({ icon: Icon, label, value, iconSx }) => (
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems={iconSx ? "flex-start" : "center"}
|
||||
gap={1}
|
||||
px={1.5}
|
||||
py={0.5}
|
||||
bgcolor="#f5f5f5"
|
||||
borderRadius={1}
|
||||
>
|
||||
<Icon color="action" sx={iconSx} />
|
||||
<Box>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{label}
|
||||
</Typography>
|
||||
<Typography variant="body1">{value || "-"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const getValidationSchema = () =>
|
||||
yup.object({
|
||||
mobile: yup
|
||||
.string()
|
||||
.required("شماره همراه الزامی است")
|
||||
.matches(/^09\d{9}$/, "شماره تلفن باید با 09 شروع شود و 11 رقم باشد"),
|
||||
});
|
||||
|
||||
const DispenserForm = ({ formik, userInfo }) => {
|
||||
return (
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
}}
|
||||
gutterBottom
|
||||
>
|
||||
اطلاعات توزیع کننده
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
{/* Additional User Info Section */}
|
||||
{userInfo && (
|
||||
<Grid container spacing={2} xs={12} mb={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
color="text.secondary"
|
||||
gutterBottom
|
||||
sx={{ mb: 1 }}
|
||||
>
|
||||
اطلاعات شخصی
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="کد ملی"
|
||||
value={userInfo.nationalCode || formik.values.national_id}
|
||||
/>
|
||||
</Grid>
|
||||
{userInfo.fatherName && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام پدر"
|
||||
value={userInfo.fatherName}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{userInfo.birthDate && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={CalendarTodayIcon}
|
||||
label="تاریخ تولد"
|
||||
value={userInfo.birthDate}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{userInfo.gender !== undefined && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={AccountBoxIcon}
|
||||
label="جنسیت"
|
||||
value={userInfo.gender ? "مرد" : "زن"}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{userInfo.identityNo && userInfo.identityNo !== "0" && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="شماره شناسنامه"
|
||||
value={userInfo.identityNo}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{userInfo.identitySeries && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="سری شناسنامه"
|
||||
value={userInfo.identitySeries}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
{userInfo.identitySerial && (
|
||||
<Grid item xs={12} md={4}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="سریال شناسنامه"
|
||||
value={userInfo.identitySerial}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid container spacing={2} xs={12}>
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام"
|
||||
value={formik.values.first_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={PersonIcon}
|
||||
label="نام خانوادگی"
|
||||
value={formik.values.last_name}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="شماره همراه"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
id="mobile"
|
||||
name="mobile"
|
||||
value={formik.values.mobile}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={Boolean(formik.errors.mobile)}
|
||||
helperText={formik.errors.mobile}
|
||||
inputProps={{ maxLength: 11 }}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={PublicIcon}
|
||||
label="شهر"
|
||||
value={formik.values.city}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="نوع توزیع کننده"
|
||||
value={
|
||||
formik.values.dispenser_type === "inductor"
|
||||
? "واسطه"
|
||||
: formik.values.dispenser_type === "salesman"
|
||||
? "فروشنده"
|
||||
: formik.values.dispenser_type === "driver"
|
||||
? "راننده"
|
||||
: formik.values.dispenser_type
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{formik.values.dispenser_type === "driver" && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="نوع خودرو"
|
||||
value={formik.values.driver_car_type}
|
||||
/>
|
||||
</Grid>
|
||||
{formik.values.pelak && (
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={BadgeIcon}
|
||||
label="پلاک خودرو"
|
||||
value={formik.values.pelak}
|
||||
/>
|
||||
</Grid>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12}>
|
||||
<InfoBox
|
||||
icon={BusinessIcon}
|
||||
label="سقف محدودیت"
|
||||
value={formik.values.limitation_amount || 0}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={!formik.isValid}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
const InquiryForm = ({ onInquiry, nationalCode, setNationalCode }) => {
|
||||
return (
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="کد ملی"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
value={nationalCode}
|
||||
onChange={(e) => setNationalCode(e.target.value)}
|
||||
placeholder="کد ملی 10 رقمی را وارد کنید"
|
||||
inputProps={{ maxLength: 10 }}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<Button
|
||||
color="primary"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
onClick={onInquiry}
|
||||
disabled={!nationalCode || nationalCode.length !== 10}
|
||||
>
|
||||
استعلام
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export const SlaughterManageDispensersForm = ({
|
||||
onClose,
|
||||
updateTable,
|
||||
dispenser,
|
||||
initialUserData,
|
||||
initialUserInfo,
|
||||
initialNationalCode,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [nationalCode, setNationalCode] = useState(
|
||||
initialNationalCode ||
|
||||
dispenser?.user?.nationalId ||
|
||||
dispenser?.national_id ||
|
||||
""
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const [userData, setUserData] = useState(
|
||||
initialUserData ||
|
||||
(dispenser
|
||||
? {
|
||||
national_id: dispenser?.user?.nationalId || "",
|
||||
first_name: dispenser?.user?.firstName || "",
|
||||
last_name: dispenser?.user?.lastName || "",
|
||||
city: dispenser?.user?.city?.cityName || "",
|
||||
mobile: dispenser?.user?.mobile || "",
|
||||
dispenser_type: dispenser?.dispenserType || "inductor",
|
||||
limitation_amount: dispenser?.limitation_amount || 0,
|
||||
driver_car_type: dispenser?.car || "",
|
||||
pelak: dispenser?.pelak || "",
|
||||
}
|
||||
: null)
|
||||
);
|
||||
const [userFound, setUserFound] = useState(dispenser ? true : false); // eslint-disable-line no-unused-vars
|
||||
const [cities, setCities] = useState([]);
|
||||
const [userInfo, setUserInfo] = useState(initialUserInfo || null);
|
||||
const sizeUpdatedRef = useRef(!!initialUserData);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(provinceGetCitiesService()).then((r) => {
|
||||
setCities(r.payload.data || []);
|
||||
});
|
||||
}, [dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (userData && !sizeUpdatedRef.current && !dispenser) {
|
||||
sizeUpdatedRef.current = true;
|
||||
const isDesktop = window.innerWidth > 600;
|
||||
const preservedUserData = userData;
|
||||
const preservedUserInfo = userInfo;
|
||||
const preservedNationalCode = nationalCode;
|
||||
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ثبت توزیع کننده جدید",
|
||||
content: (
|
||||
<SlaughterManageDispensersForm
|
||||
onClose={onClose}
|
||||
updateTable={updateTable}
|
||||
initialUserData={preservedUserData}
|
||||
initialUserInfo={preservedUserInfo}
|
||||
initialNationalCode={preservedNationalCode}
|
||||
/>
|
||||
),
|
||||
size: isDesktop ? 600 : 300,
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [
|
||||
userData,
|
||||
dispatch,
|
||||
onClose,
|
||||
updateTable,
|
||||
dispenser,
|
||||
userInfo,
|
||||
nationalCode,
|
||||
]);
|
||||
|
||||
const handleInquiry = useCallback(() => {
|
||||
if (!nationalCode || nationalCode.length !== 10) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "لطفا کد ملی 10 رقمی معتبر وارد کنید",
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
slaughterGetDispenserUserInfoService({
|
||||
national_code: nationalCode,
|
||||
role_key:
|
||||
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.payload.error) {
|
||||
setUserFound(false);
|
||||
setUserInfo(null);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else if (r.payload.data) {
|
||||
const response = r.payload.data;
|
||||
|
||||
if (response.status === true && response.data) {
|
||||
const userDataFromApi = response.data;
|
||||
|
||||
setUserFound(true);
|
||||
setUserInfo(userDataFromApi);
|
||||
|
||||
console.log(userDataFromApi);
|
||||
setUserData({
|
||||
national_id: userDataFromApi.nationalCode || nationalCode,
|
||||
first_name: userDataFromApi.firstName || "",
|
||||
last_name: userDataFromApi.lastName || "",
|
||||
city: userDataFromApi.city || "",
|
||||
mobile: "", // Mobile is not in API response, user must enter it
|
||||
dispenser_type: "inductor",
|
||||
limitation_amount: 0,
|
||||
});
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "اطلاعات با موفقیت دریافت شد",
|
||||
severity: "success",
|
||||
});
|
||||
} else if (response.status === false) {
|
||||
setUserFound(false);
|
||||
setUserInfo(null);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: response.errorDescription || "خطا در دریافت اطلاعات",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
const userDataFromApi = response.data || response;
|
||||
|
||||
if (userDataFromApi && userDataFromApi.nationalCode) {
|
||||
setUserFound(true);
|
||||
setUserInfo(userDataFromApi);
|
||||
|
||||
setUserData({
|
||||
national_id: userDataFromApi.nationalCode || nationalCode,
|
||||
first_name: userDataFromApi.firstName || "",
|
||||
last_name: userDataFromApi.lastName || "",
|
||||
city: userDataFromApi.city || "",
|
||||
mobile: "",
|
||||
dispenser_type: "inductor",
|
||||
limitation_amount: 0,
|
||||
});
|
||||
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "اطلاعات با موفقیت دریافت شد",
|
||||
severity: "success",
|
||||
});
|
||||
} else {
|
||||
setUserFound(false);
|
||||
setUserInfo(null);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "خطا در دریافت اطلاعات",
|
||||
severity: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [dispatch, nationalCode, openNotif, selectedSubUser]);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
national_id:
|
||||
userData?.national_id ||
|
||||
userData?.nationalCode ||
|
||||
userData?.nationalId ||
|
||||
"",
|
||||
first_name: userData?.first_name || "",
|
||||
last_name: userData?.last_name || "",
|
||||
city: userData?.city || "",
|
||||
mobile: userData?.mobile || "",
|
||||
dispenser_type: userData?.dispenser_type || "inductor",
|
||||
limitation_amount: userData?.limitation_amount || 0,
|
||||
driver_car_type: userData?.driverCarType || userData?.car || "",
|
||||
pelak: userData?.pelak || "",
|
||||
},
|
||||
validationSchema: getValidationSchema(),
|
||||
enableReinitialize: true,
|
||||
onSubmit: (values) => {
|
||||
const currentUserInfo = userInfo;
|
||||
const submitData = {
|
||||
nationalCode: values.national_id || "",
|
||||
firstName: values.first_name || "",
|
||||
lastName: values.last_name || "",
|
||||
fatherName: currentUserInfo?.fatherName || null,
|
||||
gender:
|
||||
currentUserInfo?.gender !== undefined ? currentUserInfo.gender : null,
|
||||
isLive:
|
||||
currentUserInfo?.isLive !== undefined ? currentUserInfo.isLive : true,
|
||||
identityNo: currentUserInfo?.identityNo || null,
|
||||
birthDate: currentUserInfo?.birthDate || null,
|
||||
city: values.city || currentUserInfo?.city || "",
|
||||
mobile: values.mobile,
|
||||
role: getRoleFromUrl(),
|
||||
};
|
||||
|
||||
if (dispenser?.key) {
|
||||
// Edit mode
|
||||
dispatch(
|
||||
slaughterHouseEditDispenserService({
|
||||
type: "update-profile",
|
||||
dispenser_key: dispenser.key,
|
||||
...submitData,
|
||||
})
|
||||
).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Create mode
|
||||
dispatch(slaughterHouseSubmitDispenserService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!userData && !dispenser) {
|
||||
return (
|
||||
<InquiryForm
|
||||
onInquiry={handleInquiry}
|
||||
nationalCode={nationalCode}
|
||||
setNationalCode={setNationalCode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <DispenserForm formik={formik} cities={cities} userInfo={userInfo} />;
|
||||
};
|
||||
@@ -0,0 +1,133 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
TextField,
|
||||
Typography,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterEditDispenserInfoService } from "../../services/slaughter-edit-dispenser-info";
|
||||
|
||||
export const SlaughterManageDispensersLimitationForm = ({
|
||||
item,
|
||||
updateTable,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
|
||||
const [hasLimitation, setHasLimitation] = useState(item?.limitation || false);
|
||||
const [governmentalValue, setGovernmentalValue] = useState(
|
||||
item?.governmentalLimitationWeight || 0
|
||||
);
|
||||
const [freeValue, setFreeValue] = useState(item?.freeLimitationWeight || 0);
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitData = {
|
||||
key: item?.key,
|
||||
limitation: hasLimitation,
|
||||
governmental_limitation_weight: hasLimitation
|
||||
? Number(governmentalValue)
|
||||
: 0,
|
||||
free_limitation_weight: hasLimitation ? Number(freeValue) : 0,
|
||||
};
|
||||
|
||||
dispatch(slaughterEditDispenserInfoService(submitData)).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",
|
||||
});
|
||||
if (updateTable) {
|
||||
updateTable();
|
||||
}
|
||||
dispatch(CLOSE_MODAL());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Grid container gap={SPACING.SMALL} p={2}>
|
||||
<Grid container item xs={12} alignItems="center" gap={1}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
اطلاعات توزیع کننده:
|
||||
</Typography>
|
||||
<Typography variant="h6" mb={0.75}>
|
||||
{item?.firstName} {item?.lastName}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} mb={1}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={hasLimitation}
|
||||
onChange={(e) => setHasLimitation(e.target.checked)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="محدودیت فروش روزانه"
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
{hasLimitation && (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش دولتی (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={governmentalValue}
|
||||
onChange={(e) => setGovernmentalValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
label="حداکثر فروش آزاد (کیلوگرم)"
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
type="number"
|
||||
value={freeValue}
|
||||
onChange={(e) => setFreeValue(e.target.value)}
|
||||
inputProps={{ min: 0 }}
|
||||
/>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Grid item xs={12} mt={2}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
disabled={
|
||||
hasLimitation && governmentalValue === 0 && freeValue === 0
|
||||
}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
import { IconButton, Popover, Typography, Button } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { SlaughterManageDispensersLimitationForm } from "./SlaughterManageDispensersLimitationForm";
|
||||
|
||||
export const SlaughterManageDispensersOperations = ({ item, updateTable }) => {
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
const handleOpenLimitationModal = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تنظیم محدودیت فروش",
|
||||
content: (
|
||||
<SlaughterManageDispensersLimitationForm
|
||||
item={item}
|
||||
updateTable={updateTable}
|
||||
/>
|
||||
),
|
||||
size: 400,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleClick}
|
||||
size="small"
|
||||
>
|
||||
<TuneIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<div style={{ padding: "10px" }}>
|
||||
<Button
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={handleOpenLimitationModal}
|
||||
startIcon={<BlockIcon fontSize="small" />}
|
||||
sx={{ textTransform: "none", userSelect: "text" }}
|
||||
>
|
||||
<Typography variant="body2" sx={{ userSelect: "text" }}>
|
||||
تنظیم محدودیت
|
||||
</Typography>
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Popover,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterInventoryFinalSubmitService } from "../../services/slaughter-inventory-final-submit";
|
||||
import { slaughterDeleteAllocatedService } from "../../services/salughter-delete-allocated";
|
||||
import { SlaughterAllocateToGuild } from "../slaughter-allocate-to-guild/SlaughterAllocateToGuild";
|
||||
import { SlaughterAllocateForFreezing } from "../slaughter-allocate-for-freezing/SlaughterAllocateForFreezing";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
|
||||
export const SlaughterManageInventoryAllocationOperations = ({
|
||||
fetchApiData,
|
||||
item,
|
||||
priceInfo,
|
||||
remainWeight,
|
||||
}) => {
|
||||
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 [openNotif] = useContext(AppContext);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleEdit = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "ویرایش تخصیص",
|
||||
content:
|
||||
item?.allocationType === "ColdHouse" ? (
|
||||
<SlaughterAllocateForFreezing
|
||||
fetchApiData={fetchApiData}
|
||||
editData={item}
|
||||
priceInfo={priceInfo}
|
||||
remainWeight={remainWeight}
|
||||
/>
|
||||
) : (
|
||||
<SlaughterAllocateToGuild
|
||||
fetchApiData={fetchApiData}
|
||||
editData={item}
|
||||
priceInfo={priceInfo}
|
||||
remainWeight={remainWeight}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleFinalSubmit = () => {
|
||||
handleClose();
|
||||
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(
|
||||
slaughterInventoryFinalSubmitService({
|
||||
steward_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 {
|
||||
fetchApiData(1);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
<Button
|
||||
fullWidth
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "آیا مطمئن هستید؟",
|
||||
content: (
|
||||
<Grid container spacing={2}>
|
||||
<Grid item>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterDeleteAllocatedService({
|
||||
steward_allocation_key: item.key,
|
||||
})
|
||||
).then(() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
dispatch(fetchSlaughterBroadcastAndProducts());
|
||||
fetchApiData(1);
|
||||
});
|
||||
}}
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
}}
|
||||
>
|
||||
لغو
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const options = [
|
||||
{
|
||||
key: "edit",
|
||||
label: "ویرایش",
|
||||
icon: EditIcon,
|
||||
color: "primary.main",
|
||||
action: handleEdit,
|
||||
},
|
||||
];
|
||||
|
||||
if (!item?.registrationCode) {
|
||||
options.push({
|
||||
key: "finalSubmit",
|
||||
label: "تایید نهایی",
|
||||
icon: CheckCircleOutlineIcon,
|
||||
color: "info.main",
|
||||
action: handleFinalSubmit,
|
||||
});
|
||||
}
|
||||
|
||||
if (!item?.registrationCode) {
|
||||
options.push({
|
||||
key: "delete",
|
||||
label: "حذف",
|
||||
icon: DeleteIcon,
|
||||
color: "error.main",
|
||||
action: handleDelete,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<IconButton
|
||||
size="small"
|
||||
disabled={item?.registrationCode}
|
||||
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={{ minWidth: 160, p: 0.5 }}>
|
||||
{options.map((option) => {
|
||||
const IconComponent = option.icon;
|
||||
return (
|
||||
<ListItemButton
|
||||
key={option.key}
|
||||
onClick={option.action}
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
mb: 0.25,
|
||||
py: 0.5,
|
||||
"&:last-of-type": { mb: 0 },
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 32, color: option.color }}>
|
||||
<IconComponent fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={option.label}
|
||||
primaryTypographyProps={{
|
||||
sx: {
|
||||
color: option.color,
|
||||
fontSize: "0.82rem",
|
||||
fontWeight: 600,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,191 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { useContext } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteAllocatedService } from "../../services/salughter-delete-allocated";
|
||||
import { slaughterGetUpdatedInventoryStock } from "../../services/salughter-get-updated-inventory-stock";
|
||||
import { slaughterManageInventoryAllocationsService } from "../../services/salughter-manage-inventory-allocations";
|
||||
import { slaughterGetKillhouseGuildsService } from "../../services/slaughter-get-killhouse-guilds";
|
||||
import { slaughterGetKillhouseStewardsService } from "../../services/slaughter-get-killhouse-stewards";
|
||||
import { SlaughterAddSteward } from "../slaughter-add-steward/SlaughterAddSteward";
|
||||
import { SubmitAuthCode } from "../submit-auth-code/SubmitAuthCode";
|
||||
import { slaughterInventoryFinalSubmitService } from "../../services/slaughter-inventory-final-submit";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
|
||||
export const SlaughterManageInventoryAllocationOperationsTest = ({
|
||||
item,
|
||||
disabled,
|
||||
}) => {
|
||||
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 || disabled
|
||||
}
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "کداحراز",
|
||||
content: <SubmitAuthCode 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(
|
||||
slaughterInventoryFinalSubmitService({
|
||||
steward_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(
|
||||
slaughterManageInventoryAllocationsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
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: (
|
||||
<SlaughterAddSteward
|
||||
item={item}
|
||||
quantity={item.numberOfCarcasses}
|
||||
weight={item.weightOfCarcasses}
|
||||
stewardKey={item.key}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
ویرایش
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={item.finalRegistration}
|
||||
color="error"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
slaughterDeleteAllocatedService({
|
||||
steward_allocation_key: item.key,
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(
|
||||
slaughterGetKillhouseStewardsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetUpdatedInventoryStock({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterManageInventoryAllocationsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
slaughterGetKillhouseGuildsService({
|
||||
kill_house_key: inventorySelectedKillHouse,
|
||||
date: selectedDate1,
|
||||
})
|
||||
);
|
||||
});
|
||||
}}
|
||||
>
|
||||
حذف
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export const SlaughterMorgueBroadcastManagement = () => {
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
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_SLAUGHTER_MORGUE_BROADCAST_MANAGEMENT,
|
||||
ROUTE_SLAUGHTER_MORGUE_STOCK,
|
||||
} from "../../../../routes/routes";
|
||||
|
||||
export const SlaughterMorgueOperation = () => {
|
||||
const { pathname } = useLocation();
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
p={SPACING.SMALL}
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
justifyContent="center"
|
||||
style={{ placeContent: "baseline" }}
|
||||
>
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_MORGUE_STOCK}
|
||||
active={pathname === ROUTE_SLAUGHTER_MORGUE_STOCK ? "true" : null}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="موجودی انبار"
|
||||
/>
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_MORGUE_BROADCAST_MANAGEMENT}
|
||||
active={
|
||||
pathname === ROUTE_SLAUGHTER_MORGUE_BROADCAST_MANAGEMENT
|
||||
? "true"
|
||||
: null
|
||||
}
|
||||
>
|
||||
<LinkItem
|
||||
icon={<VscNewFolder size={30} color="#244CCC" />}
|
||||
title="مدیریت پخش"
|
||||
/>
|
||||
</NavLink>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export const SlaughterMorgueStock = () => {
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,221 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import moment from "moment";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import {
|
||||
liveStockGetInventoryData,
|
||||
liveStockGetInventoryDataDashboard,
|
||||
} from "../../../live-stock-support/services/live-stock-get-inventory-data";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { SlaughterColdHouseBars } from "../slaughter-cold-house-bars/SlaughterColdHouseBars";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterMorgueView = () => {
|
||||
const dispatch = useDispatch();
|
||||
const [tableData, setTableData] = useState([]);
|
||||
const [tableDataDashboard, setTableDataDashboard] = useState([]);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const { key } = useParams();
|
||||
|
||||
const [withDate, setWithDate] = useState(false);
|
||||
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const [selectedDate2, setSelectedDate2] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
|
||||
const getDashboardsData = () => {
|
||||
dispatch(
|
||||
liveStockGetInventoryData({
|
||||
dashboard: true,
|
||||
cold_house_key: key,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setTableData(r.payload.data);
|
||||
});
|
||||
dispatch(
|
||||
liveStockGetInventoryDataDashboard({
|
||||
date1: withDate ? selectedDate1 : null,
|
||||
date2: withDate ? selectedDate2 : null,
|
||||
cold_house_key: key,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then((r) => {
|
||||
setTableDataDashboard(r.payload.data);
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
getDashboardsData();
|
||||
}, [dispatch, withDate, selectedDate1, selectedDate2, selectedSubUser?.key]);
|
||||
|
||||
const [value, setValue] = useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container direction="column" justifyContent="center" xs={12}>
|
||||
<Grid container justifyContent="space-between" gap={SPACING.SMALL}>
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
columns={["وزن کل", "وزن خارج شده", "وزن باقیمانده"]}
|
||||
data={[
|
||||
[
|
||||
tableData?.totalInputWeight?.toLocaleString(),
|
||||
tableData?.totalAllocatedWeight?.toLocaleString(),
|
||||
tableData?.totalRemainWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title="موجودی سردخانه"
|
||||
isDashboard
|
||||
/>
|
||||
|
||||
<ResponsiveTable
|
||||
noPagination
|
||||
columns={[
|
||||
"تعداد کل بارهای وارد شده",
|
||||
"وزن کل بارهای وارد شده",
|
||||
"تعداد کل بارهای خارج شده",
|
||||
"وزن کل بارهای خارج شده",
|
||||
]}
|
||||
data={[
|
||||
[
|
||||
tableDataDashboard?.totalInputBars?.toLocaleString(),
|
||||
tableDataDashboard?.totalInputBarsWeight?.toLocaleString(),
|
||||
tableDataDashboard?.totalOutputBars?.toLocaleString(),
|
||||
tableDataDashboard?.totalOutputBarsWeight?.toLocaleString(),
|
||||
],
|
||||
]}
|
||||
title={"خلاصه اطلاعات"}
|
||||
isDashboard
|
||||
/>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
gap={2}
|
||||
paddingTop={2}
|
||||
mb={1}
|
||||
width="100%"
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
gap={1}
|
||||
style={{
|
||||
borderStyle: "solid",
|
||||
borderWidth: "1px",
|
||||
padding: "10px",
|
||||
borderRadius: "15px",
|
||||
borderColor: "gray",
|
||||
justifyContent: "left",
|
||||
}}
|
||||
>
|
||||
<Grid>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={withDate}
|
||||
onChange={() => setWithDate(!withDate)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container xs={12} justifyContent="center">
|
||||
<Tabs
|
||||
sx={{ mb: 2 }}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
aria-label="simple tabs example"
|
||||
>
|
||||
<Tab value={0} label="بارهای خارج شده" />
|
||||
<Tab value={1} label="بارهای وارد شده" />
|
||||
</Tabs>
|
||||
{value === 0 && (
|
||||
<SlaughterColdHouseBars
|
||||
selectedDate1={selectedDate1}
|
||||
selectedDate2={selectedDate2}
|
||||
title="بارهای خارج شده"
|
||||
type={"output"}
|
||||
withDate={withDate}
|
||||
coldHouseKey={key}
|
||||
getDashboardsData={getDashboardsData}
|
||||
remainWeight={tableData?.totalRemainWeight}
|
||||
/>
|
||||
)}
|
||||
{value === 1 && (
|
||||
<SlaughterColdHouseBars
|
||||
selectedDate1={selectedDate1}
|
||||
selectedDate2={selectedDate2}
|
||||
title="بارهای وارد شده"
|
||||
type={"input"}
|
||||
withDate={withDate}
|
||||
coldHouseKey={key}
|
||||
getDashboardsData={getDashboardsData}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,374 @@
|
||||
import { Button, Grid, IconButton, TextField, Typography } from "@mui/material";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import SendIcon from "@mui/icons-material/Send";
|
||||
import { useFormik } from "formik";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterNewCar } from "../../services/slaughter-new-car";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterGetCars } from "../../services/slaughter-get-cars";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { useContext } from "react";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
import { slaughterGetDriverByHealthCode } from "../../services/slaughter-get-driver-by-health-code";
|
||||
import { useState } from "react";
|
||||
|
||||
export const SlaughterNewCar = ({ cars, killHouseKey }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [userExist, setUserExist] = useState(false);
|
||||
const [userData, setUserData] = useState();
|
||||
const [userKey, setUserKey] = useState();
|
||||
const [userChecked, setUserChecked] = useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
driver_name: "",
|
||||
driver_mobile: "",
|
||||
type_car: "ایسوزو",
|
||||
type_weight: "سنگین",
|
||||
capocity: "",
|
||||
health_code: "",
|
||||
pelak1: "",
|
||||
pelak2: "الف",
|
||||
pelak3: "",
|
||||
pelak4: "",
|
||||
// name: "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
driver_name: Yup.string()
|
||||
.matches(
|
||||
/^[ضصثقفغعهخخحجچشسیبلاتننمکگظطزرذدوپآژ ]+$/,
|
||||
"فقط حروف فارسی وارد کنید"
|
||||
)
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
driver_mobile: Yup.string()
|
||||
.test("len", "شماره تلفن باید با 0 شروع شود", (val, context) => {
|
||||
return context.originalValue && context.originalValue.startsWith("0");
|
||||
})
|
||||
.test("len", "شماره تماس 11 رقم باید باشد", (val, context) => {
|
||||
if (context.originalValue) {
|
||||
return context.originalValue.length === 11;
|
||||
}
|
||||
})
|
||||
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
type_weight: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
capocity: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
health_code: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
pelak1: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
pelak2: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
pelak3: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
pelak4: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
name: Yup.string().typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formik.validateForm();
|
||||
formik2.validateForm();
|
||||
}, []);
|
||||
|
||||
const formik2 = useFormik({
|
||||
initialValues: {
|
||||
health_code_check: "",
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
health_code_check: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا فیلد را به درستی وارد کنید!"),
|
||||
}),
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Grid container gap={SPACING.MEDIUM} direction="column">
|
||||
<Grid>
|
||||
<Grid container gap={SPACING.SMALL} justifyContent="left">
|
||||
{!userChecked && (
|
||||
<>
|
||||
<Typography>ثبت با کد بهداشتی</Typography>
|
||||
<Grid display="flex" width={1}>
|
||||
<TextField
|
||||
fullWidth
|
||||
id="health_code_check"
|
||||
label="کد بهداشتی"
|
||||
variant="outlined"
|
||||
value={formik2.values.health_code_check}
|
||||
error={
|
||||
formik2.touched.health_code_check
|
||||
? Boolean(formik2.errors.health_code_check)
|
||||
: null
|
||||
}
|
||||
onChange={formik2.handleChange}
|
||||
onBlur={formik2.handleBlur}
|
||||
helperText={
|
||||
formik2.touched.health_code_check &&
|
||||
Boolean(formik2.errors.health_code_check)
|
||||
? formik2.errors.health_code_check
|
||||
: null
|
||||
}
|
||||
/>
|
||||
<IconButton
|
||||
disabled={!formik2.isValid}
|
||||
aria-label="delete"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
if (formik2.values.health_code_check) {
|
||||
dispatch(LOADING_START());
|
||||
dispatch(
|
||||
slaughterGetDriverByHealthCode(
|
||||
formik2.values.health_code_check
|
||||
)
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است!",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
setUserChecked(true);
|
||||
if (r.payload.data[0]) {
|
||||
setUserData(r.payload.data[0]);
|
||||
setUserExist(true);
|
||||
setUserKey(r.payload.data[0]?.key);
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "راننده پیدا نشد!",
|
||||
severity: "error",
|
||||
});
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: false,
|
||||
bottom: false,
|
||||
content: null,
|
||||
})
|
||||
);
|
||||
setUserExist(false);
|
||||
}
|
||||
}
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SearchIcon />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
</>
|
||||
)}
|
||||
{userChecked && (
|
||||
<>
|
||||
{userExist ? (
|
||||
<>
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
direction="column"
|
||||
flex="1"
|
||||
height="100%"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid display="flex">
|
||||
<Typography
|
||||
variant="body1"
|
||||
mr={SPACING.TINY}
|
||||
color={(prop) => prop.palette.grey["A700"]}
|
||||
>
|
||||
نام راننده:
|
||||
</Typography>
|
||||
<Typography mr={SPACING.TINY} fontWeight="bold">
|
||||
{userData.driverName}
|
||||
</Typography>{" "}
|
||||
</Grid>
|
||||
|
||||
<Grid display="flex">
|
||||
<Typography
|
||||
variant="body1"
|
||||
mr={SPACING.TINY}
|
||||
color={(prop) => prop.palette.grey["A700"]}
|
||||
>
|
||||
موبایل:
|
||||
</Typography>
|
||||
<Typography mr={SPACING.TINY} fontWeight="bold">
|
||||
{userData.driverMobile}
|
||||
</Typography>
|
||||
</Grid>
|
||||
|
||||
<Grid display="flex">
|
||||
<Typography
|
||||
variant="body1"
|
||||
mr={SPACING.TINY}
|
||||
color={(prop) => prop.palette.grey["A700"]}
|
||||
>
|
||||
خودرو:
|
||||
</Typography>
|
||||
<Typography mr={SPACING.TINY} fontWeight="bold">
|
||||
{userData.typeCar}
|
||||
</Typography>{" "}
|
||||
</Grid>
|
||||
|
||||
<Grid display="flex">
|
||||
<Typography
|
||||
variant="body1"
|
||||
mr={SPACING.TINY}
|
||||
color={(prop) => prop.palette.grey["A700"]}
|
||||
>
|
||||
پلاک:
|
||||
</Typography>
|
||||
<Typography mr={SPACING.TINY} fontWeight="bold">
|
||||
{userData.pelak}
|
||||
</Typography>{" "}
|
||||
</Grid>
|
||||
|
||||
<Grid display="flex">
|
||||
<Typography
|
||||
variant="body1"
|
||||
mr={SPACING.TINY}
|
||||
color={(prop) => prop.palette.grey["A700"]}
|
||||
>
|
||||
ظرفیت:
|
||||
</Typography>
|
||||
<Typography mr={SPACING.TINY} fontWeight="bold">
|
||||
{userData.capocity}
|
||||
</Typography>{" "}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Typography>خودرو وجود ندارد!</Typography>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
fullWidth
|
||||
color="primary"
|
||||
variant="contained"
|
||||
disabled={userKey ? !formik2.isValid : !formik.isValid}
|
||||
startIcon={<SendIcon />}
|
||||
onClick={() => {
|
||||
dispatch(LOADING_START());
|
||||
if (userKey) {
|
||||
dispatch(
|
||||
slaughterNewCar({
|
||||
driver_key: userKey,
|
||||
kill_house_key: killHouseKey,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
if (r.error.message.includes("403")) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "این خودرو قبلا برای این کشتارگاه ثبت شده است!",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است!",
|
||||
severity: "error",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
dispatch(slaughterGetCars()).then((r) => {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: false,
|
||||
bottom: false,
|
||||
content: null,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
} else {
|
||||
dispatch(
|
||||
slaughterNewCar({
|
||||
driver_name: formik.values.driver_name,
|
||||
driver_mobile: formik.values.driver_mobile,
|
||||
type_car: formik.values.type_car,
|
||||
capocity: formik.values.capocity,
|
||||
weight_without_load: "0",
|
||||
health_code: formik.values.health_code,
|
||||
pelak1: formik.values.pelak1,
|
||||
pelak2: formik.values.pelak2,
|
||||
pelak3: formik.values.pelak3,
|
||||
pelak4: formik.values.pelak4,
|
||||
// name: formik.values.name,
|
||||
})
|
||||
).then((r) => {
|
||||
if (r.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "مشکلی پیش آمده است!",
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
dispatch(slaughterGetCars()).then((r) => {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: false,
|
||||
bottom: false,
|
||||
content: null,
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
ثبت اطلاعات
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,414 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import { PropTypes } from "prop-types";
|
||||
import { useSystemName } from "../../../../utils/getSystemName";
|
||||
import logo from "../../../../assets/images/logo.png";
|
||||
import { useCeoName } from "../../../../utils/getCeoName";
|
||||
|
||||
const styles = {
|
||||
page: {
|
||||
width: "210mm",
|
||||
margin: "0 auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
direction: "rtl",
|
||||
fontFamily: "nazanin",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
container: {
|
||||
width: "95%",
|
||||
alignSelf: "center",
|
||||
pageBreakInside: "avoid",
|
||||
},
|
||||
p: {
|
||||
fontFamily: "nazanin",
|
||||
fontWeight: "bold",
|
||||
pAlign: "justify",
|
||||
},
|
||||
span: {
|
||||
fontFamily: "nazanin",
|
||||
fontWeight: "bold",
|
||||
pAlign: "justify",
|
||||
},
|
||||
invoiceTable: {
|
||||
width: "100%",
|
||||
borderCollapse: "collapse",
|
||||
alignSelf: "center",
|
||||
marginBottom: "2px",
|
||||
},
|
||||
tableCell: {
|
||||
border: "1px solid #000",
|
||||
pAlign: "left",
|
||||
textAlign: "center",
|
||||
fontSize: 11,
|
||||
},
|
||||
tableCellMobile: {
|
||||
border: "1px solid #000",
|
||||
pAlign: "left",
|
||||
textAlign: "center",
|
||||
fontSize: 10,
|
||||
},
|
||||
tableInnerCell: {
|
||||
border: "1px solid #000",
|
||||
pAlign: "left",
|
||||
textAlign: "center",
|
||||
fontSize: 8,
|
||||
whiteSpace: "nowrap",
|
||||
},
|
||||
tableHeader: {
|
||||
backgroundColor: "rgba(211, 211, 211, 0.3)",
|
||||
pageBreakAfter: "auto",
|
||||
},
|
||||
headerRow: {
|
||||
backgroundColor: "rgba(211, 211, 211, 0.3)",
|
||||
color: "black",
|
||||
pageBreakInside: "avoid",
|
||||
pageBreakAfter: "auto",
|
||||
},
|
||||
logo: {
|
||||
width: "60px",
|
||||
height: "auto",
|
||||
marginBottom: "10px",
|
||||
},
|
||||
contentContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "20px",
|
||||
marginLeft: "100px",
|
||||
marginRight: "30px",
|
||||
},
|
||||
contentInLine: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
},
|
||||
mainTitle: {
|
||||
fontFamily: "nazanin",
|
||||
fontSize: 11,
|
||||
pAlign: "center",
|
||||
fontWeight: "bolder",
|
||||
},
|
||||
signature: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-end",
|
||||
marginLeft: "20px",
|
||||
},
|
||||
watermarkContainer: {
|
||||
position: "fixed",
|
||||
top: 450,
|
||||
left: 0,
|
||||
right: 30,
|
||||
bottom: 0,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
opacity: 0.2,
|
||||
zIndex: -1,
|
||||
},
|
||||
watermarkp: {
|
||||
fontSize: 100,
|
||||
fontWeight: "bolder",
|
||||
color: "grey",
|
||||
transform: "rotate(-45deg)",
|
||||
left: "50%",
|
||||
},
|
||||
title: {
|
||||
fontSize: 12,
|
||||
fontWeight: "bolder",
|
||||
pAlign: "center",
|
||||
},
|
||||
titleTopic: {
|
||||
marginTop: "10px",
|
||||
fontSize: 12,
|
||||
fontWeight: "bolder",
|
||||
pAlign: "center",
|
||||
},
|
||||
firsttitle: {
|
||||
fontSize: 14,
|
||||
fontWeight: "bolder",
|
||||
marginLeft: "40px",
|
||||
pAlign: "center",
|
||||
},
|
||||
title2: {
|
||||
fontSize: 10,
|
||||
marginBottom: 10,
|
||||
pAlign: "center",
|
||||
},
|
||||
options: {
|
||||
marginLeft: "50px",
|
||||
padding: "10px",
|
||||
marginTop: "15px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
divider: {
|
||||
width: "100%",
|
||||
height: "2px",
|
||||
backgroundColor: "red",
|
||||
marginBottom: 15,
|
||||
},
|
||||
pTitleContainer: {
|
||||
pAlign: "center",
|
||||
margin: "15px",
|
||||
textAlign: "justify",
|
||||
textJustify: "inter-word",
|
||||
},
|
||||
tableHeaderCell: {
|
||||
backgroundColor: "rgba(211, 211, 211, 0.3)",
|
||||
fontSize: 10,
|
||||
border: "1px solid #000",
|
||||
padding: "4px",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
footer: {
|
||||
pageBreakAfter: "always",
|
||||
position: "fixed",
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
width: "100%",
|
||||
},
|
||||
};
|
||||
|
||||
const SlaughterNewFactorFile = forwardRef((props, ref) => {
|
||||
const { item } = props;
|
||||
// const { date } = props;
|
||||
const systemName = useSystemName();
|
||||
const ceoName = useCeoName();
|
||||
|
||||
return (
|
||||
<div style={styles.page} ref={ref}>
|
||||
<div style={styles.contentContainer}>
|
||||
<div style={styles.contentInLine}>
|
||||
<img alt="logo" src={logo} style={styles.logo} />
|
||||
<span style={styles.mainTitle}>
|
||||
اتحادیه سراسری تعاونیهای کشاورزی پرورش دهندگان مرغ گوشتی ایران
|
||||
</span>
|
||||
<span style={styles.title}>
|
||||
اتحادیه شرکت های تعاونی کشاورزی مرغداران {" "} {systemName}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span style={styles.firsttitle}>بسمه تعالی</span>
|
||||
</div>
|
||||
|
||||
<div style={styles.options}>
|
||||
<span style={styles.title}>شماره:</span>
|
||||
<span style={styles.titleTopic}>تاریخ:</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr style={styles.divider} />
|
||||
|
||||
<strong style={{ fontSize: "20px", textAlign: "center" }}>
|
||||
فاکتور فروش
|
||||
</strong>
|
||||
<br />
|
||||
|
||||
<div style={styles.container}>
|
||||
<table
|
||||
style={{
|
||||
...styles.invoiceTable,
|
||||
marginBottom: "5px",
|
||||
}}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style={{
|
||||
...styles.tableCell,
|
||||
width: "3%",
|
||||
backgroundColor: "grey",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
writingMode: "vertical-lr",
|
||||
textOrientation: "mixed",
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
خریدار{" "}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
...styles.tableCell,
|
||||
width: "90%",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{" "}
|
||||
{
|
||||
item?.provinceCheckInfo?.killHouseAssignment?.killHouseRequest
|
||||
?.killhouseUser?.killHouseOperator?.user?.fullname
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table
|
||||
style={{
|
||||
...styles.invoiceTable,
|
||||
marginBottom: "5px",
|
||||
}}
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style={{
|
||||
...styles.tableCell,
|
||||
width: "3%",
|
||||
backgroundColor: "grey",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
writingMode: "vertical-lr",
|
||||
textOrientation: "mixed",
|
||||
fontSize: 14,
|
||||
fontWeight: "bold",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
فروشنده{" "}
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
...styles.tableCell,
|
||||
width: "90%",
|
||||
textAlign: "right",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{" "}
|
||||
اتحادیه شرکت های تعاونی کشاورزی مرغداران {" "} {systemName}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table style={styles.invoiceTable}>
|
||||
<tr>
|
||||
<table style={styles.invoiceTable}>
|
||||
<thead style={styles.tableHeader}>
|
||||
<tr style={styles.headerRow}>
|
||||
<th style={styles.tableHeaderCell}>ردیف</th>
|
||||
<th style={styles.tableHeaderCell}>شرح</th>
|
||||
<th style={styles.tableHeaderCell}>وزن (کیلوگرم)</th>
|
||||
<th style={styles.tableHeaderCell}>
|
||||
قیمت مرغ زنده (کیلوگرم)
|
||||
</th>
|
||||
<th style={styles.tableHeaderCell}>قیمت کل (ریال)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style={styles.tableCell}>1</td>
|
||||
<td style={styles.tableCell}>
|
||||
بار شماره
|
||||
{
|
||||
item?.provinceCheckInfo?.killHouseAssignment
|
||||
?.killHouseRequest?.barCode
|
||||
}
|
||||
مرغداری :{" "}
|
||||
{`${item?.poultryRequest?.poultryName} (${item?.poultryRequest?.poultryUserMobile})`}
|
||||
</td>
|
||||
<td style={styles.tableCell}>
|
||||
{item?.provinceFactorToKillHouse.netWeight?.toLocaleString()}
|
||||
</td>
|
||||
<td style={styles.tableCell}>
|
||||
{item?.factorFee?.toLocaleString() + " ﷼"}
|
||||
</td>
|
||||
<td style={styles.tableCell}>
|
||||
{item?.provinceFactorToKillHouse?.totalFactorAmount?.toLocaleString() +
|
||||
" ﷼"}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<table style={styles.invoiceTable}>
|
||||
<thead style={styles.tableHeader}>
|
||||
<tr style={styles.headerRow}>
|
||||
<th colSpan={4} style={styles.tableHeaderCell}>
|
||||
جمع فاکتور
|
||||
</th>
|
||||
<th style={styles.tableHeaderCell}>
|
||||
{item?.provinceFactorToKillHouse?.totalFactorAmount?.toLocaleString() +
|
||||
" ﷼"}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style={styles.tableCell}>
|
||||
<tr>
|
||||
<td colSpan={3}></td>
|
||||
<td style={styles.tableCell}>تخفیف</td>
|
||||
<td style={styles.tableCell}>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan={3}></td>
|
||||
<td style={styles.tableCell}>مالیات</td>
|
||||
<td style={styles.tableCell}>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colSpan={3}></td>
|
||||
<td style={styles.tableCell}>عوارض</td>
|
||||
<td style={styles.tableCell}>0</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={styles.tableCell} colSpan={3}>
|
||||
مبلغ قابل پرداخت (ریال)
|
||||
</td>
|
||||
<td colSpan={2} style={styles.tableCell}>
|
||||
{item?.provinceFactorToKillHouse?.totalFactorAmount?.toLocaleString() +
|
||||
" ﷼"}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style={{ flexDirection: "row", marginTop: "20px" }}>
|
||||
<div style={styles.signature}>
|
||||
<div style={styles.contentInLine}>
|
||||
<span style={styles.title}>{ceoName}</span>
|
||||
<span style={styles.title}>
|
||||
مدیرعامل اتحادیه مرغداران{" "}
|
||||
{systemName}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={styles.watermarkContainer}>
|
||||
<p style={styles.watermarkp}>سامانه رصدیار </p>
|
||||
</div>
|
||||
|
||||
{/* <div style={styles.footer}>
|
||||
<div style={styles.divider} />
|
||||
<p style={{ fontSize: 12, padding: "10px", marginRight: "10px" }}>
|
||||
{getAddressContent(systemName)}
|
||||
</p>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
SlaughterNewFactorFile.displayName = "SlaughterNewFactorFile";
|
||||
|
||||
export default SlaughterNewFactorFile;
|
||||
|
||||
SlaughterNewFactorFile.propTypes = {
|
||||
item: PropTypes.any,
|
||||
};
|
||||
@@ -0,0 +1,517 @@
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormHelperText,
|
||||
Grid,
|
||||
InputLabel,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import DoneIcon from "@mui/icons-material/Done";
|
||||
import { useEffect, useState, useContext } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useFormik } from "formik";
|
||||
import moment from "moment";
|
||||
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Yup } from "../../../../lib/yup/yup";
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
DRAWER,
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DialogAlert } from "../../../../components/dialog-alert/DialogAlert";
|
||||
import { NumberInput } from "../../../../components/number-format-custom/NumberFormatCustom";
|
||||
import useUserProfile from "../../../authentication/hooks/useUserProfile";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { slaughterNewRequest } from "../../services/slaughter-new-request";
|
||||
import { slaughterGetRequests } from "../../services/salughter-get-requests";
|
||||
import { slaughterGetProfile } from "../../services/slaughter-get-profile";
|
||||
import { slaughterGetKillerKillhousesService } from "../../services/slaughter-get-killers-killhouses";
|
||||
import { provinceGetPricing } from "../../../province/services/province-get-pricing";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
const TIME_RANGES = [
|
||||
"12 - 14",
|
||||
"14 - 16",
|
||||
"16 - 18",
|
||||
"18 - 20",
|
||||
"20 - 22",
|
||||
"22 - 24",
|
||||
];
|
||||
|
||||
const CHICKEN_BREEDS = [
|
||||
"آرین",
|
||||
"راس",
|
||||
"آربراکرز (آپلاس)",
|
||||
"کاب",
|
||||
"هوبارد",
|
||||
"ترکیبی",
|
||||
"وارداتی",
|
||||
];
|
||||
|
||||
const DEFAULT_INDEX_WEIGHT = 2.7;
|
||||
const PENALTY_MULTIPLIER = 1000;
|
||||
const SMS_COST = "5000 تومان";
|
||||
|
||||
const getInitialValues = (selectedSubUser) => ({
|
||||
capacity: "",
|
||||
recieveTime: "",
|
||||
selectedKillhouse: selectedSubUser?.key || "",
|
||||
selectedKillerKillhouse: "",
|
||||
race: CHICKEN_BREEDS[0],
|
||||
sellType: {
|
||||
cash: true,
|
||||
haveTime: false,
|
||||
},
|
||||
weightType: {
|
||||
under2AndHalf: false,
|
||||
over2AndHalf: false,
|
||||
},
|
||||
recieveDate: moment().format("YYYY-MM-DD hh:mm:ss"),
|
||||
isAccepted: getRoleFromUrl() === "ProvinceOperator",
|
||||
indexWeight: DEFAULT_INDEX_WEIGHT,
|
||||
});
|
||||
|
||||
const getValidationSchema = (selectedSubUser) =>
|
||||
Yup.object({
|
||||
capacity: Yup.number()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا عدد وارد کنید!"),
|
||||
selectedKillhouse: Yup.string().required("این فیلد اجباری است!"),
|
||||
selectedKillerKillhouse: selectedSubUser?.killer
|
||||
? Yup.string().required("این فیلد اجباری است!")
|
||||
: Yup.string(),
|
||||
recieveTime: Yup.string()
|
||||
.required("این فیلد اجباری است!")
|
||||
.typeError("لطفا وزن را وارد کنید!"),
|
||||
sellType: Yup.object()
|
||||
.test("sellType", "نحوه فروش را انتخاب کنید!", (val, context) => {
|
||||
return (
|
||||
context.originalValue &&
|
||||
Object.values(context.originalValue).some((item) => item === true)
|
||||
);
|
||||
})
|
||||
.required("این فیلد اجباری است!"),
|
||||
isAccepted: Yup.boolean()
|
||||
.test("req", "باید تعهد نامه را بپذیرید!", (val, context) => {
|
||||
return context.originalValue && context.originalValue === true;
|
||||
})
|
||||
.required("این فیلد اجباری است!"),
|
||||
});
|
||||
|
||||
export const SlaughterNewRequestForm = () => {
|
||||
const [openNotif, , selectedDate1, , selectedDate2] = useContext(AppContext);
|
||||
const dispatch = useDispatch();
|
||||
const [, userProfile] = useUserProfile();
|
||||
const { profile, slaughterGetKillerKillhouses } = useSelector(
|
||||
(state) => state.slaughterSlice
|
||||
);
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
|
||||
const [checkedSms, setCheckedSms] = useState(true);
|
||||
const [checkedBreedAndWeight, setCheckedBreedAndWeight] = useState(false);
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: getInitialValues(selectedSubUser),
|
||||
validationSchema: getValidationSchema(selectedSubUser),
|
||||
});
|
||||
|
||||
const penaltyPrice = formik.values.capacity * PENALTY_MULTIPLIER;
|
||||
|
||||
const dialogContent = (
|
||||
<>
|
||||
<Typography variant="body1">
|
||||
اینجانب {userProfile.fullname} موافقت خود را نسبت به موارد ذکر شده اعلام
|
||||
می نمایم.
|
||||
</Typography>
|
||||
<ListItem>
|
||||
<ListItemIcon>
|
||||
<DoneIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={`بر اساس این توافق نامه در صورت لغو کشتار ${formik.values.capacity} قطعه
|
||||
مرغ ${penaltyPrice} ریال جریمه خواهم شد.`}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(
|
||||
slaughterGetKillerKillhousesService({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(LOADING_START());
|
||||
dispatch(
|
||||
slaughterGetProfile({
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
).then(() => {
|
||||
dispatch(LOADING_END());
|
||||
});
|
||||
dispatch(provinceGetPricing());
|
||||
formik.validateForm();
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
dispatch(LOADING_START());
|
||||
const result = await dispatch(
|
||||
slaughterNewRequest({
|
||||
kill_capacity: formik.values.capacity,
|
||||
recive_time: formik.values.recieveTime,
|
||||
recive_date: formik.values.recieveDate,
|
||||
low_weight: formik.values.weightType.under2AndHalf,
|
||||
high_weight: formik.values.weightType.over2AndHalf,
|
||||
Index_weight: checkedBreedAndWeight
|
||||
? formik.values.indexWeight
|
||||
: DEFAULT_INDEX_WEIGHT,
|
||||
chicken_breed: checkedBreedAndWeight
|
||||
? formik.values.race
|
||||
: "تعیین نشده",
|
||||
cash: formik.values.sellType.cash,
|
||||
credit: formik.values.sellType.haveTime,
|
||||
sms_payment: checkedSms,
|
||||
kill_house_key: formik.values.selectedKillhouse,
|
||||
killer_kill_house_key: formik.values.selectedKillerKillhouse || null,
|
||||
role: getRoleFromUrl(),
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(LOADING_END());
|
||||
|
||||
if (result.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: result.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
slaughterGetRequests({
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
role_key: checkPathStartsWith("slaughter")
|
||||
? selectedSubUser?.key || ""
|
||||
: "",
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: result.payload.data.result,
|
||||
content: (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => dispatch(CLOSE_MODAL())}
|
||||
color="primary"
|
||||
>
|
||||
تایید
|
||||
</Button>
|
||||
),
|
||||
})
|
||||
);
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
dispatch(DRAWER({ right: false, bottom: false, content: null }));
|
||||
};
|
||||
|
||||
const isProvinceOperator = getRoleFromUrl() === "ProvinceOperator";
|
||||
|
||||
return (
|
||||
<Grid
|
||||
className="slaughter-new-request-form"
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
direction="column"
|
||||
flex="1"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Grid container direction="column" gap={SPACING.SMALL}>
|
||||
{!selectedSubUser?.key && (
|
||||
<FormControl
|
||||
fullWidth
|
||||
error={
|
||||
formik.errors.selectedKillhouse &&
|
||||
formik.touched.selectedKillhouse
|
||||
}
|
||||
>
|
||||
<InputLabel>
|
||||
{selectedSubUser?.killer ? "کشتارکن" : "محل کشتار"} را انتخاب کنید
|
||||
</InputLabel>
|
||||
<Select
|
||||
label="محل کشتار را انتخاب کنید"
|
||||
id="selectedKillhouse"
|
||||
name="selectedKillhouse"
|
||||
value={formik.values.selectedKillhouse}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
>
|
||||
{profile?.killHouse?.map((option) => (
|
||||
<MenuItem key={option.key} value={option.key}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{formik.errors.selectedKillhouse &&
|
||||
formik.touched.selectedKillhouse && (
|
||||
<FormHelperText>
|
||||
{formik.errors.selectedKillhouse}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
{selectedSubUser?.killer && (
|
||||
<FormControl
|
||||
fullWidth
|
||||
error={
|
||||
formik.errors.selectedKillerKillhouse &&
|
||||
formik.touched.selectedKillerKillhouse
|
||||
}
|
||||
>
|
||||
<InputLabel>محل کشتار را انتخاب کنید</InputLabel>
|
||||
<Select
|
||||
label="محل کشتار را انتخاب کنید"
|
||||
id="selectedKillerKillhouse"
|
||||
name="selectedKillerKillhouse"
|
||||
value={formik.values.selectedKillerKillhouse}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
>
|
||||
{slaughterGetKillerKillhouses?.map((option) => (
|
||||
<MenuItem key={option.key} value={option.key}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
{formik.errors.selectedKillerKillhouse &&
|
||||
formik.touched.selectedKillerKillhouse && (
|
||||
<FormHelperText>
|
||||
{formik.errors.selectedKillerKillhouse}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
)}
|
||||
|
||||
<Grid>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
id="capacity"
|
||||
fullWidth
|
||||
label="حجم کشتار را در روز به قطعه وارد کنید"
|
||||
variant="outlined"
|
||||
value={formik.values.capacity}
|
||||
error={
|
||||
formik.touched.capacity ? Boolean(formik.errors.capacity) : null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.capacity && Boolean(formik.errors.capacity)
|
||||
? formik.errors.capacity
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<FormControl fullWidth sx={{ minWidth: 210 }}>
|
||||
<InputLabel>بازه زمانی دریافت مرغ مرغدار</InputLabel>
|
||||
<Select
|
||||
id="recieveTime"
|
||||
value={formik.values.recieveTime}
|
||||
label="بازه زمانی دریافت مرغ مرغدار"
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("recieveTime", e.target.value);
|
||||
}}
|
||||
>
|
||||
{TIME_RANGES.map((range) => (
|
||||
<MenuItem key={range} value={range}>
|
||||
{range}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<DatePicker
|
||||
label="تاریخ کشتار"
|
||||
id="recieveDate"
|
||||
renderInput={(params) => <TextField {...params} />}
|
||||
value={formik.values.recieveDate}
|
||||
error={
|
||||
formik.touched.recieveDate
|
||||
? Boolean(formik.errors.recieveDate)
|
||||
: null
|
||||
}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue(
|
||||
"recieveDate",
|
||||
moment(e).format("YYYY-MM-DD hh:mm:ss")
|
||||
);
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.recieveDate && Boolean(formik.errors.recieveDate)
|
||||
? formik.errors.recieveDate
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={checkedBreedAndWeight}
|
||||
onChange={(e) => setCheckedBreedAndWeight(e.target.checked)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
label="تعیین نژاد/وزن مرغ"
|
||||
/>
|
||||
|
||||
{checkedBreedAndWeight && (
|
||||
<Grid container direction="column" gap={SPACING.TINY}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="race-select-label">نژاد مرغ</InputLabel>
|
||||
<Select
|
||||
labelId="race-select-label"
|
||||
id="race"
|
||||
label="نژاد مرغ"
|
||||
value={formik.values.race}
|
||||
error={formik.touched.race ? Boolean(formik.errors.race) : null}
|
||||
onChange={(e) => {
|
||||
formik.setFieldValue("race", e.target.value);
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
>
|
||||
{CHICKEN_BREEDS.map((breed) => (
|
||||
<MenuItem key={breed} value={breed}>
|
||||
{breed}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
{formik.touched.race && Boolean(formik.errors.race)
|
||||
? formik.errors.race
|
||||
: null}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
|
||||
<Grid>
|
||||
<NumberInput
|
||||
allowLeadingZeros
|
||||
thousandSeparator=","
|
||||
id="indexWeight"
|
||||
fullWidth
|
||||
label="وزن مرغ"
|
||||
variant="outlined"
|
||||
value={formik.values.indexWeight}
|
||||
error={
|
||||
formik.touched.indexWeight
|
||||
? Boolean(formik.errors.indexWeight)
|
||||
: null
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
helperText={
|
||||
formik.touched.indexWeight && Boolean(formik.errors.indexWeight)
|
||||
? formik.errors.indexWeight
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid>
|
||||
{!isProvinceOperator && (
|
||||
<DialogAlert
|
||||
title="تعهد نامه"
|
||||
content={dialogContent}
|
||||
actions={
|
||||
<Grid container justifyContent="end" gap={SPACING.TINY}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
onClick={() => formik.setFieldValue("isAccepted", false)}
|
||||
>
|
||||
رد
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
onClick={() => formik.setFieldValue("isAccepted", true)}
|
||||
>
|
||||
موافقم
|
||||
</Button>
|
||||
</Grid>
|
||||
}
|
||||
btnTitle="با تعهد نامه موافق هستم!"
|
||||
isAccepted={formik.values.isAccepted}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Grid>
|
||||
<FormControlLabel
|
||||
style={{ fontSize: "10px" }}
|
||||
control={
|
||||
<Checkbox
|
||||
checked={checkedSms}
|
||||
onChange={(e) => setCheckedSms(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Tooltip title={SMS_COST} arrow>
|
||||
<Typography variant="caption">
|
||||
مایل به دریافت پیامک اطلاع رسانی هستم!
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid container mt={SPACING.SMALL} justifyContent="center">
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
disabled={!formik.isValid}
|
||||
size="large"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
ثبت درخواست
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Typography,
|
||||
Stack,
|
||||
Divider,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { format } from "date-fns-jalali";
|
||||
|
||||
export const SlaughterRecieptBackModal = ({ handleSubmit, item }) => {
|
||||
const validationSchema = Yup.object({
|
||||
message: Yup.string().required("پیام الزامی است"),
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
message: "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
handleSubmit(values);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container gap={SPACING.SMALL} direction="column">
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
sx={{ p: 2, minWidth: 300 }}
|
||||
>
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xs={6}>
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">کدبار:</Typography>
|
||||
<Typography variant="body2">{item?.barCode || "-"}</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">تاریخ کشتار:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.poultryRequest.sendDate
|
||||
? format(
|
||||
new Date(item?.poultryRequest.sendDate),
|
||||
"yyyy/MM/dd"
|
||||
)
|
||||
: "-"}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">خریدار:</Typography>
|
||||
<Typography variant="body2">{`${item.killhouseUser?.name}(${item.killhouseUser?.killHouseOperator?.user?.mobile})`}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">مرغدار:</Typography>
|
||||
<Typography variant="body2">{`${item.poultryRequest?.poultry?.unitName}`}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2"> کد سفارش:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.poultryRequest.orderCode}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">تعداد اولیه:</Typography>
|
||||
<Typography variant="body2">
|
||||
{item.quantity?.toLocaleString()} (قطعه)
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">وزن :</Typography>
|
||||
<Typography variant="body2">
|
||||
{item?.weightInfo?.weight?.toLocaleString()} (کیلوگرم)
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Divider sx={{ mt: 1, mb: 2 }} />
|
||||
|
||||
<TextField
|
||||
name="message"
|
||||
label="پیام (اجباری)"
|
||||
multiline
|
||||
rows={4}
|
||||
value={formik.values.message}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.message && Boolean(formik.errors.message)}
|
||||
helperText={formik.touched.message && formik.errors.message}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={!formik.isValid || formik.isSubmitting}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,152 @@
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
TextField,
|
||||
FormHelperText,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Typography,
|
||||
Stack,
|
||||
Divider,
|
||||
} from "@mui/material";
|
||||
import { useFormik } from "formik";
|
||||
import * as Yup from "yup";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { format } from "date-fns-jalali";
|
||||
|
||||
export const SlaughterNoneRecieptModal = ({ handleSubmit, item }) => {
|
||||
const validationSchema = Yup.object({
|
||||
state: Yup.string().required("لطفا یک گزینه را انتخاب کنید"),
|
||||
message: Yup.string().required("پیام الزامی است"),
|
||||
});
|
||||
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
state: "accepted",
|
||||
message: "",
|
||||
},
|
||||
validationSchema,
|
||||
onSubmit: (values) => {
|
||||
handleSubmit(values);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<Grid container gap={SPACING.SMALL} direction="column">
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={formik.handleSubmit}
|
||||
sx={{ p: 2, minWidth: 300 }}
|
||||
>
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xs={6}>
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">کدبار:</Typography>
|
||||
<Typography>{item?.barCode || "-"}</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Typography variant="body2">تاریخ کشتار:</Typography>
|
||||
<Typography>
|
||||
{item?.poultryRequest.sendDate
|
||||
? format(
|
||||
new Date(item?.poultryRequest.sendDate),
|
||||
"yyyy/MM/dd"
|
||||
)
|
||||
: "-"}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={1}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">مرغدار:</Typography>
|
||||
<Typography>{`${item.poultryRequest?.poultry?.unitName}`}</Typography>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6}>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">خریدار:</Typography>
|
||||
<Typography>{`${item.killhouseUser?.name} (${item.killhouseUser?.killHouseOperator?.user?.mobile})`}</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2"> کد سفارش:</Typography>
|
||||
<Typography>{item?.poultryRequest.orderCode}</Typography>
|
||||
</Stack>
|
||||
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">تعداد اولیه:</Typography>
|
||||
<Typography>{item.quantity?.toLocaleString()} (قطعه)</Typography>
|
||||
</Stack>
|
||||
<Stack direction="row" spacing={2}>
|
||||
<Typography variant="body2">وزن :</Typography>
|
||||
<Typography>
|
||||
{item?.weightInfo?.weight?.toLocaleString()} (کیلوگرم)
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Divider sx={{ mt: 1, mb: 2 }} />
|
||||
|
||||
<FormControl
|
||||
component="fieldset"
|
||||
error={formik.touched.state && Boolean(formik.errors.state)}
|
||||
fullWidth
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
<FormLabel component="legend">وضعیت</FormLabel>
|
||||
<RadioGroup
|
||||
row
|
||||
name="state"
|
||||
value={formik.values.state}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
>
|
||||
<FormControlLabel
|
||||
value="accepted"
|
||||
control={<Radio />}
|
||||
label="تایید"
|
||||
/>
|
||||
<FormControlLabel value="rejected" control={<Radio />} label="رد" />
|
||||
</RadioGroup>
|
||||
{formik.touched.state && formik.errors.state && (
|
||||
<FormHelperText>{formik.errors.state}</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
|
||||
<TextField
|
||||
name="message"
|
||||
label="پیام (اجباری)"
|
||||
multiline
|
||||
rows={4}
|
||||
value={formik.values.message}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
error={formik.touched.message && Boolean(formik.errors.message)}
|
||||
helperText={formik.touched.message && formik.errors.message}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
sx={{ mb: 2 }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={!formik.isValid || formik.isSubmitting}
|
||||
>
|
||||
ثبت
|
||||
</Button>
|
||||
</Box>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
import { useContext, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import ReceiptLongIcon from "@mui/icons-material/ReceiptLong";
|
||||
import { CLOSE_MODAL, OPEN_MODAL } from "../../../../lib/redux/slices/appSlice";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { slaughterNoneRecieptService } from "../../services/slaughter-none-reciept-operation";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { SlaughterNoneRecieptModal } from "../slaughter-none-reciept-modal/SlaughterNoneRecieptModal";
|
||||
import RestoreIcon from "@mui/icons-material/Restore";
|
||||
import { SlaughterRecieptBackModal } from "../slaughter-none-reciept-back-modal/SlaughterRecieptBackModal";
|
||||
import { slaughterNoneBackRecieptService } from "../../services/slaughter-none-back-reciept";
|
||||
|
||||
export const SlaughterNoneRecieptOperation = ({ item, updateTable }) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
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 handleSubmit = (values) => {
|
||||
dispatch(
|
||||
slaughterNoneRecieptService({
|
||||
key: item?.key,
|
||||
role: getRoleFromUrl(),
|
||||
state: values.state,
|
||||
message: values.message,
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
handleClose();
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleBackSubmit = (values) => {
|
||||
dispatch(
|
||||
slaughterNoneBackRecieptService({
|
||||
key: item?.key,
|
||||
non_receipt: false,
|
||||
non_receipt_return: true,
|
||||
non_receipt_return_message: values.message,
|
||||
})
|
||||
).then((r) => {
|
||||
dispatch(CLOSE_MODAL());
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.error,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
handleClose();
|
||||
updateTable();
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: "عملیات با موفقیت انجام شد.",
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<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}
|
||||
>
|
||||
<Grid
|
||||
style={{ padding: "10px", width: "200px" }}
|
||||
container
|
||||
direction="column"
|
||||
alignItems="flex-start"
|
||||
>
|
||||
{["ProvinceOperator", "SuperAdmin", "AdminX"].includes(
|
||||
getRoleFromUrl()
|
||||
) && (
|
||||
<Tooltip
|
||||
title={"تایید / رد عدم وصول کشتارگاه"}
|
||||
placement="left-start"
|
||||
>
|
||||
<Button
|
||||
// variant="outlined"
|
||||
disabled={item?.nonReceiptState !== "pending"}
|
||||
size="small"
|
||||
color="primary"
|
||||
startIcon={<ReceiptLongIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "تایید / رد عدم وصول کشتارگاه",
|
||||
content: (
|
||||
<SlaughterNoneRecieptModal
|
||||
handleSubmit={handleSubmit}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" textAlign="left" fontWeight={600}>
|
||||
تایید / رد عدم وصول کشتارگاه
|
||||
</Typography>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={"برگشت عدم وصول"} placement="left-start">
|
||||
<Button
|
||||
// variant="outlined"
|
||||
disabled={item?.registrationCode}
|
||||
size="small"
|
||||
color="error"
|
||||
startIcon={<RestoreIcon fontSize="small" />}
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "برگشت عدم وصول",
|
||||
content: (
|
||||
<SlaughterRecieptBackModal
|
||||
handleSubmit={handleBackSubmit}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" textAlign="left" fontWeight={600}>
|
||||
برگشت عدم وصول
|
||||
</Typography>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Grid>
|
||||
</Popover>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { SPACING } from "../../../../data/spacing";
|
||||
import { NavLink } from "../../../../components/nav-link/NavLink";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { Button } from "@mui/material";
|
||||
import { ROUTE_SLAUGHTER_CAR_MANAGEMENT } from "../../../../routes/routes";
|
||||
|
||||
export const SlaughterOperations = () => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
gap={SPACING.SMALL}
|
||||
p={SPACING.SMALL}
|
||||
direction={{ xs: "column", md: "row" }}
|
||||
>
|
||||
{/* <NavLink
|
||||
to={ROUTE_SLAUGHTER_ADD_CAR}
|
||||
active={pathname === ROUTE_SLAUGHTER_ADD_CAR ? "true" : null}
|
||||
>
|
||||
<Button variant="text" color="inherit">
|
||||
ثبت خودرو جدید
|
||||
</Button>
|
||||
</NavLink> */}
|
||||
<NavLink
|
||||
to={ROUTE_SLAUGHTER_CAR_MANAGEMENT}
|
||||
active={pathname === ROUTE_SLAUGHTER_CAR_MANAGEMENT ? "true" : null}
|
||||
>
|
||||
<Button variant="text" color="inherit">
|
||||
مدیریت خودروها
|
||||
</Button>
|
||||
</NavLink>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,304 @@
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
TextField,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import moment from "moment";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import axios from "axios";
|
||||
import {
|
||||
LOADING_END,
|
||||
LOADING_START,
|
||||
OPEN_MODAL,
|
||||
} from "../../../../lib/redux/slices/appSlice";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import VisibilityIcon from "@mui/icons-material/Visibility";
|
||||
import { formatJustDate } from "../../../../utils/formatTime";
|
||||
import { RiSearchLine } from "react-icons/ri";
|
||||
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
|
||||
|
||||
export const SlaughterOrders = () => {
|
||||
const [selectedDate1, setSelectedDate1] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const [selectedDate2, setSelectedDate2] = useState(
|
||||
moment(new Date()).format("YYYY-MM-DD")
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const selectedSubUser = useSelector(
|
||||
(state) => state.userSlice.selectedSubUser
|
||||
);
|
||||
const handleTextChange = (event) => {
|
||||
setTextValue(event.target.value);
|
||||
};
|
||||
const [withDate, setWithDate] = useState(true);
|
||||
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 fetchApiData = useCallback(
|
||||
async (page) => {
|
||||
dispatch(LOADING_START());
|
||||
const response = await axios.get(
|
||||
`orders_for_kill_house/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&page=${page}&page_size=${perPage}`
|
||||
);
|
||||
dispatch(LOADING_END());
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
},
|
||||
[
|
||||
textValue,
|
||||
withDate,
|
||||
selectedDate1,
|
||||
selectedDate2,
|
||||
perPage,
|
||||
setData,
|
||||
setTotalRows,
|
||||
page,
|
||||
dispatch,
|
||||
selectedSubUser?.key,
|
||||
]
|
||||
);
|
||||
|
||||
const handlePageChange = (page) => {
|
||||
fetchApiData(page);
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
const handlePerRowsChange = (perRows) => {
|
||||
setPerPage(perRows);
|
||||
setPage(1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const d = data?.map((item, i) => {
|
||||
return [
|
||||
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
|
||||
item?.orderCode,
|
||||
formatJustDate(item?.date),
|
||||
item?.customerName,
|
||||
item?.customerMobile,
|
||||
item?.customerCity,
|
||||
item?.productType,
|
||||
item?.quantity?.toLocaleString(),
|
||||
item?.weight?.toLocaleString(),
|
||||
item?.status,
|
||||
item?.deliveryDate ? formatJustDate(item?.deliveryDate) : "-",
|
||||
<Tooltip title="مشاهده جزئیات" key={i}>
|
||||
<IconButton
|
||||
size={"small"}
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
dispatch(
|
||||
OPEN_MODAL({
|
||||
title: "جزئیات سفارش",
|
||||
content: (
|
||||
<Grid container gap={2}>
|
||||
<Grid xs={12}>
|
||||
<strong>کد سفارش:</strong> {item?.orderCode}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>مشتری:</strong> {item?.customerName}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>تلفن:</strong> {item?.customerMobile}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>شهر:</strong> {item?.customerCity}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>نوع محصول:</strong> {item?.productType}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>حجم:</strong> {item?.quantity?.toLocaleString()}{" "}
|
||||
قطعه
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>وزن:</strong> {item?.weight?.toLocaleString()}{" "}
|
||||
کیلوگرم
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>وضعیت:</strong> {item?.status}
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<strong>تاریخ ثبت:</strong> {formatJustDate(item?.date)}
|
||||
</Grid>
|
||||
{item?.deliveryDate && (
|
||||
<Grid xs={12}>
|
||||
<strong>تاریخ تحویل:</strong>{" "}
|
||||
{formatJustDate(item?.deliveryDate)}
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
),
|
||||
})
|
||||
);
|
||||
}}
|
||||
>
|
||||
<VisibilityIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>,
|
||||
];
|
||||
});
|
||||
|
||||
setTableData(d);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiData(1);
|
||||
}, [selectedSubUser?.key]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
dispatch(LOADING_START());
|
||||
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`orders_for_kill_house/?role=${getRoleFromUrl()}${
|
||||
checkPathStartsWith("slaughter")
|
||||
? `&role_key=${selectedSubUser?.key}`
|
||||
: ""
|
||||
}&search=filter&value=${textValue}${
|
||||
withDate ? `&date1=${selectedDate1}&date2=${selectedDate2}` : ``
|
||||
}&page=${1}&page_size=${perPage}`
|
||||
);
|
||||
setData(response.data.results);
|
||||
setTotalRows(response.data.count);
|
||||
dispatch(LOADING_END());
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
|
||||
<Grid
|
||||
container
|
||||
xs={12}
|
||||
justifyContent="start"
|
||||
alignItems="center"
|
||||
gap={2}
|
||||
>
|
||||
<Grid
|
||||
container
|
||||
style={{
|
||||
borderStyle: "solid",
|
||||
borderWidth: "1px",
|
||||
padding: "10px",
|
||||
borderRadius: "15px",
|
||||
borderColor: "gray",
|
||||
justifyContent: "left",
|
||||
}}
|
||||
>
|
||||
<Grid>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={withDate}
|
||||
onChange={() => setWithDate(!withDate)}
|
||||
color="primary"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="از تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate1}
|
||||
onChange={(e) => {
|
||||
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<DatePicker
|
||||
disabled={!withDate}
|
||||
label="تا تاریخ"
|
||||
id="date"
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
size="small"
|
||||
style={{ width: "160px" }}
|
||||
{...params}
|
||||
/>
|
||||
)}
|
||||
value={selectedDate2}
|
||||
onChange={(e) => {
|
||||
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
size="small"
|
||||
label="جستجو"
|
||||
variant="outlined"
|
||||
style={{ width: 250 }}
|
||||
onChange={handleTextChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
onClick={handleSubmit}
|
||||
endIcon={<RiSearchLine />}
|
||||
>
|
||||
جستجو
|
||||
</Button>
|
||||
</form>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ResponsiveTable
|
||||
data={tableData}
|
||||
columns={[
|
||||
"ردیف",
|
||||
"کد سفارش",
|
||||
"تاریخ ثبت",
|
||||
"نام مشتری",
|
||||
"شماره تماس",
|
||||
"شهر",
|
||||
"نوع محصول",
|
||||
"حجم (قطعه)",
|
||||
"وزن (کیلوگرم)",
|
||||
"وضعیت",
|
||||
"تاریخ تحویل",
|
||||
"عملیات",
|
||||
]}
|
||||
handlePageChange={handlePageChange}
|
||||
totalRows={totalRows}
|
||||
page={page}
|
||||
perPage={perPage}
|
||||
handlePerRowsChange={handlePerRowsChange}
|
||||
title="سفارشات کشتارگاه"
|
||||
/>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
import React from "react";
|
||||
import { SlaughterFreeBuyBars } from "../slaughter-free-buy-bars/SlaughterFreeBuyBars";
|
||||
|
||||
export const SlaughterOutProvinceBars = () => {
|
||||
return <SlaughterFreeBuyBars isBarManagemen />;
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import { Grid } from "../../../../components/grid/Grid";
|
||||
import { Button, TextField } from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { slaughterEditOutOfProvinceService } from "../../services/slaughterEditOutOfProvinceService";
|
||||
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
|
||||
import { Done } from "@mui/icons-material";
|
||||
|
||||
export const SlaughterOutProvinceRegistrationCodeInput = ({
|
||||
item,
|
||||
fetchApiData,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [registrationCode, setRegistrationCode] = useState(
|
||||
item?.loggedRegistrationCode || ""
|
||||
);
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch(
|
||||
slaughterEditOutOfProvinceService({
|
||||
key: item?.key,
|
||||
register_code: parseInt(registrationCode),
|
||||
role: getRoleFromUrl(),
|
||||
// Include all required fields from item
|
||||
date: item?.date,
|
||||
buyer_name: item?.buyerName,
|
||||
buyer_mobile: item?.buyerMobile,
|
||||
province: item?.province,
|
||||
city: item?.city,
|
||||
clearance_code: item?.clearanceCode,
|
||||
number_of_carcasses: item?.numberOfCarcasses,
|
||||
quarantine_weight_of_carcasses: item?.quarantineWeightOfCarcasses,
|
||||
weight_of_carcasses: item?.weightOfCarcasses,
|
||||
quota: item?.quota,
|
||||
sale_type: item?.saleType,
|
||||
...(item?.buyer?.key && { buyer_key: item?.buyer?.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();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="flex-start"
|
||||
gap={1}
|
||||
sx={{ position: "relative" }}
|
||||
>
|
||||
<TextField
|
||||
value={registrationCode}
|
||||
size="small"
|
||||
onChange={(e) => setRegistrationCode(e.target.value)}
|
||||
style={{ minWidth: "150px" }}
|
||||
disabled={item?.loggedRegistrationCode}
|
||||
placeholder="کد احراز"
|
||||
inputProps={{
|
||||
inputMode: "numeric",
|
||||
pattern: "[0-9]*",
|
||||
}}
|
||||
type="number"
|
||||
/>
|
||||
{!item?.loggedRegistrationCode && registrationCode && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={handleSubmit}
|
||||
sx={{
|
||||
position: "absolute",
|
||||
right: "0",
|
||||
minWidth: "40px",
|
||||
width: "40px",
|
||||
height: "38px",
|
||||
}}
|
||||
>
|
||||
<Done />
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
import {
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { AppContext } from "../../../../contexts/AppContext";
|
||||
import { DRAWER } from "../../../../lib/redux/slices/appSlice";
|
||||
import { slaughterDeleteOutOfProvinceSell } from "../../services/slaughter-delete-out-province-sell";
|
||||
import { SlaughterSubmitOutProvinceSell } from "../slaughter-submit-out-province-sell/SlaughterSubmitOutProvinceSell";
|
||||
import { fetchSlaughterBroadcastAndProducts } from "../../services/handle-fetch-slaughter-products";
|
||||
import { slaughterResendOutProvinceRegistrationCodeService } from "../../services/slaughter-resend-out-province-registration-code";
|
||||
import TuneIcon from "@mui/icons-material/Tune";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import DeleteIcon from "@mui/icons-material/Delete";
|
||||
import SendIcon from "@mui/icons-material/Send";
|
||||
|
||||
export const SlaughterOutProvinceSalesOperations = ({
|
||||
item,
|
||||
updateTable,
|
||||
fetchApiData,
|
||||
page,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [openNotif] = useContext(AppContext);
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
|
||||
const openPopover = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const closePopover = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleEdit = () => {
|
||||
closePopover();
|
||||
dispatch(
|
||||
DRAWER({
|
||||
right: !(window.innerWidth <= 600),
|
||||
bottom: window.innerWidth <= 600,
|
||||
title: "ویرایش فروش خارج از استان",
|
||||
content: (
|
||||
<SlaughterSubmitOutProvinceSell
|
||||
fetchItems={updateTable}
|
||||
isEdit={true}
|
||||
item={item}
|
||||
/>
|
||||
),
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
closePopover();
|
||||
dispatch(slaughterDeleteOutOfProvinceSell(item?.key)).then((r) => {
|
||||
if (r.payload.error) {
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.data.result,
|
||||
severity: "error",
|
||||
});
|
||||
} else {
|
||||
updateTable();
|
||||
dispatch(fetchSlaughterBroadcastAndProducts());
|
||||
openNotif({
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
msg: r.payload.data.result,
|
||||
severity: "success",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleResend = () => {
|
||||
closePopover();
|
||||
dispatch(
|
||||
slaughterResendOutProvinceRegistrationCodeService({
|
||||
key: item?.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(page);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? "popover" : undefined;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<IconButton
|
||||
aria-describedby={id}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={openPopover}
|
||||
>
|
||||
<TuneIcon />
|
||||
</IconButton>
|
||||
<Popover
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "right",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
id={id}
|
||||
open={open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={closePopover}
|
||||
>
|
||||
<List sx={{ py: 1, minWidth: 130 }}>
|
||||
<Tooltip title="ویرایش" placement="left-start">
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton onClick={handleEdit}>
|
||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
||||
<EditIcon color="primary" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="body2" color="primary">
|
||||
ویرایش
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="حذف" placement="left-start">
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton onClick={handleDelete}>
|
||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
||||
<DeleteIcon color="error" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="body2" color="error">
|
||||
حذف
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</Tooltip>
|
||||
|
||||
{item?.systemRegistrationCode &&
|
||||
item?.registrationCode &&
|
||||
!item?.loggedRegistrationCode && (
|
||||
<Tooltip title="ارسال مجدد کد" placement="left-start">
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton onClick={handleResend}>
|
||||
<ListItemIcon sx={{ minWidth: 36 }}>
|
||||
<SendIcon color="success" />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={
|
||||
<Typography variant="body2" color="success">
|
||||
ارسال مجدد کد
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
</Tooltip>
|
||||
)}
|
||||
</List>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user