2026-01-27 18:27:29 +05:30
|
|
|
import React, {
|
|
|
|
|
useEffect,
|
|
|
|
|
useState,
|
|
|
|
|
useRef,
|
|
|
|
|
useContext,
|
|
|
|
|
useCallback,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "react";
|
|
|
|
|
import { useDispatch, useSelector } from "react-redux";
|
|
|
|
|
import { Select, Tooltip } from "antd";
|
|
|
|
|
import { Form, Input, Table } from "antd";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
EditFilled,
|
|
|
|
|
DeleteFilled,
|
|
|
|
|
ArrowRightOutlined,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "@ant-design/icons";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
PutStockPrice,
|
|
|
|
|
bulkPriceUpdate,
|
|
|
|
|
getStockNames,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Features/StockPriceUpdate/StockPriceUpdateMaster";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
dateFormatChange,
|
|
|
|
|
ExtractDateFormate,
|
|
|
|
|
getSession,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Services/Others";
|
|
|
|
|
import { DefaultModal } from "../../Components/Modal/DefaultModal";
|
|
|
|
|
import { Tables } from "../../Components/Tables/Table";
|
|
|
|
|
import Buttons from "../../Components/Forms/Buttons";
|
|
|
|
|
import { Messages } from "../../Components/Notifications/Messages";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
changeBreadCrumb,
|
|
|
|
|
getEmpAccess,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Features/AppPage/CenterPage.js";
|
|
|
|
|
import FormHeader from "../PageComponents/FormHeader";
|
|
|
|
|
import Search from "../../Components/Forms/Search";
|
|
|
|
|
import { RadioGrpButton } from "../../Components/Forms/RadioGroup.jsx";
|
|
|
|
|
import { useAuth } from "../../AuthContext.jsx";
|
|
|
|
|
import "../../Styles/OverAllStyle/OverAllStyle.scss";
|
|
|
|
|
import { getPreferenceData } from "../../Features/BookingScreen/BookingData/BookingData.js";
|
|
|
|
|
import { DropDowns } from "../../Components/Forms/DropDown.jsx";
|
|
|
|
|
import { FiDelete, FiUploadCloud } from "react-icons/fi";
|
|
|
|
|
import { CiExport } from "react-icons/ci";
|
|
|
|
|
import Excelupldimg from "../../Images/Excel.png";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
emptyExcelData,
|
|
|
|
|
fileInputRefSelector,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Features/ExcelUploadPage/ExcelUploadPage.js";
|
2026-01-27 18:27:29 +05:30
|
|
|
const subDirectory = import.meta.env.BASE_URL;
|
2026-01-28 15:59:11 +05:30
|
|
|
import ExcelJS from "exceljs";
|
|
|
|
|
import { read, utils } from "xlsx";
|
|
|
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
|
import { InputField } from "../../Components/Forms/InputField.jsx";
|
|
|
|
|
import { MdOutlineAppRegistration } from "react-icons/md";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
getFieldSetupData,
|
|
|
|
|
postFieldSetup,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Features/ProductPage/ProductPage.js";
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
ApplicationPreferences,
|
|
|
|
|
getCommonAppPreference,
|
2026-01-28 15:59:11 +05:30
|
|
|
} from "../../Features/BrachLogin/BranchLogin.js";
|
|
|
|
|
import { IoClose } from "react-icons/io5";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const StockPriceUpdate = () => {
|
|
|
|
|
const { SadminuserAccess } = useAuth();
|
|
|
|
|
let SAAccessCommonMaster = SadminuserAccess?.find(
|
2026-01-28 15:59:11 +05:30
|
|
|
(e) => e?.MenuName === "Price Change",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
|
|
|
|
|
const categoryId = ApplicationPreferenceData?.find(
|
2026-01-28 15:59:11 +05:30
|
|
|
(p) => p?.PreferredCatName?.toLowerCase() === "price change fields",
|
|
|
|
|
)?.PreferredCatId;
|
|
|
|
|
|
|
|
|
|
const excelCategoryId = ApplicationPreferenceData?.find(
|
|
|
|
|
(p) => p?.PreferredCatName?.toLowerCase() === "price change sheet fields",
|
2026-01-27 18:27:29 +05:30
|
|
|
)?.PreferredCatId;
|
|
|
|
|
|
|
|
|
|
const fileInputRef = useRef(fileInputRefSelector);
|
|
|
|
|
const excelDataRef = useRef(null);
|
|
|
|
|
const formRef = useRef(null);
|
|
|
|
|
|
|
|
|
|
const allowedExcelTypes = [
|
2026-01-28 15:59:11 +05:30
|
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xlsx
|
|
|
|
|
"application/vnd.ms-excel", // .xls
|
2026-01-27 18:27:29 +05:30
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const [selectedFields, setSelectedFields] = useState([]);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [selectedExcelFields, setSelectedExcelFields] = useState([]);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [tableExcelFieldPreferences, setTableExcelFieldPreferences] = useState(
|
|
|
|
|
[],
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [messageType, setMessageType] = useState(null);
|
|
|
|
|
const [messageData, setMessageData] = useState(null);
|
|
|
|
|
const [StockNames, setStockNames] = useState([]);
|
|
|
|
|
const [ProductName, setProductName] = useState(null);
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const [fieldSetup, setFieldSetup] = useState(false);
|
|
|
|
|
const [excelFieldSetup, setExcelFieldSetup] = useState(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [StockDetails, setStockDetails] = useState([]);
|
|
|
|
|
const [dataSource, setDataSource] = useState([]);
|
|
|
|
|
const [sortedInfo, setSortedInfo] = useState({});
|
|
|
|
|
const [BulksortedInfo, setBulksortedInfo] = useState({});
|
2026-01-28 15:59:11 +05:30
|
|
|
const [searchedText, setSearchedText] = useState("");
|
|
|
|
|
const [BulksearchedText, setBulksearchedText] = useState("");
|
2026-01-27 18:27:29 +05:30
|
|
|
const [filteredInfo, setFilteredInfo] = useState({});
|
|
|
|
|
const [page, setpage] = useState(1);
|
|
|
|
|
const [Bulkchangepage, setBulkchangepage] = useState(1);
|
|
|
|
|
|
|
|
|
|
const [pageSize, setPageSize] = useState(10);
|
|
|
|
|
const [openEditModal, setOpenEditModal] = useState(false);
|
|
|
|
|
const [open, setOpen] = useState(false);
|
|
|
|
|
const [excelModalOpen, setExcelModalOpen] = useState(false);
|
|
|
|
|
const [priceChangeModalOpen, setPriceChangeModalOpen] = useState(false);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [stockVariantBased, setStockVariantBased] = useState("Yes");
|
2026-01-27 18:27:29 +05:30
|
|
|
const [exportLoading, setExportLoading] = useState(false);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [fileLoading, setFileLoading] = useState(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [loading, setLoading] = useState(false);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [headers, setHeaders] = useState([]);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [uploadedData, setUploadedData] = useState([]);
|
2026-01-28 15:59:11 +05:30
|
|
|
const CompId = getSession("CompId");
|
|
|
|
|
const BranchId = getSession("BranchId");
|
|
|
|
|
const AppId = getSession("AppId");
|
|
|
|
|
const UserId = getSession("UserId");
|
|
|
|
|
const UserType = getSession("UserType");
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const [empData, setEmpData] = useState();
|
|
|
|
|
const [addnewAccess, setaddnewAccess] = useState(true);
|
2026-01-28 15:59:11 +05:30
|
|
|
const [RadioSelection, setRadioSelection] = useState("Single");
|
2026-01-27 18:27:29 +05:30
|
|
|
const [BulkProductData, setBulkProductData] = useState([]);
|
|
|
|
|
const [allowDecimal, setAllowDecimal] = useState(false);
|
2026-01-28 15:59:11 +05:30
|
|
|
const hasFieldExists = (label) =>
|
|
|
|
|
headers.some((h) => h.toLowerCase() === label.toLowerCase());
|
|
|
|
|
const hasField = (label) =>
|
|
|
|
|
tableFieldPreferences?.some((f) => f.label === label && f.access === "Y");
|
|
|
|
|
const hasExcelField = (label) =>
|
|
|
|
|
tableExcelFieldPreferences?.some(
|
|
|
|
|
(f) => f.label === label && f.access === "Y",
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const items = [
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
name: "Home",
|
2026-01-27 18:27:29 +05:30
|
|
|
link: `${subDirectory}app-page/home`,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const handleRemoveRecord = (index) => {
|
|
|
|
|
setUploadedData((prev) => prev.filter((_, i) => i !== index));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const columns = [
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Product Name",
|
|
|
|
|
dataIndex: "ProductName",
|
|
|
|
|
key: "ProductName",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 180,
|
|
|
|
|
render: (value, record, index) => (
|
|
|
|
|
<p>{`${value} (${record?.Size} ${record?.UOMName})`}</p>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Variant Name",
|
|
|
|
|
dataIndex: "VariantName",
|
|
|
|
|
key: "VariantName",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 180,
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Batch No",
|
|
|
|
|
dataIndex: "BatchRef",
|
|
|
|
|
key: "BatchRef",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 180,
|
|
|
|
|
},
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasFieldExists("Stock")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Stock",
|
|
|
|
|
dataIndex: "Stock",
|
|
|
|
|
key: "Stock",
|
|
|
|
|
width: 80,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasFieldExists("Stock Date")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Stock Date",
|
|
|
|
|
dataIndex: "StockDate",
|
|
|
|
|
key: "StockDate",
|
|
|
|
|
width: 80,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasFieldExists("Old MRP")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old MRP",
|
|
|
|
|
dataIndex: "OldMRP",
|
|
|
|
|
key: "OldMRP",
|
|
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasFieldExists("Old SP")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old SP",
|
|
|
|
|
dataIndex: "OldSP",
|
|
|
|
|
key: "OldSP",
|
|
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasFieldExists("Old Wholesale Price")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old Wholesale Price",
|
|
|
|
|
dataIndex: "OldWholeSalePrice",
|
|
|
|
|
key: "OldWholeSalePrice",
|
|
|
|
|
width: 140,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
// ✅ EDITABLE
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New MRP",
|
|
|
|
|
dataIndex: "NewMRP",
|
|
|
|
|
key: "NewMRP",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 120,
|
|
|
|
|
render: (_, record, index) => (
|
|
|
|
|
<Form.Item name={`NewMRP${record.localId}`}>
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="New MRP"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onChange={(e) =>
|
2026-01-28 15:59:11 +05:30
|
|
|
handlePriceChange(index, "NewMRP", e.target.value, record.localId)
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
onInput={(e) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, "");
|
|
|
|
|
if (cleanedValue.startsWith(".")) {
|
|
|
|
|
cleanedValue = "0" + cleanedValue;
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
2026-01-28 15:59:11 +05:30
|
|
|
const parts = cleanedValue.split(".");
|
2026-01-27 18:27:29 +05:30
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
2026-01-28 15:59:11 +05:30
|
|
|
? `${parts[0]}.${parts.slice(1).join("")}`
|
2026-01-27 18:27:29 +05:30
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New SP",
|
|
|
|
|
dataIndex: "NewSellPrice",
|
|
|
|
|
key: "NewSellPrice",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 120,
|
|
|
|
|
render: (_, record, index) => (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={`NewSellPrice${record.localId}`}
|
2026-01-28 15:59:11 +05:30
|
|
|
validateTrigger={["onChange", "onBlur"]}
|
2026-01-27 18:27:29 +05:30
|
|
|
rules={[
|
|
|
|
|
({ getFieldValue }) => ({
|
|
|
|
|
validator(_, value) {
|
|
|
|
|
const mrp = getFieldValue(`NewMRP${record.localId}`);
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
if (mrp === undefined || mrp === null || mrp === "") {
|
2026-01-27 18:27:29 +05:30
|
|
|
return Promise.resolve();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const numMRP = Number(mrp);
|
|
|
|
|
const numSP =
|
2026-01-28 15:59:11 +05:30
|
|
|
value === undefined || value === null || value === ""
|
2026-01-27 18:27:29 +05:30
|
|
|
? null
|
|
|
|
|
: Number(value);
|
|
|
|
|
|
|
|
|
|
if (numSP === null) {
|
|
|
|
|
return Promise.reject(
|
2026-01-28 15:59:11 +05:30
|
|
|
new Error("New SP is required when New MRP is provided"),
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (numSP > numMRP) {
|
|
|
|
|
return Promise.reject(
|
2026-01-28 15:59:11 +05:30
|
|
|
new Error("New SP cannot be greater than New MRP"),
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
placeholder="New SP"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, "");
|
|
|
|
|
const parts = cleanedValue.split(".");
|
|
|
|
|
if (cleanedValue.startsWith(".")) {
|
|
|
|
|
cleanedValue = "0" + cleanedValue;
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
2026-01-28 15:59:11 +05:30
|
|
|
? `${parts[0]}.${parts.slice(1).join("")}`
|
2026-01-27 18:27:29 +05:30
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
{
|
|
|
|
|
handlePriceChange(
|
|
|
|
|
index,
|
2026-01-28 15:59:11 +05:30
|
|
|
"NewSellPrice",
|
2026-01-27 18:27:29 +05:30
|
|
|
e.target.value,
|
2026-01-28 15:59:11 +05:30
|
|
|
record.localId,
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
excelDataRef.current
|
|
|
|
|
?.validateFields([`NewSellPrice${record.localId}`])
|
2026-01-28 15:59:11 +05:30
|
|
|
.catch(() => { });
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
),
|
|
|
|
|
},
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasFieldExists("New Wholesale Price")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "New Wholesale Price",
|
|
|
|
|
dataIndex: "NewWholeSalePrice",
|
|
|
|
|
key: "NewWholeSalePrice",
|
|
|
|
|
width: 160,
|
|
|
|
|
render: (value, record, index) => (
|
|
|
|
|
<Form.Item name={`NewWholeSalePrice${record?.localId}`}>
|
|
|
|
|
<Input
|
|
|
|
|
onChange={(e) =>
|
|
|
|
|
handlePriceChange(
|
|
|
|
|
index,
|
|
|
|
|
"NewWholeSalePrice",
|
|
|
|
|
e.target.value,
|
|
|
|
|
record.localId,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
placeholder="New Wholesale"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
|
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, "");
|
|
|
|
|
const parts = cleanedValue.split(".");
|
|
|
|
|
if (cleanedValue.startsWith(".")) {
|
|
|
|
|
cleanedValue = "0" + cleanedValue;
|
|
|
|
|
}
|
|
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
|
|
|
|
? `${parts[0]}.${parts.slice(1).join("")}`
|
|
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
2026-01-27 18:27:29 +05:30
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Action",
|
|
|
|
|
key: "action",
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 80,
|
2026-01-28 15:59:11 +05:30
|
|
|
align: "center",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (_, record, index) => (
|
|
|
|
|
<DeleteFilled
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
color: "#EF4443",
|
|
|
|
|
cursor: "pointer",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
onClick={() => handleRemoveRecord(index)}
|
|
|
|
|
/>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
|
|
|
getPreference();
|
|
|
|
|
// if (UserType === "Employee") {
|
|
|
|
|
// fetchApi()
|
|
|
|
|
// }
|
|
|
|
|
}, []);
|
|
|
|
|
useEffect(() => {
|
2026-01-28 15:59:11 +05:30
|
|
|
dispatch(getCommonAppPreference(AppId));
|
|
|
|
|
}, [AppId, dispatch]);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (UserType === "Employee") {
|
2026-01-27 18:27:29 +05:30
|
|
|
fetchApi();
|
|
|
|
|
}
|
|
|
|
|
}, [UserType]);
|
2026-01-28 15:59:11 +05:30
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getFieldSetup();
|
|
|
|
|
}, [categoryId]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getExcelFieldSetup();
|
|
|
|
|
}, [excelCategoryId]);
|
|
|
|
|
|
|
|
|
|
const getFieldSetup = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await dispatch(
|
|
|
|
|
getFieldSetupData({ AppId, CompId, BranchId, categoryId, Type: "GB" }),
|
|
|
|
|
).unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
console.log(response?.data?.data?.[0]?.ConfigDtl, "Field Setup Data");
|
|
|
|
|
setSelectedFields(
|
|
|
|
|
response?.data?.data?.[0]?.ConfigDtl?.filter(
|
|
|
|
|
(c) => c.ConfigId && c.Access === "Y",
|
|
|
|
|
)?.map((c) => c.ConfigId) || [],
|
|
|
|
|
);
|
|
|
|
|
setTableFieldPreferences(
|
|
|
|
|
response?.data?.data?.[0]?.ConfigDtl?.map((c) => ({
|
|
|
|
|
value: c.ConfigId,
|
|
|
|
|
label: c.ConfigName,
|
|
|
|
|
access: c.Access,
|
|
|
|
|
})) || [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error fetching field setup:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getExcelFieldSetup = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const response = await dispatch(
|
|
|
|
|
getFieldSetupData({
|
|
|
|
|
AppId,
|
|
|
|
|
CompId,
|
|
|
|
|
BranchId,
|
|
|
|
|
categoryId: excelCategoryId,
|
|
|
|
|
Type: "GB",
|
|
|
|
|
}),
|
|
|
|
|
).unwrap();
|
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
console.log(response?.data?.data?.[0]?.ConfigDtl, "Field Setup Data");
|
|
|
|
|
setSelectedExcelFields(
|
|
|
|
|
response?.data?.data?.[0]?.ConfigDtl?.filter(
|
|
|
|
|
(c) => c.ConfigId && c.Access === "Y",
|
|
|
|
|
)?.map((c) => c.ConfigId) || [],
|
|
|
|
|
);
|
|
|
|
|
setTableExcelFieldPreferences(
|
|
|
|
|
response?.data?.data?.[0]?.ConfigDtl?.map((c) => ({
|
|
|
|
|
value: c.ConfigId,
|
|
|
|
|
label: c.ConfigName,
|
|
|
|
|
access: c.Access,
|
|
|
|
|
})) || [],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Error fetching field setup:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
useEffect(() => {
|
|
|
|
|
let hasAccess = false;
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
if (UserType === "Admin" || UserType === "Super Admin") {
|
2026-01-27 18:27:29 +05:30
|
|
|
hasAccess = true;
|
2026-01-28 15:59:11 +05:30
|
|
|
} else if (UserType === "Employee") {
|
|
|
|
|
hasAccess = empData?.AddAccess === "Y";
|
|
|
|
|
} else if (UserType === "Super Admin User") {
|
|
|
|
|
hasAccess = SAAccessCommonMaster?.AddAccess === "Y";
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setaddnewAccess(!hasAccess);
|
|
|
|
|
}, [empData, SAAccessCommonMaster, UserType]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (uploadedData?.length) {
|
|
|
|
|
setFormValuesFromExtractedData(uploadedData);
|
|
|
|
|
} else {
|
|
|
|
|
excelDataRef?.current?.resetFields();
|
|
|
|
|
}
|
|
|
|
|
}, [uploadedData]);
|
|
|
|
|
|
|
|
|
|
const fetchApi = async () => {
|
|
|
|
|
let data = {
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
EmpId: UserId,
|
|
|
|
|
};
|
|
|
|
|
let response = await dispatch(getEmpAccess(data)).unwrap();
|
|
|
|
|
let datas = response?.data?.data?.[0]?.EmpAccessDetails?.filter(
|
2026-01-28 15:59:11 +05:30
|
|
|
(item) => item.ConfigName === "Price Change",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
setEmpData(datas?.[0]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const EditableContext = React.createContext(null);
|
|
|
|
|
const EditableRow = ({ index, ...props }) => {
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
return (
|
|
|
|
|
<Form form={form} component={false}>
|
|
|
|
|
<EditableContext.Provider value={form}>
|
|
|
|
|
<tr {...props} />
|
|
|
|
|
</EditableContext.Provider>
|
|
|
|
|
</Form>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
const BulkEditableRow = ({ index, ...props }) => {
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
return (
|
|
|
|
|
<Form form={form} component={false}>
|
|
|
|
|
<EditableContext.Provider value={form}>
|
|
|
|
|
<tr {...props} />
|
|
|
|
|
</EditableContext.Provider>
|
|
|
|
|
</Form>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const EditableCell = ({
|
|
|
|
|
title,
|
|
|
|
|
editable,
|
|
|
|
|
children,
|
|
|
|
|
dataIndex,
|
|
|
|
|
record,
|
|
|
|
|
handleSave,
|
|
|
|
|
...restProps
|
|
|
|
|
}) => {
|
|
|
|
|
const [editing, setEditing] = useState(false);
|
|
|
|
|
const inputRef = useRef(null);
|
|
|
|
|
const form = useContext(EditableContext);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (editing) {
|
|
|
|
|
inputRef?.current?.focus();
|
|
|
|
|
}
|
|
|
|
|
}, [editing]);
|
|
|
|
|
|
|
|
|
|
const toggleEdit = () => {
|
|
|
|
|
setEditing(!editing);
|
|
|
|
|
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
[dataIndex]: record[dataIndex],
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const save = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const values = await form.validateFields();
|
|
|
|
|
toggleEdit();
|
|
|
|
|
handleSave({
|
|
|
|
|
...record,
|
|
|
|
|
...values,
|
|
|
|
|
});
|
|
|
|
|
} catch (errInfo) {
|
2026-01-28 15:59:11 +05:30
|
|
|
console.log("Save failed:", errInfo);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let childNode = children;
|
|
|
|
|
|
|
|
|
|
if (editable) {
|
|
|
|
|
childNode = editing ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
style={{
|
|
|
|
|
margin: 0,
|
|
|
|
|
}}
|
|
|
|
|
name={dataIndex}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
pattern: /^(?!0$)(\d+)(\.\d{1,2})?$/,
|
2026-01-28 15:59:11 +05:30
|
|
|
message: "Invalid format (Max 2 decimals, No zero)",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
validator: (_, value) =>
|
|
|
|
|
value?.length > 10
|
2026-01-28 15:59:11 +05:30
|
|
|
? Promise.reject("Max 10 characters allowed")
|
2026-01-27 18:27:29 +05:30
|
|
|
: Promise.resolve(),
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
className="editable-table-input"
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
onPressEnter={save}
|
|
|
|
|
onBlur={save}
|
|
|
|
|
// onMouseLeave={save}
|
|
|
|
|
value={
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
}
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
const cleanedValue = e.target.value.replace(/[^0-9.]/g, "");
|
|
|
|
|
const parts = cleanedValue.split(".");
|
2026-01-27 18:27:29 +05:30
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
2026-01-28 15:59:11 +05:30
|
|
|
? `${parts[0]}.${parts.slice(1).join("")}`
|
2026-01-27 18:27:29 +05:30
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="editable-cell-value-wrap" onClick={toggleEdit}>
|
|
|
|
|
{/* {dataIndex === 'CurrentAmt' && Array.isArray(record[dataIndex])
|
|
|
|
|
? record[dataIndex]?.map((item, index) => (
|
|
|
|
|
<span key={index}>
|
|
|
|
|
{item.CurrentAmt + '-' + item.CurrentAmt}
|
|
|
|
|
</span>
|
|
|
|
|
))
|
|
|
|
|
: children} */}
|
|
|
|
|
|
|
|
|
|
<Input
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
className="editable-table-input"
|
|
|
|
|
onPressEnter={save}
|
|
|
|
|
onBlur={save}
|
|
|
|
|
value={
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return <td {...restProps}>{childNode}</td>;
|
|
|
|
|
};
|
|
|
|
|
const BulkEditableCell = ({
|
|
|
|
|
title,
|
|
|
|
|
editable,
|
|
|
|
|
children,
|
|
|
|
|
dataIndex,
|
|
|
|
|
record,
|
|
|
|
|
handleSave,
|
|
|
|
|
...restProps
|
|
|
|
|
}) => {
|
|
|
|
|
const [editing, setEditing] = useState(false);
|
|
|
|
|
const inputRef = useRef(null);
|
|
|
|
|
const form = useContext(EditableContext);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (editing) {
|
|
|
|
|
inputRef?.current?.focus();
|
|
|
|
|
}
|
|
|
|
|
}, [editing]);
|
|
|
|
|
|
|
|
|
|
const toggleEdit = () => {
|
|
|
|
|
setEditing(!editing);
|
|
|
|
|
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
[dataIndex]: record[dataIndex],
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Bulksave = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const values = await form.validateFields();
|
|
|
|
|
toggleEdit();
|
|
|
|
|
handleBulkSave({
|
|
|
|
|
...record,
|
|
|
|
|
...values,
|
|
|
|
|
});
|
|
|
|
|
} catch (errInfo) {
|
2026-01-28 15:59:11 +05:30
|
|
|
console.log("Save failed:", errInfo);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let childNode = children;
|
|
|
|
|
|
|
|
|
|
if (editable) {
|
|
|
|
|
childNode = editing ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
style={{
|
|
|
|
|
margin: 0,
|
|
|
|
|
}}
|
|
|
|
|
name={dataIndex}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
pattern: /^(?!0$)(\d+)(\.\d{1,2})?$/,
|
2026-01-28 15:59:11 +05:30
|
|
|
message: "Invalid format (Max 2 decimals, No zero)",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
validator: (_, value) =>
|
|
|
|
|
value?.length > 10
|
2026-01-28 15:59:11 +05:30
|
|
|
? Promise.reject("Max 10 characters allowed")
|
2026-01-27 18:27:29 +05:30
|
|
|
: Promise.resolve(),
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
onPressEnter={Bulksave}
|
|
|
|
|
onBlur={Bulksave}
|
|
|
|
|
// onMouseLeave={Bulksave}
|
|
|
|
|
value={
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
}
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
const cleanedValue = e.target.value.replace(/[^0-9.]/g, "");
|
|
|
|
|
const parts = cleanedValue.split(".");
|
2026-01-27 18:27:29 +05:30
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
2026-01-28 15:59:11 +05:30
|
|
|
? `${parts[0]}.${parts.slice(1).join("")}`
|
2026-01-27 18:27:29 +05:30
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="editable-cell-value-wrap" onClick={toggleEdit}>
|
|
|
|
|
{/* {dataIndex === "CurrentAmt" && Array.isArray(record[dataIndex])
|
|
|
|
|
? record[dataIndex]?.map((item, index) => (
|
|
|
|
|
<span key={index}>
|
|
|
|
|
{item.CurrentAmt + "-" + item.CurrentAmt}
|
|
|
|
|
</span>
|
|
|
|
|
))
|
|
|
|
|
: children} */}
|
|
|
|
|
<Input
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
onPressEnter={Bulksave}
|
|
|
|
|
onBlur={Bulksave}
|
|
|
|
|
value={
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return <td {...restProps}>{childNode}</td>;
|
|
|
|
|
};
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
fetchData();
|
|
|
|
|
}, []);
|
|
|
|
|
const getPreference = async () => {
|
|
|
|
|
const data = { AppId: AppId, CompId: CompId, BranchId: BranchId };
|
|
|
|
|
const { data: res } = await dispatch(getPreferenceData(data)).unwrap();
|
|
|
|
|
const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find(
|
|
|
|
|
(setting) =>
|
2026-01-28 15:59:11 +05:30
|
|
|
setting?.SettingIdName?.toLowerCase() === "decimal" &&
|
|
|
|
|
setting?.SettingValue === "Y",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
if (decimalSetting) {
|
|
|
|
|
setAllowDecimal(true);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const fetchData = async () => {
|
|
|
|
|
let data = {
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let res = await dispatch(getStockNames(data)).unwrap();
|
|
|
|
|
const stockNamesWithKeys = res?.data?.data?.map((stockName) => ({
|
|
|
|
|
...stockName,
|
|
|
|
|
stockDetails: stockName?.stockDetails?.map((item, index) => ({
|
|
|
|
|
...item,
|
|
|
|
|
key: `${stockName.ProdId}_${index}`,
|
|
|
|
|
})),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
setStockNames(stockNamesWithKeys);
|
|
|
|
|
const flattenedArray = res?.data?.data?.flatMap((product) =>
|
|
|
|
|
product.stockDetails.map((detail) => ({
|
|
|
|
|
ProdName: product.ProdName,
|
|
|
|
|
InwardDtlId: detail.InwardDtlId,
|
|
|
|
|
InwardDate: detail.InwardDate,
|
|
|
|
|
ExpDate: detail.ExpDate,
|
|
|
|
|
BalanceQty: detail.BalanceQty,
|
|
|
|
|
MRP: detail.MRP,
|
|
|
|
|
SellPrice: detail.SellPrice,
|
|
|
|
|
ProdId: product.ProdId,
|
|
|
|
|
Size: product.Size,
|
|
|
|
|
StockAvailable: product.StockAvailable,
|
|
|
|
|
CompId: product.CompId,
|
|
|
|
|
BranchId: product.BranchId,
|
|
|
|
|
AppId: product.AppId,
|
|
|
|
|
UOM: product.UOM,
|
|
|
|
|
UOMName: product.UOMName,
|
|
|
|
|
WhSalePrice: detail?.WhSalePrice,
|
|
|
|
|
ProdVariantName: detail?.ProdVariantName,
|
|
|
|
|
BatchRef: detail?.BatchRef,
|
|
|
|
|
key: `${product.ProdId}_${detail.InwardDtlId}`,
|
2026-01-28 15:59:11 +05:30
|
|
|
})),
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
setBulkProductData(flattenedArray);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const actionsFormatter = async (row) => {
|
|
|
|
|
setOpenEditModal(true);
|
|
|
|
|
setDataSource([row]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePriceChange = (rowIndex, field, value, localId) => {
|
|
|
|
|
const numValue = value ? parseFloat(value) : null;
|
|
|
|
|
|
|
|
|
|
setUploadedData((prev) => {
|
|
|
|
|
const updated = [...prev];
|
|
|
|
|
const currentRow = { ...updated[rowIndex] };
|
|
|
|
|
|
|
|
|
|
// If changing New MRP, clear New SP
|
2026-01-28 15:59:11 +05:30
|
|
|
if (field === "NewMRP") {
|
2026-01-27 18:27:29 +05:30
|
|
|
currentRow.NewSellPrice = null;
|
|
|
|
|
excelDataRef.current?.setFieldsValue({
|
|
|
|
|
[`NewSellPrice${localId}`]: null,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentRow[field] = numValue;
|
|
|
|
|
updated[rowIndex] = currentRow;
|
|
|
|
|
return updated;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Validate New SP against New MRP
|
2026-01-28 15:59:11 +05:30
|
|
|
if (field === "NewSellPrice" && numValue) {
|
2026-01-27 18:27:29 +05:30
|
|
|
const currentRow = uploadedData[rowIndex];
|
|
|
|
|
const newMRP = currentRow?.NewMRP;
|
|
|
|
|
|
|
|
|
|
if (newMRP && numValue > newMRP) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("New SP cannot be greater than New MRP");
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
excelDataRef.current?.setFieldsValue({
|
|
|
|
|
[`${field}${localId}`]: numValue,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const statusFormatter = async (row) => {
|
|
|
|
|
const updatedData = StockDetails?.filter(
|
2026-01-28 15:59:11 +05:30
|
|
|
(item) => item?.InwardDtlId !== row?.InwardDtlId,
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
setStockDetails(updatedData);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let tableValue = StockNames?.[0]?.stockDetails;
|
|
|
|
|
let DataSource = StockNames?.map((name, index) => ({
|
|
|
|
|
value: index + 1,
|
2026-01-28 15:59:11 +05:30
|
|
|
label: name?.ProdName + "(" + (name?.Size + " " + name?.UOMName) + ")",
|
2026-01-27 18:27:29 +05:30
|
|
|
ProdId: name?.ProdId,
|
|
|
|
|
stockDetails: name?.stockDetails,
|
|
|
|
|
Quantity: name?.Size,
|
|
|
|
|
QuantityName: name?.UOMName,
|
|
|
|
|
ExpDate: name.stockDetails?.[0]?.ExpDate,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
setDataSource(tableValue);
|
|
|
|
|
}, [tableValue]);
|
|
|
|
|
|
|
|
|
|
const handleSave = (row) => {
|
|
|
|
|
if (row?.CurrentAmt && row?.CurrentMRP) {
|
|
|
|
|
if (parseFloat(row?.CurrentMRP) >= parseFloat(row?.CurrentAmt)) {
|
|
|
|
|
const newData = StockDetails?.map((item) => {
|
|
|
|
|
return item.key === row.key ? { ...item, ...row } : item;
|
|
|
|
|
});
|
|
|
|
|
const index = newData?.findIndex((item) => row.key === item.key);
|
|
|
|
|
const item = newData[index];
|
|
|
|
|
newData?.splice(index, 1, {
|
|
|
|
|
...item,
|
|
|
|
|
...row,
|
|
|
|
|
});
|
|
|
|
|
setStockDetails(newData);
|
|
|
|
|
} else {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("MRP is must be greater than or equal to selling price");
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const newData = StockDetails?.map((item) => {
|
|
|
|
|
return item.key === row.key ? { ...item, ...row } : item;
|
|
|
|
|
});
|
|
|
|
|
const index = newData?.findIndex((item) => row.key === item.key);
|
|
|
|
|
const item = newData[index];
|
|
|
|
|
newData?.splice(index, 1, {
|
|
|
|
|
...item,
|
|
|
|
|
...row,
|
|
|
|
|
});
|
|
|
|
|
setStockDetails(newData);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const handleBulkSave = (row) => {
|
|
|
|
|
if (row?.CurrentAmt && row?.CurrentMRP) {
|
|
|
|
|
if (parseFloat(row?.CurrentMRP) >= parseFloat(row?.CurrentAmt)) {
|
|
|
|
|
const newData = BulkProductData?.map((item) => {
|
|
|
|
|
return item.key === row.key ? { ...item, ...row } : item;
|
|
|
|
|
});
|
|
|
|
|
const index = newData?.findIndex((item) => row.key === item.key);
|
|
|
|
|
const item = newData[index];
|
|
|
|
|
newData?.splice(index, 1, {
|
|
|
|
|
...item,
|
|
|
|
|
...row,
|
|
|
|
|
});
|
|
|
|
|
setBulkProductData(newData);
|
|
|
|
|
} else {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(
|
2026-01-28 15:59:11 +05:30
|
|
|
"MRP is must be greater than or equal to selling price",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const newData = BulkProductData?.map((item) => {
|
|
|
|
|
return item.key === row.key ? { ...item, ...row } : item;
|
|
|
|
|
});
|
|
|
|
|
const index = newData?.findIndex((item) => row.key === item.key);
|
|
|
|
|
const item = newData[index];
|
|
|
|
|
newData?.splice(index, 1, {
|
|
|
|
|
...item,
|
|
|
|
|
...row,
|
|
|
|
|
});
|
|
|
|
|
setBulkProductData(newData);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const components = {
|
|
|
|
|
body: {
|
|
|
|
|
row: EditableRow,
|
|
|
|
|
cell: EditableCell,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
const BulkComponents = {
|
|
|
|
|
body: {
|
|
|
|
|
row: BulkEditableRow,
|
|
|
|
|
cell: BulkEditableCell,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function safeRound(amountStr) {
|
2026-01-28 15:59:11 +05:30
|
|
|
if (amountStr == null) return allowDecimal ? "0.00" : "0";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const cleaned = String(amountStr).replace(/[^0-9.-]+/g, "");
|
2026-01-27 18:27:29 +05:30
|
|
|
const num = Number(cleaned);
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
if (isNaN(num)) return allowDecimal ? "0.00" : "0";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
return allowDecimal ? num.toFixed(2) : Math.round(num).toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const columns2 = [
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Sl.No",
|
|
|
|
|
align: "center",
|
|
|
|
|
key: "sno",
|
|
|
|
|
width: "60px",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (text, object, index) => (
|
2026-01-28 15:59:11 +05:30
|
|
|
<a style={{ color: "black" }}>{index + 1}</a>
|
2026-01-27 18:27:29 +05:30
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Product Name",
|
|
|
|
|
dataIndex: "ProdName",
|
|
|
|
|
key: "ProdName",
|
|
|
|
|
width: "20%",
|
2026-01-27 18:27:29 +05:30
|
|
|
filteredValue: [searchedText],
|
|
|
|
|
onFilter: (value, record) => {
|
|
|
|
|
return String(record.ProdName)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
.includes(value?.toLowerCase());
|
|
|
|
|
},
|
|
|
|
|
sorter: (a, b) => a?.ProdName?.localeCompare(b.ProdName),
|
2026-01-28 15:59:11 +05:30
|
|
|
sortOrder: sortedInfo.columnKey === "ProdName" ? sortedInfo.order : null,
|
2026-01-27 18:27:29 +05:30
|
|
|
ellipsis: true,
|
|
|
|
|
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
<span>
|
|
|
|
|
{record.ProdName} ({record.UOM} {record.UOMName})
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "stock Date",
|
|
|
|
|
dataIndex: "InwardDate",
|
|
|
|
|
key: "InwardDate",
|
|
|
|
|
align: "right",
|
|
|
|
|
width: "150px",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (InwardDate) =>
|
2026-01-28 15:59:11 +05:30
|
|
|
InwardDate !== null ? ExtractDateFormate(InwardDate) : "-",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Old MRP",
|
|
|
|
|
dataIndex: "MRP",
|
|
|
|
|
key: "MRP",
|
|
|
|
|
align: "right",
|
|
|
|
|
render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : "-"),
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Old Price",
|
|
|
|
|
dataIndex: "SellPrice",
|
|
|
|
|
key: "SellPrice",
|
|
|
|
|
align: "right",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (SellPrice) =>
|
2026-01-28 15:59:11 +05:30
|
|
|
safeRound(SellPrice) !== null ? safeRound(SellPrice) : "-",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New MRP",
|
|
|
|
|
dataIndex: "CurrentMRP",
|
|
|
|
|
key: "CurrentMRP",
|
|
|
|
|
align: "right",
|
2026-01-27 18:27:29 +05:30
|
|
|
editable: true,
|
2026-01-28 15:59:11 +05:30
|
|
|
render: (text, record) => <p>{text ? text : "Enter MRP"}</p>,
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New SP",
|
|
|
|
|
dataIndex: "CurrentAmt",
|
|
|
|
|
key: "CurrentAmt",
|
|
|
|
|
align: "right",
|
2026-01-27 18:27:29 +05:30
|
|
|
editable: true,
|
2026-01-28 15:59:11 +05:30
|
|
|
render: (text, record) => <p>{text ? text : "Enter Price"}</p>,
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Action",
|
|
|
|
|
dataIndex: "SellPrice",
|
|
|
|
|
key: "SellPrice",
|
|
|
|
|
align: "center",
|
|
|
|
|
width: "100px",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (_, record, index) => (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
columnGap: "1rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<DeleteFilled
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ color: "#FF4D4F" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
onClick={() => statusFormatter(record, index)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
const BulkPricechangeColumns = [
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Sl.No",
|
|
|
|
|
align: "center",
|
|
|
|
|
key: "sno",
|
|
|
|
|
width: "50px",
|
2026-01-27 18:27:29 +05:30
|
|
|
render: (text, object, index) => (
|
2026-01-28 15:59:11 +05:30
|
|
|
<a style={{ color: "black" }}>
|
2026-01-27 18:27:29 +05:30
|
|
|
{(Bulkchangepage - 1) * 10 + index + 1}
|
|
|
|
|
</a>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Name",
|
|
|
|
|
dataIndex: "ProdName",
|
|
|
|
|
key: "ProdName",
|
|
|
|
|
width: "20%",
|
2026-01-27 18:27:29 +05:30
|
|
|
filteredValue: [BulksearchedText],
|
|
|
|
|
onFilter: (value, record) => {
|
|
|
|
|
return String(record.ProdName)
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
.includes(value?.toLowerCase());
|
|
|
|
|
},
|
|
|
|
|
sorter: (a, b) => a?.ProdName?.localeCompare(b.ProdName),
|
|
|
|
|
sortOrder:
|
2026-01-28 15:59:11 +05:30
|
|
|
BulksortedInfo.columnKey === "ProdName" ? BulksortedInfo.order : null,
|
2026-01-27 18:27:29 +05:30
|
|
|
ellipsis: true,
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
<span>
|
|
|
|
|
{record.ProdName} ({record.Size} {record.UOMName})
|
|
|
|
|
</span>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Variant Name",
|
|
|
|
|
dataIndex: "ProdVariantName",
|
|
|
|
|
key: "ProdVariantName",
|
|
|
|
|
align: "left",
|
|
|
|
|
width: "120px",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Batch No",
|
|
|
|
|
dataIndex: "BatchRef",
|
|
|
|
|
key: "BatchRef",
|
|
|
|
|
align: "left",
|
|
|
|
|
width: "120px",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasField("Stock Date")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "stock Date",
|
|
|
|
|
dataIndex: "InwardDate",
|
|
|
|
|
key: "InwardDate",
|
|
|
|
|
align: "center",
|
|
|
|
|
width: "100px",
|
|
|
|
|
render: (InwardDate) =>
|
|
|
|
|
InwardDate !== null ? ExtractDateFormate(InwardDate) : "-",
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasField("Expiry Date")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Exp date",
|
|
|
|
|
dataIndex: "ExpDate",
|
|
|
|
|
key: "ExpDate",
|
|
|
|
|
align: "center",
|
|
|
|
|
width: "100px",
|
|
|
|
|
render: (ExpDate) =>
|
|
|
|
|
ExpDate !== null ? ExtractDateFormate(ExpDate) : "-",
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasField("Stock")
|
|
|
|
|
? [
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
title: "stock",
|
|
|
|
|
dataIndex: "BalanceQty",
|
|
|
|
|
key: "BalanceQty",
|
|
|
|
|
align: "right",
|
|
|
|
|
width: "60px",
|
|
|
|
|
render: (BalanceQty) => (BalanceQty !== null ? BalanceQty : "-"),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasField("Old MRP")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old MRP",
|
|
|
|
|
dataIndex: "MRP",
|
|
|
|
|
key: "MRP",
|
|
|
|
|
align: "right",
|
|
|
|
|
width: "70px",
|
|
|
|
|
render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : "-"),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasField("Old SP")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old SP",
|
|
|
|
|
dataIndex: "SellPrice",
|
|
|
|
|
key: "SellPrice",
|
|
|
|
|
align: "right",
|
|
|
|
|
width: "70px",
|
|
|
|
|
render: (SellPrice) =>
|
|
|
|
|
safeRound(SellPrice) !== null ? safeRound(SellPrice) : "-",
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasField("Old Wholesale Price")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "Old Wholesale Price",
|
|
|
|
|
dataIndex: "WhSalePrice",
|
|
|
|
|
key: "WhSalePrice",
|
|
|
|
|
align: "right",
|
|
|
|
|
width: "120px",
|
|
|
|
|
render: (WhSalePrice) =>
|
|
|
|
|
safeRound(WhSalePrice) !== null ? safeRound(WhSalePrice) : "-",
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
2026-01-27 18:27:29 +05:30
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New MRP",
|
|
|
|
|
dataIndex: "CurrentMRP",
|
|
|
|
|
key: "CurrentMRP",
|
|
|
|
|
align: "center",
|
|
|
|
|
with: "4rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
editable: true,
|
2026-01-28 15:59:11 +05:30
|
|
|
render: (text, record) => <p>{text ? text : "Enter MRP"}</p>,
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "New SP",
|
|
|
|
|
dataIndex: "CurrentAmt",
|
|
|
|
|
key: "CurrentAmt",
|
|
|
|
|
align: "center",
|
|
|
|
|
with: "4rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
editable: true,
|
2026-01-28 15:59:11 +05:30
|
|
|
render: (text, record) => <p>{text ? text : "Enter Price"}</p>,
|
2026-01-27 18:27:29 +05:30
|
|
|
width: 100,
|
|
|
|
|
},
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasField("New Wholesale Price")
|
|
|
|
|
? [
|
|
|
|
|
{
|
|
|
|
|
title: "New Wholesale Price",
|
|
|
|
|
dataIndex: "CurrentWhAmt",
|
|
|
|
|
key: "CurrentWhAmt",
|
|
|
|
|
align: "center",
|
|
|
|
|
with: "4rem",
|
|
|
|
|
editable: true,
|
|
|
|
|
render: (text, record) => (
|
|
|
|
|
<p>{text ? text : "Enter Wholesale Price"}</p>
|
|
|
|
|
),
|
|
|
|
|
width: 120,
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
: []),
|
2026-01-27 18:27:29 +05:30
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const HandleStockNames = (e, option) => {
|
|
|
|
|
const newStockDetails = option?.stockDetails || [];
|
|
|
|
|
// Check if any of the new products already exist in StockDetails
|
|
|
|
|
setStockDetails((prevStockDetails) => {
|
|
|
|
|
const existingInwardDtlIds = new Set(
|
2026-01-28 15:59:11 +05:30
|
|
|
prevStockDetails?.map((item) => item.InwardDtlId),
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const uniqueNewStockDetails = newStockDetails
|
|
|
|
|
?.filter((item) => !existingInwardDtlIds.has(item.InwardDtlId))
|
|
|
|
|
?.map((detail) => ({
|
|
|
|
|
...detail,
|
|
|
|
|
UOMName: option?.QuantityName,
|
|
|
|
|
UOM: option?.Quantity,
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
return [...prevStockDetails, ...uniqueNewStockDetails];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setProductName(option?.label);
|
|
|
|
|
};
|
|
|
|
|
// const handleCancel = () => {
|
|
|
|
|
// setOpen(false);
|
|
|
|
|
// setOpenEditModal(false);
|
|
|
|
|
// };
|
|
|
|
|
// const HandleSubmit = () => {
|
|
|
|
|
// const newStockDetails = dataSource || [];
|
|
|
|
|
// const filteredCurrentAmtData = newStockDetails?.filter(
|
|
|
|
|
// (item) =>
|
|
|
|
|
// item.CurrentAmt !== undefined &&
|
|
|
|
|
// item.CurrentAmt !== null &&
|
|
|
|
|
// item.CurrentMRP !== undefined &&
|
|
|
|
|
// item.CurrentMRP !== null
|
|
|
|
|
// );
|
|
|
|
|
// if (filteredCurrentAmtData?.length > 0) {
|
|
|
|
|
// setStockDetails((prevStockDetails) => {
|
|
|
|
|
// const existingInwardDtlIds = new Set(
|
|
|
|
|
// prevStockDetails?.map((item) => item.InwardDtlId)
|
|
|
|
|
// );
|
|
|
|
|
// const uniqueNewStockDetails = filteredCurrentAmtData?.filter(
|
|
|
|
|
// (item) => !existingInwardDtlIds.has(item.InwardDtlId)
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// let beforeFinal = [...prevStockDetails, ...uniqueNewStockDetails];
|
|
|
|
|
// const existingInwardDtlIds2 = new Set(
|
|
|
|
|
// filteredCurrentAmtData?.map((item) => item.InwardDtlId)
|
|
|
|
|
// );
|
|
|
|
|
// const uniqueNewStockDetails2 = beforeFinal?.filter(
|
|
|
|
|
// (item) => !existingInwardDtlIds2.has(item.InwardDtlId)
|
|
|
|
|
// );
|
|
|
|
|
// return [...filteredCurrentAmtData, ...uniqueNewStockDetails2];
|
|
|
|
|
// });
|
|
|
|
|
// setOpen(false);
|
|
|
|
|
// } else {
|
|
|
|
|
// setMessageType('error');
|
|
|
|
|
// setMessageData('Please give all details');
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
const HandlePutData = async () => {
|
2026-01-28 15:59:11 +05:30
|
|
|
if (RadioSelection == "Bulk") {
|
2026-01-27 18:27:29 +05:30
|
|
|
const filteredCurrentAmtData = BulkProductData?.filter(
|
|
|
|
|
(item) =>
|
2026-01-28 15:59:11 +05:30
|
|
|
(item.CurrentAmt !== undefined &&
|
|
|
|
|
item.CurrentAmt !== null &&
|
|
|
|
|
item.CurrentAmt !== "" &&
|
|
|
|
|
item.CurrentMRP !== undefined &&
|
|
|
|
|
item.CurrentMRP !== null &&
|
|
|
|
|
item.CurrentMRP !== "") ||
|
|
|
|
|
(item.CurrentWhAmt !== undefined &&
|
|
|
|
|
item.CurrentWhAmt !== null &&
|
|
|
|
|
item.CurrentWhAmt !== ""),
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
const hasInvalidData = BulkProductData.every((item) => {
|
|
|
|
|
const isAbsent = item.CurrentAmt == null && item.CurrentMRP == null;
|
|
|
|
|
|
|
|
|
|
const isPresent = item.CurrentAmt != null && item.CurrentMRP != null;
|
|
|
|
|
|
|
|
|
|
return isAbsent || isPresent;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (filteredCurrentAmtData?.length > 0 && hasInvalidData) {
|
|
|
|
|
let Postdata = {
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
2026-01-28 15:59:11 +05:30
|
|
|
Type: "Variant",
|
2026-01-27 18:27:29 +05:30
|
|
|
ProductDetails: filteredCurrentAmtData?.map((item) => ({
|
|
|
|
|
ProdId: item?.ProdId,
|
2026-01-28 15:59:11 +05:30
|
|
|
NewMRP: item?.CurrentMRP,
|
|
|
|
|
NewSellPrice: item?.CurrentAmt,
|
|
|
|
|
AdjComment: "string",
|
2026-01-27 18:27:29 +05:30
|
|
|
InwardDtlId: item?.InwardDtlId,
|
2026-01-28 15:59:11 +05:30
|
|
|
NewWholeSalePrice: item.CurrentWhAmt,
|
2026-01-27 18:27:29 +05:30
|
|
|
})),
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
let response = await dispatch(bulkPriceUpdate(Postdata)).unwrap();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
if (response?.data?.statusCode == 1) {
|
|
|
|
|
setProductName();
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("success");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
fetchData();
|
2026-01-28 15:59:11 +05:30
|
|
|
setBulksearchedText("");
|
2026-01-27 18:27:29 +05:30
|
|
|
setStockDetails([]);
|
|
|
|
|
setBulkProductData([]);
|
|
|
|
|
} else {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("Please give all details");
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const filteredStockDetails = StockDetails?.filter(
|
|
|
|
|
(item) =>
|
|
|
|
|
item?.CurrentMRP &&
|
2026-01-28 15:59:11 +05:30
|
|
|
item?.CurrentMRP !== "" &&
|
2026-01-27 18:27:29 +05:30
|
|
|
item?.CurrentAmt &&
|
2026-01-28 15:59:11 +05:30
|
|
|
item?.CurrentAmt !== "",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (filteredStockDetails?.length === 0) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("Please enter price details for at least one product");
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let data = {
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
ProductDetails: filteredStockDetails?.map((item) => ({
|
|
|
|
|
ProdId: item?.ProdId,
|
|
|
|
|
MRP: item?.CurrentMRP,
|
|
|
|
|
SellPrice: item?.CurrentAmt,
|
2026-01-28 15:59:11 +05:30
|
|
|
AdjComment: "string",
|
2026-01-27 18:27:29 +05:30
|
|
|
InwardDtlId: item?.InwardDtlId,
|
|
|
|
|
})),
|
|
|
|
|
UpdatedBy: 1,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let response = await dispatch(PutStockPrice(data)).unwrap();
|
|
|
|
|
let res = await dispatch(getStockNames(data)).unwrap();
|
|
|
|
|
setStockNames(res?.data?.data);
|
|
|
|
|
if (response?.data?.statusCode == 1) {
|
|
|
|
|
setProductName();
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("success");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
fetchData();
|
|
|
|
|
} else {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
}
|
|
|
|
|
setStockDetails([]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// const HandleEditSubmit = () => {
|
|
|
|
|
// let newStockDetails = dataSource || [];
|
|
|
|
|
|
|
|
|
|
// let filteredInverd = StockDetails?.filter(
|
|
|
|
|
// (item) => item.InwardDtlId !== newStockDetails?.[0].InwardDtlId
|
|
|
|
|
// );
|
|
|
|
|
// filteredInverd.push(newStockDetails?.[0]);
|
|
|
|
|
// setStockDetails(filteredInverd);
|
|
|
|
|
// setOpenEditModal(false);
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const columns = defaultColumns?.map((col) => {
|
|
|
|
|
// if (!col.editable) {
|
|
|
|
|
// return col;
|
|
|
|
|
// }
|
|
|
|
|
// return {
|
|
|
|
|
// ...col,
|
|
|
|
|
// onCell: (record) => ({
|
|
|
|
|
// record,
|
|
|
|
|
// editable: col.editable,
|
|
|
|
|
// dataIndex: col.dataIndex,
|
|
|
|
|
// title: col.title,
|
|
|
|
|
// handleSave,
|
|
|
|
|
// }),
|
|
|
|
|
// };
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
const columns2WithEditable = columns2?.map((col) => {
|
|
|
|
|
if (!col.editable) {
|
|
|
|
|
return col;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
...col,
|
|
|
|
|
onCell: (record) => ({
|
|
|
|
|
record,
|
|
|
|
|
editable: col.editable,
|
|
|
|
|
dataIndex: col.dataIndex,
|
|
|
|
|
title: col.title,
|
|
|
|
|
handleSave,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
const BulkPriceColumns = BulkPricechangeColumns?.map((col) => {
|
|
|
|
|
if (!col.editable) {
|
|
|
|
|
return col;
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
...col,
|
|
|
|
|
onCell: (record) => ({
|
|
|
|
|
record,
|
|
|
|
|
editable: col.editable,
|
|
|
|
|
dataIndex: col.dataIndex,
|
|
|
|
|
title: col.title,
|
|
|
|
|
handleSave,
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const handlePageChange = (current) => {
|
|
|
|
|
setpage(current);
|
|
|
|
|
};
|
|
|
|
|
const handlePageChangeBulk = (current) => {
|
|
|
|
|
setBulkchangepage(current);
|
|
|
|
|
|
|
|
|
|
setPageSize(pageSize);
|
|
|
|
|
};
|
|
|
|
|
const onComplete = useCallback(() => {
|
|
|
|
|
setMessageData(null);
|
|
|
|
|
setMessageType(null);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onSearch = (value) => {
|
|
|
|
|
setSearchedText(value);
|
|
|
|
|
};
|
|
|
|
|
const onSearchBulk = (value) => {
|
|
|
|
|
setBulksearchedText(value);
|
|
|
|
|
};
|
|
|
|
|
const onSearchChange = (e) => {
|
|
|
|
|
setSearchedText(e?.target?.value);
|
|
|
|
|
};
|
|
|
|
|
const onSearchChangeBulk = (e) => {
|
|
|
|
|
setBulksearchedText(e?.target?.value);
|
|
|
|
|
};
|
|
|
|
|
const handleChange = (pagination, filters, sorter) => {
|
|
|
|
|
setFilteredInfo(filters);
|
|
|
|
|
setSortedInfo(sorter);
|
|
|
|
|
};
|
|
|
|
|
const handleChangeBulk = (pagination, filters, sorter) => {
|
|
|
|
|
setBulksortedInfo(sorter);
|
|
|
|
|
};
|
|
|
|
|
const onRadioChange = (data) => {
|
|
|
|
|
setRadioSelection(data);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleUploadExcel = () => {
|
|
|
|
|
setExcelModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFieldSetup = () => {
|
|
|
|
|
setFieldSetup(true);
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const handleExcelFieldSetup = () => {
|
|
|
|
|
setExcelFieldSetup(true);
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
const showPriceChangeModal = () => {
|
|
|
|
|
setPriceChangeModalOpen(true);
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const handleExport = async (isStockVariantBased = "Yes") => {
|
2026-01-27 18:27:29 +05:30
|
|
|
setExportLoading(true);
|
|
|
|
|
setPriceChangeModalOpen(false);
|
|
|
|
|
|
|
|
|
|
const uniqueBulkProductData =
|
2026-01-28 15:59:11 +05:30
|
|
|
isStockVariantBased === "Yes"
|
2026-01-27 18:27:29 +05:30
|
|
|
? BulkProductData || []
|
|
|
|
|
: (BulkProductData || [])?.filter(
|
2026-01-28 15:59:11 +05:30
|
|
|
(item, index, self) =>
|
|
|
|
|
index === self.findIndex((p) => p.ProdId === item.ProdId),
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
if (!uniqueBulkProductData?.length) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("No data available to export");
|
2026-01-27 18:27:29 +05:30
|
|
|
setExportLoading(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const workbook = new ExcelJS.Workbook();
|
2026-01-28 15:59:11 +05:30
|
|
|
const worksheet = workbook.addWorksheet("Products");
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
/* ---------------- COLUMN DEFINITIONS ---------------- */
|
|
|
|
|
const columns = [
|
2026-01-28 15:59:11 +05:30
|
|
|
{ header: "Product Name", key: "ProdName", width: 20 },
|
|
|
|
|
...(isStockVariantBased === "Yes"
|
|
|
|
|
? [{ header: "Variant Name", key: "ProdVariantName", width: 20 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(isStockVariantBased === "Yes"
|
|
|
|
|
? [{ header: "Batch No", key: "BatchRef", width: 20 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("Stock Date")
|
|
|
|
|
? [{ header: "Stock Date", key: "StockDate", width: 15 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("Expiry Date")
|
|
|
|
|
? [{ header: "Exp Date", key: "ExpDate", width: 15 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("Stock")
|
|
|
|
|
? [{ header: "Stock", key: "Stock", width: 10 }]
|
2026-01-27 18:27:29 +05:30
|
|
|
: []),
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasExcelField("Old MRP")
|
|
|
|
|
? [{ header: "Old MRP", key: "OldMRP", width: 10 }]
|
2026-01-27 18:27:29 +05:30
|
|
|
: []),
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasExcelField("Old SP")
|
|
|
|
|
? [{ header: "Old SP", key: "OldSP", width: 10 }]
|
2026-01-27 18:27:29 +05:30
|
|
|
: []),
|
2026-01-28 15:59:11 +05:30
|
|
|
...(hasExcelField("Old Wholesale Price")
|
|
|
|
|
? [{ header: "Old Wholesale Price", key: "WhSalePrice", width: 14 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("Size")
|
|
|
|
|
? [{ header: "Size", key: "Size", width: 10 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("Stock Maintainence")
|
|
|
|
|
? [{ header: "Stock Maintainence", key: "StockAvailable", width: 18 }]
|
|
|
|
|
: []),
|
|
|
|
|
...(hasExcelField("UOM Name")
|
|
|
|
|
? [{ header: "UOMName", key: "UOMName", width: 15 }]
|
|
|
|
|
: []),
|
|
|
|
|
// ...(hasExcelField("New MRP & New SP")
|
|
|
|
|
// ? [
|
|
|
|
|
{ header: "New MRP", key: "NewMRP", width: 12 },
|
|
|
|
|
{ header: "New SP", key: "NewSP", width: 12 },
|
|
|
|
|
// ]
|
|
|
|
|
// : []),
|
|
|
|
|
|
|
|
|
|
...(hasExcelField("New Wholesale Price")
|
|
|
|
|
? [{ header: "New Wholesale Price", key: "NewWhSalePrice", width: 14 }]
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
// --- Hidden system columns (always included) ---
|
|
|
|
|
{ header: "ProdId", key: "ProdId", width: 1 },
|
2026-01-27 18:27:29 +05:30
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
...(isStockVariantBased === "Yes"
|
|
|
|
|
? [{ header: "InwardDtlId", key: "InwardDtlId", width: 1 }]
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
{ header: "key", key: "key", width: 1 },
|
|
|
|
|
{ header: "downloadType", key: "downloadType", width: 1 },
|
2026-01-27 18:27:29 +05:30
|
|
|
];
|
|
|
|
|
|
|
|
|
|
worksheet.columns = columns;
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
worksheet.views = [{ state: "frozen", xSplit: 1, ySplit: 1 }];
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const headerRow = worksheet.getRow(1);
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const newMRPCol = headerRow.values.indexOf("New MRP");
|
|
|
|
|
const newSPCol = headerRow.values.indexOf("New SP");
|
|
|
|
|
const hasNewMRPAndSP = newMRPCol > 0 && newSPCol > 0;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
/* ---------------- HEADER STYLE ---------------- */
|
|
|
|
|
worksheet.getRow(1).eachCell((cell) => {
|
|
|
|
|
const header = cell.value;
|
|
|
|
|
|
|
|
|
|
const isHiddenCol =
|
2026-01-28 15:59:11 +05:30
|
|
|
header === "key" ||
|
|
|
|
|
header === "ProdId" ||
|
|
|
|
|
header === "InwardDtlId" ||
|
|
|
|
|
header === "downloadType";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
cell.font = {
|
|
|
|
|
bold: true,
|
|
|
|
|
size: isHiddenCol ? 1 : 11,
|
2026-01-28 15:59:11 +05:30
|
|
|
color: { argb: isHiddenCol ? "FFFFFFFF" : "FF000000" },
|
2026-01-27 18:27:29 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cell.alignment = {
|
2026-01-28 15:59:11 +05:30
|
|
|
horizontal: "center",
|
|
|
|
|
vertical: "middle",
|
2026-01-27 18:27:29 +05:30
|
|
|
wrapText: true, // ✅ prevents overflow in header
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cell.fill = {
|
2026-01-28 15:59:11 +05:30
|
|
|
type: "pattern",
|
|
|
|
|
pattern: "solid",
|
2026-01-27 18:27:29 +05:30
|
|
|
fgColor: {
|
2026-01-28 15:59:11 +05:30
|
|
|
argb: isHiddenCol ? "FFFFFFFF" : "FF52C41A",
|
2026-01-27 18:27:29 +05:30
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cell.border = isHiddenCol
|
|
|
|
|
? undefined
|
|
|
|
|
: {
|
2026-01-28 15:59:11 +05:30
|
|
|
right: { style: "thin", color: { argb: "FF000000" } },
|
|
|
|
|
bottom: { style: "thin", color: { argb: "FF000000" } },
|
|
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* ---------------- ADD DATA ---------------- */
|
|
|
|
|
uniqueBulkProductData.forEach((product) => {
|
|
|
|
|
worksheet.addRow({
|
|
|
|
|
ProdName: product?.ProdName,
|
|
|
|
|
ProdVariantName: product?.ProdVariantName,
|
|
|
|
|
BatchRef: product?.BatchRef,
|
|
|
|
|
StockDate: product?.InwardDate,
|
2026-01-28 15:59:11 +05:30
|
|
|
ExpDate: product?.ExpDate || "-",
|
2026-01-27 18:27:29 +05:30
|
|
|
Stock: product?.BalanceQty,
|
|
|
|
|
OldMRP: product?.MRP,
|
|
|
|
|
OldSP: product?.SellPrice,
|
|
|
|
|
WhSalePrice: product?.WhSalePrice,
|
|
|
|
|
Size: product?.Size,
|
|
|
|
|
StockAvailable: product?.StockAvailable,
|
|
|
|
|
UOMName: product?.UOMName,
|
|
|
|
|
key: product?.key,
|
2026-01-28 15:59:11 +05:30
|
|
|
downloadType: isStockVariantBased === "Yes" ? "Variant" : "Product",
|
|
|
|
|
NewMRP: "",
|
|
|
|
|
NewSP: "",
|
|
|
|
|
NewWhSalePrice: "",
|
2026-01-27 18:27:29 +05:30
|
|
|
ProdId: product?.ProdId,
|
|
|
|
|
InwardDtlId:
|
2026-01-28 15:59:11 +05:30
|
|
|
isStockVariantBased === "Yes" ? product?.InwardDtlId : undefined,
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// ---------------- VALIDATION: New SP <= New MRP ----------------
|
2026-01-28 15:59:11 +05:30
|
|
|
if (hasNewMRPAndSP) {
|
|
|
|
|
worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
|
|
|
|
|
if (rowNumber === 1) return; // skip header
|
|
|
|
|
|
|
|
|
|
const newMRPCell = row.getCell(newMRPCol);
|
|
|
|
|
const newSPCell = row.getCell(newSPCol);
|
|
|
|
|
|
|
|
|
|
newSPCell.dataValidation = {
|
|
|
|
|
type: "custom",
|
|
|
|
|
allowBlank: true,
|
|
|
|
|
formulae: [
|
|
|
|
|
`IFERROR(VALUE(${newSPCell.address}),0) <= IFERROR(VALUE(${newMRPCell.address}),0)`,
|
|
|
|
|
],
|
|
|
|
|
showErrorMessage: true,
|
|
|
|
|
errorStyle: "stop",
|
|
|
|
|
errorTitle: "Invalid Selling Price",
|
|
|
|
|
error: "New SP cannot be greater than New MRP",
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
/* ---------------- UNLOCK EVERYTHING ---------------- */
|
|
|
|
|
worksheet.eachRow({ includeEmpty: true }, (row) => {
|
|
|
|
|
row.eachCell({ includeEmpty: true }, (cell) => {
|
|
|
|
|
cell.protection = { locked: false };
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* ---------------- LOCK HEADER ---------------- */
|
|
|
|
|
worksheet.getRow(1).eachCell((cell) => {
|
|
|
|
|
cell.protection = { locked: true };
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
worksheet.getRow(1).height = 32;
|
|
|
|
|
|
|
|
|
|
/* ---------------- LOCK ALL EXCEPT New MRP & New SP ---------------- */
|
|
|
|
|
worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
|
|
|
|
|
if (rowNumber === 1) return;
|
|
|
|
|
|
|
|
|
|
row.eachCell((cell, colNumber) => {
|
|
|
|
|
const header = worksheet.getRow(1).getCell(colNumber).value;
|
|
|
|
|
|
|
|
|
|
const isHiddenCol =
|
2026-01-28 15:59:11 +05:30
|
|
|
header === "key" ||
|
|
|
|
|
header === "ProdId" ||
|
|
|
|
|
header === "InwardDtlId" ||
|
|
|
|
|
header === "downloadType";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const isEditable =
|
2026-01-28 15:59:11 +05:30
|
|
|
header === "New MRP" ||
|
|
|
|
|
header === "New SP" ||
|
|
|
|
|
header === "New Wholesale Price";
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
cell.protection = { locked: !isEditable };
|
|
|
|
|
cell.alignment = {
|
2026-01-28 15:59:11 +05:30
|
|
|
vertical: "middle",
|
2026-01-27 18:27:29 +05:30
|
|
|
wrapText: true,
|
|
|
|
|
};
|
|
|
|
|
if (isHiddenCol) {
|
|
|
|
|
cell.font = {
|
|
|
|
|
size: 1,
|
2026-01-28 15:59:11 +05:30
|
|
|
color: { argb: "FFFFFFFF" },
|
2026-01-27 18:27:29 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cell.fill = {
|
2026-01-28 15:59:11 +05:30
|
|
|
type: "pattern",
|
|
|
|
|
pattern: "solid",
|
|
|
|
|
fgColor: { argb: "FFFFFFFF" },
|
2026-01-27 18:27:29 +05:30
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* ---------------- PROTECT SHEET ---------------- */
|
2026-01-28 15:59:11 +05:30
|
|
|
await worksheet.protect("", {
|
2026-01-27 18:27:29 +05:30
|
|
|
selectLockedCells: false,
|
|
|
|
|
selectUnlockedCells: true,
|
|
|
|
|
formatCells: false,
|
|
|
|
|
formatColumns: false,
|
|
|
|
|
insertRows: false,
|
|
|
|
|
deleteRows: false,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* ---------------- DOWNLOAD ---------------- */
|
|
|
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
|
|
|
const blob = new Blob([buffer], {
|
2026-01-28 15:59:11 +05:30
|
|
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
const link = document.createElement("a");
|
2026-01-27 18:27:29 +05:30
|
|
|
link.href = URL.createObjectURL(blob);
|
2026-01-28 15:59:11 +05:30
|
|
|
link.download = "PriceChange_Data.xlsx";
|
2026-01-27 18:27:29 +05:30
|
|
|
link.click();
|
|
|
|
|
|
|
|
|
|
setExportLoading(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleClick = () => {
|
|
|
|
|
fileInputRef.current.click();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFileUpload = (e) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
setFileLoading(true);
|
2026-01-27 18:27:29 +05:30
|
|
|
const file = e.target.files[0];
|
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
|
|
dispatch(emptyExcelData());
|
2026-01-28 15:59:11 +05:30
|
|
|
setFileLoading(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isAllowed = allowedExcelTypes?.includes(file.type);
|
|
|
|
|
if (!isAllowed) {
|
|
|
|
|
Modal.error({
|
2026-01-28 15:59:11 +05:30
|
|
|
title: "Invalid File Type",
|
|
|
|
|
content: "Only Excel files (.xls, .xlsx) are allowed.",
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
|
|
|
|
handleCancelData();
|
2026-01-28 15:59:11 +05:30
|
|
|
setFileLoading(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
|
|
|
|
|
|
|
reader.onload = (event) => {
|
|
|
|
|
const arrayBuffer = event.target.result;
|
|
|
|
|
|
|
|
|
|
const extractedData = extractPriceChangeDataFromExcel(arrayBuffer);
|
|
|
|
|
|
2026-01-28 15:59:11 +05:30
|
|
|
console.log(extractedData, "extractedData");
|
2026-01-27 18:27:29 +05:30
|
|
|
if ((extractedData || [])?.length === 0) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageData("No Data Found in Uploaded Sheet");
|
|
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
handleCancelData();
|
2026-01-28 15:59:11 +05:30
|
|
|
setFileLoading(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setUploadedData(extractedData);
|
2026-01-28 15:59:11 +05:30
|
|
|
setFileLoading(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
// setFormValuesFromExtractedData(extractedData);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
reader.readAsArrayBuffer(file); // ✅ THIS IS REQUIRED
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const setFormValuesFromExtractedData = (data) => {
|
|
|
|
|
const formValues = {};
|
|
|
|
|
|
|
|
|
|
data.forEach((item) => {
|
|
|
|
|
const id = item.localId;
|
|
|
|
|
|
|
|
|
|
if (item.NewMRP !== null && item.NewMRP !== undefined) {
|
|
|
|
|
formValues[`NewMRP${id}`] = item.NewMRP;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (item.NewSellPrice !== null && item.NewSellPrice !== undefined) {
|
|
|
|
|
formValues[`NewSellPrice${id}`] = item.NewSellPrice;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
item.NewWholeSalePrice !== null &&
|
|
|
|
|
item.NewWholeSalePrice !== undefined
|
|
|
|
|
) {
|
|
|
|
|
formValues[`NewWholeSalePrice${id}`] = item.NewWholeSalePrice;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
excelDataRef.current?.setFieldsValue(formValues);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const extractPriceChangeDataFromExcel = (arrayBuffer) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
const workbook = read(arrayBuffer, { type: "array" });
|
2026-01-27 18:27:29 +05:30
|
|
|
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
|
|
|
|
|
|
|
|
const rows = utils.sheet_to_json(worksheet, {
|
|
|
|
|
header: 1,
|
|
|
|
|
raw: false,
|
2026-01-28 15:59:11 +05:30
|
|
|
defval: "",
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!rows.length) return [];
|
|
|
|
|
|
|
|
|
|
const header = rows[0];
|
2026-01-28 15:59:11 +05:30
|
|
|
setHeaders(header);
|
2026-01-27 18:27:29 +05:30
|
|
|
const dataRows = rows.slice(1);
|
|
|
|
|
|
|
|
|
|
// Helper to safely get column value
|
|
|
|
|
const getVal = (row, colName) => {
|
|
|
|
|
const idx = header.indexOf(colName);
|
2026-01-28 15:59:11 +05:30
|
|
|
return idx !== -1 ? row[idx] : "";
|
2026-01-27 18:27:29 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const result = dataRows
|
|
|
|
|
.map((row) => {
|
2026-01-28 15:59:11 +05:30
|
|
|
const prodId = getVal(row, "ProdId")?.toString().trim();
|
2026-01-27 18:27:29 +05:30
|
|
|
if (!prodId) return null;
|
|
|
|
|
|
|
|
|
|
const newMRP =
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "New MRP") !== "" ? Number(getVal(row, "New MRP")) : null;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const newSP =
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "New SP") !== "" ? Number(getVal(row, "New SP")) : null;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const newWholesale =
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "New Wholesale Price") !== ""
|
|
|
|
|
? Number(getVal(row, "New Wholesale Price"))
|
2026-01-27 18:27:29 +05:30
|
|
|
: null;
|
|
|
|
|
|
|
|
|
|
// ❌ Must have at least one change
|
|
|
|
|
if (newMRP === null && newSP === null && newWholesale === null) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
// 🔹 Product identity
|
|
|
|
|
localId: uuidv4(),
|
|
|
|
|
ProdId: prodId,
|
2026-01-28 15:59:11 +05:30
|
|
|
InwardDtlId: getVal(row, "InwardDtlId")
|
|
|
|
|
? getVal(row, "InwardDtlId").toString()
|
2026-01-27 18:27:29 +05:30
|
|
|
: null,
|
|
|
|
|
|
|
|
|
|
// 🔹 Product info
|
2026-01-28 15:59:11 +05:30
|
|
|
VariantName: getVal(row, "Variant Name") || null,
|
|
|
|
|
BatchRef: getVal(row, "Batch No") || null,
|
|
|
|
|
ProductName: getVal(row, "Product Name") || null,
|
|
|
|
|
Size: getVal(row, "Size") || null,
|
|
|
|
|
UOMName: getVal(row, "UOMName") || null,
|
|
|
|
|
StockMaintainence: getVal(row, "Stock Maintainence") || null,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
// 🔹 Stock / dates
|
2026-01-28 15:59:11 +05:30
|
|
|
StockDate: getVal(row, "Stock Date") || null,
|
|
|
|
|
ExpDate: getVal(row, "Exp Date") || null,
|
|
|
|
|
downloadType: getVal(row, "downloadType") || null,
|
2026-01-27 18:27:29 +05:30
|
|
|
Stock:
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "Stock") !== "" ? Number(getVal(row, "Stock")) : null,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
// 🔹 Old prices
|
|
|
|
|
OldMRP:
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "Old MRP") !== ""
|
|
|
|
|
? Number(getVal(row, "Old MRP"))
|
2026-01-27 18:27:29 +05:30
|
|
|
: null,
|
|
|
|
|
|
|
|
|
|
OldSP:
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "Old SP") !== "" ? Number(getVal(row, "Old SP")) : null,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
OldWholeSalePrice:
|
2026-01-28 15:59:11 +05:30
|
|
|
getVal(row, "Old Wholesale Price") !== ""
|
|
|
|
|
? Number(getVal(row, "Old Wholesale Price"))
|
2026-01-27 18:27:29 +05:30
|
|
|
: null,
|
|
|
|
|
|
|
|
|
|
// 🔹 New prices (normalized)
|
|
|
|
|
NewMRP: newMRP,
|
|
|
|
|
NewSellPrice: newSP,
|
|
|
|
|
NewWholeSalePrice: newWholesale,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.filter(Boolean);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCancelData = () => {
|
|
|
|
|
dispatch(emptyExcelData());
|
|
|
|
|
if (fileInputRef.current) {
|
2026-01-28 15:59:11 +05:30
|
|
|
fileInputRef.current.value = "";
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
setUploadedData([]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSubmit = async () => {
|
|
|
|
|
try {
|
2026-01-28 15:59:11 +05:30
|
|
|
setLoading(true);
|
2026-01-27 18:27:29 +05:30
|
|
|
const formValues = excelDataRef.current?.getFieldsValue();
|
|
|
|
|
|
|
|
|
|
// Validate all records
|
|
|
|
|
for (let i = 0; i < uploadedData.length; i++) {
|
|
|
|
|
const record = uploadedData[i];
|
|
|
|
|
const newMRP = formValues[`NewMRP${record.localId}`];
|
|
|
|
|
const newSP = formValues[`NewSellPrice${record.localId}`];
|
|
|
|
|
|
|
|
|
|
// If MRP is present, SP must also be present
|
|
|
|
|
if (newMRP && !newSP) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(
|
2026-01-28 15:59:11 +05:30
|
|
|
"If New MRP is provided, New SP must also be provided",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If SP is present, MRP must also be present
|
|
|
|
|
if (newSP && !newMRP) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(
|
2026-01-28 15:59:11 +05:30
|
|
|
"If New SP is provided, New MRP must also be provided",
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// New SP cannot be greater than New MRP
|
|
|
|
|
if (newMRP && newSP && parseFloat(newSP) > parseFloat(newMRP)) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("New SP cannot be greater than New MRP");
|
2026-01-27 18:27:29 +05:30
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updatedData = uploadedData
|
|
|
|
|
?.filter((data) => {
|
|
|
|
|
const hasMRP = !!data?.NewMRP;
|
|
|
|
|
const hasSell = !!data?.NewSellPrice;
|
|
|
|
|
const hasWholesale = !!data?.NewWholeSalePrice;
|
|
|
|
|
|
|
|
|
|
// valid cases
|
|
|
|
|
if (hasMRP && hasSell) return true;
|
|
|
|
|
if (!hasMRP && !hasSell && hasWholesale) return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
})
|
|
|
|
|
?.map((data) => ({
|
|
|
|
|
ProdId: data?.ProdId,
|
|
|
|
|
InwardDtlId: data?.InwardDtlId,
|
|
|
|
|
NewSellPrice: data?.NewSellPrice,
|
|
|
|
|
NewMRP: data?.NewMRP,
|
|
|
|
|
NewWholeSalePrice: data?.NewWholeSalePrice,
|
2026-01-28 15:59:11 +05:30
|
|
|
AdjComment: "string",
|
2026-01-27 18:27:29 +05:30
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const putData = {
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
Type: uploadedData?.[0]?.downloadType,
|
|
|
|
|
ProductDetails: updatedData,
|
|
|
|
|
CreatedBy: UserId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const res = await dispatch(bulkPriceUpdate(putData))?.unwrap();
|
|
|
|
|
|
|
|
|
|
if (res?.data?.statusCode === 1) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageData(res?.data?.response || "Price Updated Successfully");
|
|
|
|
|
setMessageType("success");
|
2026-01-27 18:27:29 +05:30
|
|
|
setUploadedData([]);
|
|
|
|
|
handleCancelData();
|
|
|
|
|
setExcelModalOpen(false);
|
|
|
|
|
await fetchData();
|
|
|
|
|
} else {
|
|
|
|
|
setMessageData(res?.data?.response);
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If validation passes, proceed with submission
|
2026-01-28 15:59:11 +05:30
|
|
|
console.log("Form validation passed", updatedData);
|
2026-01-27 18:27:29 +05:30
|
|
|
} catch (error) {
|
2026-01-28 15:59:11 +05:30
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("Please check all fields and try again");
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFieldSetupSubmit = async () => {
|
|
|
|
|
const postData = {
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
Type: "GB",
|
|
|
|
|
FormType: fieldSetup ? "Price Change" : "Price Change Sheet",
|
|
|
|
|
TypeId: fieldSetup ? categoryId : excelCategoryId,
|
|
|
|
|
ConfigDtl: (fieldSetup ? selectedFields : selectedExcelFields)?.map(
|
|
|
|
|
(field) => ({
|
|
|
|
|
ConfigId: field,
|
|
|
|
|
Access: "Y",
|
|
|
|
|
}),
|
|
|
|
|
),
|
|
|
|
|
CreatedBy: UserId,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const response = await dispatch(postFieldSetup(postData))?.unwrap();
|
|
|
|
|
|
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
setMessageType("success");
|
|
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
if (fieldSetup) {
|
|
|
|
|
await getFieldSetup();
|
|
|
|
|
} else {
|
|
|
|
|
await getExcelFieldSetup();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType("error");
|
|
|
|
|
setMessageData("Failed to set up fields");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFieldSelect = (value) => {
|
|
|
|
|
if (fieldSetup) {
|
|
|
|
|
setSelectedFields((prev) => {
|
|
|
|
|
if (prev.includes(value)) {
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
return [value, ...prev];
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedExcelFields((prev) => {
|
|
|
|
|
if (prev.includes(value)) {
|
|
|
|
|
return prev;
|
|
|
|
|
}
|
|
|
|
|
return [value, ...prev];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleFieldRemove = (id) => {
|
|
|
|
|
if (fieldSetup) {
|
|
|
|
|
setSelectedFields((prev) => prev.filter((field) => field !== id));
|
|
|
|
|
} else {
|
|
|
|
|
setSelectedExcelFields((prev) => prev.filter((field) => field !== id));
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="userPageTable">
|
|
|
|
|
<div className="userPageContent">
|
|
|
|
|
<Messages
|
|
|
|
|
messageType={messageType}
|
|
|
|
|
messageData={messageData}
|
|
|
|
|
onComplete={onComplete}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="formAddNew">
|
|
|
|
|
<div>
|
2026-01-28 15:59:11 +05:30
|
|
|
<FormHeader title={"Price Change"} />
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
justifyContent: "space-between",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
2026-01-28 15:59:11 +05:30
|
|
|
{RadioSelection == "Bulk" && (
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
|
|
|
|
className="toolbar"
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
gap: "1rem",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "space-between",
|
|
|
|
|
width: "100%",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div className="formSearch">
|
|
|
|
|
<Search
|
|
|
|
|
value={BulksearchedText}
|
|
|
|
|
placeholder="Search"
|
|
|
|
|
onSearch={onSearchBulk}
|
|
|
|
|
onSearchChange={onSearchChangeBulk}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="uploadexcelBtn">
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="Upload Excel"
|
|
|
|
|
className="tertiary_Button"
|
|
|
|
|
handleSubmit={handleUploadExcel}
|
|
|
|
|
disabled={addnewAccess}
|
|
|
|
|
icon={<FiUploadCloud size={18} />}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-01-28 15:59:11 +05:30
|
|
|
<Tooltip title="Field Setup">
|
|
|
|
|
<div className="btn btn--info" onClick={handleFieldSetup}>
|
|
|
|
|
<MdOutlineAppRegistration size={19} />
|
|
|
|
|
</div>
|
|
|
|
|
</Tooltip>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-01-28 15:59:11 +05:30
|
|
|
{RadioSelection == "Single" && (
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ width: "100%", marginBottom: "0" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
className="searchAddDiv"
|
|
|
|
|
>
|
2026-01-28 15:59:11 +05:30
|
|
|
<div style={{ width: "100%" }} className="formSearch">
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
gap: "1rem",
|
|
|
|
|
flexWrap: "wrap",
|
|
|
|
|
rowGap: "1.5rem",
|
|
|
|
|
marginBottom: "0.5rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
// justifyContent: 'space-between',
|
2026-01-28 15:59:11 +05:30
|
|
|
width: "100%",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
className="PricePrice-input"
|
|
|
|
|
>
|
|
|
|
|
<DropDowns
|
|
|
|
|
label="Select Product"
|
|
|
|
|
valueData={ProductName}
|
|
|
|
|
showSearch
|
|
|
|
|
onChangeFunction={(value, option) =>
|
|
|
|
|
HandleStockNames(value, option)
|
|
|
|
|
}
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ width: "240px" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
options={DataSource}
|
|
|
|
|
isOnchanges={ProductName ? true : false}
|
|
|
|
|
/>
|
|
|
|
|
<div className="formSearch">
|
|
|
|
|
<Search
|
|
|
|
|
placeholder="Search"
|
|
|
|
|
onSearch={onSearch}
|
|
|
|
|
onSearchChange={onSearchChange}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{/* {RadioSelection == "Bulk" &&
|
|
|
|
|
<div style={{ padding: "5px 5px" }}>
|
|
|
|
|
<Search
|
|
|
|
|
value={BulksearchedText}
|
|
|
|
|
placeholder="Search"
|
|
|
|
|
onSearch={onSearchBulk}
|
|
|
|
|
onSearchChange={onSearchChangeBulk}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
} */}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
gap: "1rem",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "space-between",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<RadioGrpButton
|
|
|
|
|
content={[
|
2026-01-28 15:59:11 +05:30
|
|
|
{ value: "Single", label: "Single Product" },
|
|
|
|
|
{ value: "Bulk", label: "Bulk Product" },
|
2026-01-27 18:27:29 +05:30
|
|
|
]}
|
|
|
|
|
fieldState={true}
|
|
|
|
|
defaultSelect={RadioSelection}
|
|
|
|
|
onSelectFuntion={(e) => onRadioChange(e)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
2026-01-28 15:59:11 +05:30
|
|
|
{(RadioSelection == "Bulk" ||
|
|
|
|
|
(RadioSelection == "Single" && StockDetails.length > 0)) && (
|
|
|
|
|
<div className="samplereportTableButton">
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="Submit"
|
|
|
|
|
color="901D77"
|
|
|
|
|
palcement={"right"}
|
|
|
|
|
handleSubmit={HandlePutData}
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
disabled={addnewAccess}
|
|
|
|
|
></Buttons>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-01-28 15:59:11 +05:30
|
|
|
{RadioSelection == "Single" && (
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
|
|
|
|
className="samplereportTable reportTable pricechangeTable"
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ height: "61vh !important" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
|
|
|
|
<Table
|
|
|
|
|
columns={columns2WithEditable}
|
|
|
|
|
components={components}
|
|
|
|
|
bordered
|
|
|
|
|
dataSource={StockDetails}
|
|
|
|
|
data={StockDetails}
|
|
|
|
|
pagination={
|
|
|
|
|
StockDetails?.length < 11
|
|
|
|
|
? false
|
|
|
|
|
: {
|
2026-01-28 15:59:11 +05:30
|
|
|
current: page,
|
|
|
|
|
pageSize: pageSize,
|
|
|
|
|
onChange: handlePageChange,
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
></Table>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-01-28 15:59:11 +05:30
|
|
|
{RadioSelection == "Bulk" && (
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
|
|
|
|
className="samplereportTable reportTable pricechangeTable"
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ height: "65vh !important" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
|
|
|
|
<Table
|
|
|
|
|
columns={BulkPriceColumns}
|
|
|
|
|
components={BulkComponents}
|
|
|
|
|
data={BulkProductData}
|
|
|
|
|
dataSource={BulkProductData}
|
|
|
|
|
onChange={handleChangeBulk}
|
|
|
|
|
pagination={{
|
|
|
|
|
current: Bulkchangepage,
|
|
|
|
|
pageSize: pageSize,
|
2026-01-28 15:59:11 +05:30
|
|
|
pageSizeOptions: ["10", "20", "30"],
|
2026-01-27 18:27:29 +05:30
|
|
|
onChange: handlePageChangeBulk,
|
|
|
|
|
showSizeChanger: false,
|
|
|
|
|
}}
|
|
|
|
|
></Table>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<DefaultModal
|
|
|
|
|
open={excelModalOpen}
|
|
|
|
|
title="Bulk Upload"
|
|
|
|
|
footer={false}
|
2026-01-28 15:59:11 +05:30
|
|
|
className={"bulkuploadmodal padding-less-modal"}
|
2026-01-27 18:27:29 +05:30
|
|
|
handleCancel={() => {
|
|
|
|
|
setExcelModalOpen(false);
|
|
|
|
|
handleCancelData();
|
|
|
|
|
}}
|
2026-01-28 15:59:11 +05:30
|
|
|
width={uploadedData?.length > 0 ? 1200 : 600}
|
2026-01-27 18:27:29 +05:30
|
|
|
children={
|
|
|
|
|
<>
|
|
|
|
|
{uploadedData?.length === 0 && (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
width: "100%",
|
|
|
|
|
display: "flex",
|
|
|
|
|
justifyContent: "flex-end",
|
|
|
|
|
marginBottom: "1rem",
|
|
|
|
|
gap: "0.5rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
2026-01-28 15:59:11 +05:30
|
|
|
<Tooltip title="Field Setup">
|
|
|
|
|
<div
|
|
|
|
|
className="btn btn--info"
|
|
|
|
|
style={{
|
|
|
|
|
background: "#00694aff",
|
|
|
|
|
color: "#fff",
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
padding: "5px 12px",
|
|
|
|
|
borderRadius: "4px",
|
|
|
|
|
}}
|
|
|
|
|
onClick={handleExcelFieldSetup}
|
|
|
|
|
>
|
|
|
|
|
<MdOutlineAppRegistration size={19} />
|
|
|
|
|
</div>
|
|
|
|
|
</Tooltip>
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
2026-01-28 15:59:11 +05:30
|
|
|
className={`export-excel-div ${exportLoading ? "is-loading" : ""}`}
|
|
|
|
|
onClick={
|
|
|
|
|
exportLoading ? () => { } : () => showPriceChangeModal()
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<CiExport size={20} strokeWidth={1} />
|
|
|
|
|
</div>
|
2026-01-28 15:59:11 +05:30
|
|
|
<div style={{ fontSize: "14px", letterSpacing: "0.2px" }}>
|
2026-01-27 18:27:29 +05:30
|
|
|
Export Excel
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{(!uploadedData || uploadedData?.length === 0) && (
|
|
|
|
|
<>
|
2026-01-28 15:59:11 +05:30
|
|
|
{!fileLoading && (
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
border: "1px dashed #000",
|
|
|
|
|
width: "max-content",
|
|
|
|
|
padding: "10px",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
}}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
|
|
|
|
<div
|
2026-01-28 15:59:11 +05:30
|
|
|
style={{ position: "relative", display: "inline-block" }}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
2026-01-28 15:59:11 +05:30
|
|
|
{/* <Imageupload size="2x" /> */}
|
|
|
|
|
<div
|
2026-01-27 18:27:29 +05:30
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "column",
|
|
|
|
|
alignItems: "center",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
2026-01-28 15:59:11 +05:30
|
|
|
>
|
|
|
|
|
<img
|
|
|
|
|
src={Excelupldimg}
|
|
|
|
|
width={"80px"}
|
|
|
|
|
style={{ cursor: "pointer", margin: "0 0 1rem 0" }}
|
|
|
|
|
onClick={handleClick}
|
|
|
|
|
/>
|
|
|
|
|
<input
|
|
|
|
|
type="file"
|
|
|
|
|
className="form-control"
|
|
|
|
|
onChange={handleFileUpload}
|
|
|
|
|
ref={fileInputRef}
|
|
|
|
|
style={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: 0,
|
|
|
|
|
left: 0,
|
|
|
|
|
width: "100%",
|
|
|
|
|
height: "100%",
|
|
|
|
|
opacity: 0,
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
<a style={{ color: "#000", fontSize: "12px" }}>
|
|
|
|
|
{" "}
|
|
|
|
|
Upload Sheet{" "}
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-01-28 15:59:11 +05:30
|
|
|
)}
|
|
|
|
|
{fileLoading && (
|
|
|
|
|
<div style={{ textAlign: "center", marginTop: "1rem" }}>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
border: "4px solid #f3f3f3",
|
|
|
|
|
borderTop: "4px solid #3498db",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
width: "40px",
|
|
|
|
|
height: "40px",
|
|
|
|
|
animation: "spin 2s linear infinite",
|
|
|
|
|
margin: "0 auto",
|
|
|
|
|
}}
|
|
|
|
|
></div>
|
|
|
|
|
<p style={{ marginTop: "0.5rem", color: "#666" }}>
|
|
|
|
|
Processing file...
|
|
|
|
|
</p>
|
|
|
|
|
<style>{`
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
0% { transform: rotate(0deg); }
|
|
|
|
|
100% { transform: rotate(360deg); }
|
|
|
|
|
}
|
|
|
|
|
`}</style>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-01-27 18:27:29 +05:30
|
|
|
</>
|
|
|
|
|
)}
|
2026-01-28 15:59:11 +05:30
|
|
|
{uploadedData && uploadedData?.length > 0 && !loading ? (
|
|
|
|
|
<div
|
|
|
|
|
className="viewerExcelupload"
|
|
|
|
|
style={{ maxHeight: "90vh", overflowX: "auto" }}
|
|
|
|
|
>
|
2026-01-27 18:27:29 +05:30
|
|
|
<Form ref={excelDataRef} onFinish={handleSubmit}>
|
2026-01-28 15:59:11 +05:30
|
|
|
<div className="pricechangedata">
|
|
|
|
|
<Table
|
|
|
|
|
columns={columns}
|
|
|
|
|
rowKey={(record) => record.localId}
|
|
|
|
|
// components={components}
|
|
|
|
|
// bordered
|
|
|
|
|
dataSource={uploadedData}
|
|
|
|
|
// className="tableExcelUpload"
|
|
|
|
|
// onChange={handleTableChange}
|
|
|
|
|
className="price-change-data"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
<div
|
|
|
|
|
className="cancel-link"
|
|
|
|
|
onClick={handleCancelData}
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
gap: ".5rem",
|
|
|
|
|
padding: "0.3rem 0.4rem",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
backgroundColor: "ghostwhite",
|
|
|
|
|
width: "max-content",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
2026-01-28 15:59:11 +05:30
|
|
|
<FiDelete style={{ fontSize: "20px", color: "#1292EE" }} />
|
|
|
|
|
<a style={{ color: "#000" }}> Remove File</a>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
2026-01-28 15:59:11 +05:30
|
|
|
display: "flex",
|
|
|
|
|
justifyContent: "flex-end",
|
|
|
|
|
gap: "1rem",
|
|
|
|
|
marginTop: "1rem",
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="Submit"
|
|
|
|
|
color="901D77"
|
2026-01-28 15:59:11 +05:30
|
|
|
placement={"right"}
|
2026-01-27 18:27:29 +05:30
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
disabled={addnewAccess}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
2026-01-28 15:59:11 +05:30
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<p></p>
|
|
|
|
|
)}
|
|
|
|
|
{loading && (
|
|
|
|
|
<div style={{ textAlign: "center", marginTop: "1rem" }}>
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
border: "4px solid #f3f3f3",
|
|
|
|
|
borderTop: "4px solid #3498db",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
width: "40px",
|
|
|
|
|
height: "40px",
|
|
|
|
|
animation: "spin 2s linear infinite",
|
|
|
|
|
margin: "0 auto",
|
|
|
|
|
}}
|
|
|
|
|
></div>
|
|
|
|
|
<p style={{ marginTop: "0.5rem", color: "#666" }}>
|
|
|
|
|
Submitting...
|
|
|
|
|
</p>
|
|
|
|
|
<style>{`
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
0% { transform: rotate(0deg); }
|
|
|
|
|
100% { transform: rotate(360deg); }
|
|
|
|
|
}
|
|
|
|
|
`}</style>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<DefaultModal
|
|
|
|
|
open={excelFieldSetup}
|
|
|
|
|
handleCancel={() => setExcelFieldSetup(false)}
|
|
|
|
|
footer={false}
|
|
|
|
|
title={"Select the columns you want to include in the sheet"}
|
|
|
|
|
children={
|
|
|
|
|
<div className="field-setup-container">
|
|
|
|
|
{/* <div className="field-setup-header">
|
|
|
|
|
<FormHeader title={'Select the fields you want to include in the table'} />
|
|
|
|
|
</div> */}
|
|
|
|
|
<div className="field-setup-content">
|
|
|
|
|
<Form onFinish={handleFieldSetupSubmit} ref={formRef}>
|
|
|
|
|
<Form.Item name="fields">
|
|
|
|
|
<DropDowns
|
|
|
|
|
label="Select fields"
|
|
|
|
|
// valueData={selectedFields}
|
|
|
|
|
onChangeFunction={handleFieldSelect}
|
|
|
|
|
options={tableExcelFieldPreferences?.filter(
|
|
|
|
|
(p) =>
|
|
|
|
|
!selectedExcelFields?.some((s) => s === p.value),
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<div className="field-setup-selected-fields">
|
|
|
|
|
{selectedExcelFields
|
|
|
|
|
?.map((id) =>
|
|
|
|
|
tableExcelFieldPreferences?.find(
|
|
|
|
|
(p) => p.value === id,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
.map((field) => (
|
|
|
|
|
<div className="selected-field" key={field.value}>
|
|
|
|
|
<div>{field.label}</div>
|
|
|
|
|
<div
|
|
|
|
|
className="close-icon"
|
|
|
|
|
onClick={() => handleFieldRemove(field.value)}
|
|
|
|
|
>
|
|
|
|
|
<IoClose size={15} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
style={{ display: "flex", justifyContent: "flex-end" }}
|
|
|
|
|
>
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="SUBMIT"
|
|
|
|
|
color="901D77"
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
htmlType={true}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-01-27 18:27:29 +05:30
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
<DefaultModal
|
|
|
|
|
open={priceChangeModalOpen}
|
|
|
|
|
title={
|
2026-01-28 15:59:11 +05:30
|
|
|
<p style={{ fontSize: "18px" }}>Stock/Variant Based Price Change?</p>
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
footer={true}
|
|
|
|
|
width={500}
|
|
|
|
|
handleCancel={() => setPriceChangeModalOpen(false)}
|
|
|
|
|
handleSubmit={() => handleExport(stockVariantBased)}
|
|
|
|
|
children={
|
2026-01-28 15:59:11 +05:30
|
|
|
<div style={{ padding: "0.1rem 0" }}>
|
2026-01-27 18:27:29 +05:30
|
|
|
<RadioGrpButton
|
|
|
|
|
content={[
|
2026-01-28 15:59:11 +05:30
|
|
|
{ value: "Yes", label: "Yes" },
|
|
|
|
|
{ value: "No", label: "No" },
|
2026-01-27 18:27:29 +05:30
|
|
|
]}
|
|
|
|
|
fieldState={true}
|
|
|
|
|
defaultSelect={stockVariantBased}
|
|
|
|
|
onSelectFuntion={(e) => setStockVariantBased(e)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-01-28 15:59:11 +05:30
|
|
|
<DefaultModal
|
|
|
|
|
open={fieldSetup}
|
|
|
|
|
handleCancel={() => setFieldSetup(false)}
|
|
|
|
|
footer={false}
|
|
|
|
|
title={"Select the fields you want to include in the table"}
|
|
|
|
|
children={
|
|
|
|
|
<div className="field-setup-container">
|
|
|
|
|
{/* <div className="field-setup-header">
|
|
|
|
|
<FormHeader title={'Select the fields you want to include in the table'} />
|
|
|
|
|
</div> */}
|
|
|
|
|
<div className="field-setup-content">
|
|
|
|
|
<Form onFinish={handleFieldSetupSubmit} ref={formRef}>
|
|
|
|
|
<Form.Item name="fields">
|
|
|
|
|
<DropDowns
|
|
|
|
|
label="Select fields"
|
|
|
|
|
// valueData={selectedFields}
|
|
|
|
|
onChangeFunction={handleFieldSelect}
|
|
|
|
|
options={tableFieldPreferences?.filter(
|
|
|
|
|
(p) => !selectedFields?.some((s) => s === p.value),
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<div className="field-setup-selected-fields">
|
|
|
|
|
{selectedFields
|
|
|
|
|
?.map((id) =>
|
|
|
|
|
tableFieldPreferences?.find((p) => p.value === id),
|
|
|
|
|
)
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
.map((field) => (
|
|
|
|
|
<div className="selected-field" key={field.value}>
|
|
|
|
|
<div>{field.label}</div>
|
|
|
|
|
<div
|
|
|
|
|
className="close-icon"
|
|
|
|
|
onClick={() => handleFieldRemove(field.value)}
|
|
|
|
|
>
|
|
|
|
|
<IoClose size={15} />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
|
|
|
|
<Buttons
|
|
|
|
|
buttonText="SUBMIT"
|
|
|
|
|
color="901D77"
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
htmlType={true}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default StockPriceUpdate;
|