import React, { useEffect, useState, useRef, useContext, useCallback, } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Select, Tooltip } from "antd"; import { Form, Input, Table } from "antd"; import { EditFilled, DeleteFilled, ArrowRightOutlined, } from "@ant-design/icons"; import { PutStockPrice, bulkPriceUpdate, getStockNames, } from "../../Features/StockPriceUpdate/StockPriceUpdateMaster"; import { dateFormatChange, ExtractDateFormate, getSession, } 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"; import { changeBreadCrumb, getEmpAccess, } 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"; import { emptyExcelData, fileInputRefSelector, } from "../../Features/ExcelUploadPage/ExcelUploadPage.js"; const subDirectory = import.meta.env.BASE_URL; 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"; import { getFieldSetupData, postFieldSetup, } from "../../Features/ProductPage/ProductPage.js"; import { ApplicationPreferences, getCommonAppPreference, } from "../../Features/BrachLogin/BranchLogin.js"; import { IoClose } from "react-icons/io5"; const StockPriceUpdate = () => { const { SadminuserAccess } = useAuth(); let SAAccessCommonMaster = SadminuserAccess?.find( (e) => e?.MenuName === "Price Change", ); const ApplicationPreferenceData = useSelector(ApplicationPreferences); const categoryId = ApplicationPreferenceData?.find( (p) => p?.PreferredCatName?.toLowerCase() === "price change fields", )?.PreferredCatId; const excelCategoryId = ApplicationPreferenceData?.find( (p) => p?.PreferredCatName?.toLowerCase() === "price change sheet fields", )?.PreferredCatId; const fileInputRef = useRef(fileInputRefSelector); const excelDataRef = useRef(null); const formRef = useRef(null); const allowedExcelTypes = [ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // .xlsx "application/vnd.ms-excel", // .xls ]; const dispatch = useDispatch(); const [selectedFields, setSelectedFields] = useState([]); const [selectedExcelFields, setSelectedExcelFields] = useState([]); const [tableFieldPreferences, setTableFieldPreferences] = useState([]); const [tableExcelFieldPreferences, setTableExcelFieldPreferences] = useState( [], ); const [messageType, setMessageType] = useState(null); const [messageData, setMessageData] = useState(null); const [StockNames, setStockNames] = useState([]); const [ProductName, setProductName] = useState(null); const [fieldSetup, setFieldSetup] = useState(false); const [excelFieldSetup, setExcelFieldSetup] = useState(false); const [StockDetails, setStockDetails] = useState([]); const [dataSource, setDataSource] = useState([]); const [sortedInfo, setSortedInfo] = useState({}); const [BulksortedInfo, setBulksortedInfo] = useState({}); const [searchedText, setSearchedText] = useState(""); const [BulksearchedText, setBulksearchedText] = useState(""); 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); const [stockVariantBased, setStockVariantBased] = useState("Yes"); const [exportLoading, setExportLoading] = useState(false); const [fileLoading, setFileLoading] = useState(false); const [loading, setLoading] = useState(false); const [headers, setHeaders] = useState([]); const [uploadedData, setUploadedData] = useState([]); const CompId = getSession("CompId"); const BranchId = getSession("BranchId"); const AppId = getSession("AppId"); const UserId = getSession("UserId"); const UserType = getSession("UserType"); const [empData, setEmpData] = useState(); const [addnewAccess, setaddnewAccess] = useState(true); const [RadioSelection, setRadioSelection] = useState("Single"); const [BulkProductData, setBulkProductData] = useState([]); const [allowDecimal, setAllowDecimal] = useState(false); 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", ); const items = [ { name: "Home", link: `${subDirectory}app-page/home`, }, ]; const handleRemoveRecord = (index) => { setUploadedData((prev) => prev.filter((_, i) => i !== index)); }; const columns = [ { title: "Product Name", dataIndex: "ProductName", key: "ProductName", width: 180, render: (value, record, index) => (

{`${value} (${record?.Size} ${record?.UOMName})`}

), }, { title: "Variant Name", dataIndex: "VariantName", key: "VariantName", width: 180, }, { title: "Batch No", dataIndex: "BatchRef", key: "BatchRef", width: 180, }, ...(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, }, ] : []), // ✅ EDITABLE { title: "New MRP", dataIndex: "NewMRP", key: "NewMRP", width: 120, render: (_, record, index) => ( handlePriceChange(index, "NewMRP", e.target.value, record.localId) } onInput={(e) => { let cleanedValue = e.target.value.replace(/[^0-9.]/g, ""); if (cleanedValue.startsWith(".")) { cleanedValue = "0" + cleanedValue; } const parts = cleanedValue.split("."); e.target.value = parts.length > 2 ? `${parts[0]}.${parts.slice(1).join("")}` : cleanedValue; }} /> ), }, { title: "New SP", dataIndex: "NewSellPrice", key: "NewSellPrice", width: 120, render: (_, record, index) => ( ({ validator(_, value) { const mrp = getFieldValue(`NewMRP${record.localId}`); if (mrp === undefined || mrp === null || mrp === "") { return Promise.resolve(); } const numMRP = Number(mrp); const numSP = value === undefined || value === null || value === "" ? null : Number(value); if (numSP === null) { return Promise.reject( new Error("New SP is required when New MRP is provided"), ); } if (numSP > numMRP) { return Promise.reject( new Error("New SP cannot be greater than New MRP"), ); } return Promise.resolve(); }, }), ]} > { 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; }} onChange={(e) => { { handlePriceChange( index, "NewSellPrice", e.target.value, record.localId, ); excelDataRef.current ?.validateFields([`NewSellPrice${record.localId}`]) .catch(() => { }); } }} /> ), }, ...(hasFieldExists("New Wholesale Price") ? [ { title: "New Wholesale Price", dataIndex: "NewWholeSalePrice", key: "NewWholeSalePrice", width: 160, render: (value, record, index) => ( 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; }} /> ), }, ] : []), { title: "Action", key: "action", width: 80, align: "center", render: (_, record, index) => ( handleRemoveRecord(index)} /> ), }, ]; useEffect(() => { dispatch(changeBreadCrumb({ items: items })); getPreference(); // if (UserType === "Employee") { // fetchApi() // } }, []); useEffect(() => { dispatch(getCommonAppPreference(AppId)); }, [AppId, dispatch]); useEffect(() => { if (UserType === "Employee") { fetchApi(); } }, [UserType]); 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); } }; useEffect(() => { let hasAccess = false; if (UserType === "Admin" || UserType === "Super Admin") { hasAccess = true; } else if (UserType === "Employee") { hasAccess = empData?.AddAccess === "Y"; } else if (UserType === "Super Admin User") { hasAccess = SAAccessCommonMaster?.AddAccess === "Y"; } 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( (item) => item.ConfigName === "Price Change", ); setEmpData(datas?.[0]); }; const EditableContext = React.createContext(null); const EditableRow = ({ index, ...props }) => { const [form] = Form.useForm(); return (
); }; const BulkEditableRow = ({ index, ...props }) => { const [form] = Form.useForm(); return (
); }; 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) { console.log("Save failed:", errInfo); } }; let childNode = children; if (editable) { childNode = editing ? ( value?.length > 10 ? Promise.reject("Max 10 characters allowed") : Promise.resolve(), }, ]} > { const cleanedValue = e.target.value.replace(/[^0-9.]/g, ""); const parts = cleanedValue.split("."); e.target.value = parts.length > 2 ? `${parts[0]}.${parts.slice(1).join("")}` : cleanedValue; }} /> ) : (
{/* {dataIndex === 'CurrentAmt' && Array.isArray(record[dataIndex]) ? record[dataIndex]?.map((item, index) => ( {item.CurrentAmt + '-' + item.CurrentAmt} )) : children} */}
); } return {childNode}; }; 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) { console.log("Save failed:", errInfo); } }; let childNode = children; if (editable) { childNode = editing ? ( value?.length > 10 ? Promise.reject("Max 10 characters allowed") : Promise.resolve(), }, ]} > { const cleanedValue = e.target.value.replace(/[^0-9.]/g, ""); const parts = cleanedValue.split("."); e.target.value = parts.length > 2 ? `${parts[0]}.${parts.slice(1).join("")}` : cleanedValue; }} /> ) : (
{/* {dataIndex === "CurrentAmt" && Array.isArray(record[dataIndex]) ? record[dataIndex]?.map((item, index) => ( {item.CurrentAmt + "-" + item.CurrentAmt} )) : children} */}
); } return {childNode}; }; 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) => setting?.SettingIdName?.toLowerCase() === "decimal" && setting?.SettingValue === "Y", ); 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}`, })), ); 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 if (field === "NewMRP") { currentRow.NewSellPrice = null; excelDataRef.current?.setFieldsValue({ [`NewSellPrice${localId}`]: null, }); } currentRow[field] = numValue; updated[rowIndex] = currentRow; return updated; }); // Validate New SP against New MRP if (field === "NewSellPrice" && numValue) { const currentRow = uploadedData[rowIndex]; const newMRP = currentRow?.NewMRP; if (newMRP && numValue > newMRP) { setMessageType("error"); setMessageData("New SP cannot be greater than New MRP"); return; } } excelDataRef.current?.setFieldsValue({ [`${field}${localId}`]: numValue, }); }; const statusFormatter = async (row) => { const updatedData = StockDetails?.filter( (item) => item?.InwardDtlId !== row?.InwardDtlId, ); setStockDetails(updatedData); }; let tableValue = StockNames?.[0]?.stockDetails; let DataSource = StockNames?.map((name, index) => ({ value: index + 1, label: name?.ProdName + "(" + (name?.Size + " " + name?.UOMName) + ")", 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 { setMessageType("error"); setMessageData("MRP is must be greater than or equal to selling price"); } } 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 { setMessageType("error"); setMessageData( "MRP is must be greater than or equal to selling price", ); } } 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) { if (amountStr == null) return allowDecimal ? "0.00" : "0"; const cleaned = String(amountStr).replace(/[^0-9.-]+/g, ""); const num = Number(cleaned); if (isNaN(num)) return allowDecimal ? "0.00" : "0"; return allowDecimal ? num.toFixed(2) : Math.round(num).toString(); } const columns2 = [ { title: "Sl.No", align: "center", key: "sno", width: "60px", render: (text, object, index) => ( {index + 1} ), }, { title: "Product Name", dataIndex: "ProdName", key: "ProdName", width: "20%", filteredValue: [searchedText], onFilter: (value, record) => { return String(record.ProdName) ?.toLowerCase() .includes(value?.toLowerCase()); }, sorter: (a, b) => a?.ProdName?.localeCompare(b.ProdName), sortOrder: sortedInfo.columnKey === "ProdName" ? sortedInfo.order : null, ellipsis: true, render: (_, record) => ( {record.ProdName} ({record.UOM} {record.UOMName}) ), }, { title: "stock Date", dataIndex: "InwardDate", key: "InwardDate", align: "right", width: "150px", render: (InwardDate) => InwardDate !== null ? ExtractDateFormate(InwardDate) : "-", }, { title: "Old MRP", dataIndex: "MRP", key: "MRP", align: "right", render: (MRP) => (safeRound(MRP) !== null ? safeRound(MRP) : "-"), }, { title: "Old Price", dataIndex: "SellPrice", key: "SellPrice", align: "right", render: (SellPrice) => safeRound(SellPrice) !== null ? safeRound(SellPrice) : "-", }, { title: "New MRP", dataIndex: "CurrentMRP", key: "CurrentMRP", align: "right", editable: true, render: (text, record) =>

{text ? text : "Enter MRP"}

, width: 100, }, { title: "New SP", dataIndex: "CurrentAmt", key: "CurrentAmt", align: "right", editable: true, render: (text, record) =>

{text ? text : "Enter Price"}

, width: 100, }, { title: "Action", dataIndex: "SellPrice", key: "SellPrice", align: "center", width: "100px", render: (_, record, index) => (
statusFormatter(record, index)} />
), }, ]; const BulkPricechangeColumns = [ { title: "Sl.No", align: "center", key: "sno", width: "50px", render: (text, object, index) => ( {(Bulkchangepage - 1) * 10 + index + 1} ), }, { title: "Name", dataIndex: "ProdName", key: "ProdName", width: "20%", filteredValue: [BulksearchedText], onFilter: (value, record) => { return String(record.ProdName) ?.toLowerCase() .includes(value?.toLowerCase()); }, sorter: (a, b) => a?.ProdName?.localeCompare(b.ProdName), sortOrder: BulksortedInfo.columnKey === "ProdName" ? BulksortedInfo.order : null, ellipsis: true, render: (_, record) => ( {record.ProdName} ({record.Size} {record.UOMName}) ), }, { title: "Variant Name", dataIndex: "ProdVariantName", key: "ProdVariantName", align: "left", width: "120px", }, { title: "Batch No", dataIndex: "BatchRef", key: "BatchRef", align: "left", width: "120px", }, ...(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) : "-", }, ] : []), { title: "New MRP", dataIndex: "CurrentMRP", key: "CurrentMRP", align: "center", with: "4rem", editable: true, render: (text, record) =>

{text ? text : "Enter MRP"}

, width: 100, }, { title: "New SP", dataIndex: "CurrentAmt", key: "CurrentAmt", align: "center", with: "4rem", editable: true, render: (text, record) =>

{text ? text : "Enter Price"}

, width: 100, }, ...(hasField("New Wholesale Price") ? [ { title: "New Wholesale Price", dataIndex: "CurrentWhAmt", key: "CurrentWhAmt", align: "center", with: "4rem", editable: true, render: (text, record) => (

{text ? text : "Enter Wholesale Price"}

), width: 120, }, ] : []), ]; 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( prevStockDetails?.map((item) => item.InwardDtlId), ); 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 () => { if (RadioSelection == "Bulk") { const filteredCurrentAmtData = BulkProductData?.filter( (item) => (item.CurrentAmt !== undefined && item.CurrentAmt !== null && item.CurrentAmt !== "" && item.CurrentMRP !== undefined && item.CurrentMRP !== null && item.CurrentMRP !== "") || (item.CurrentWhAmt !== undefined && item.CurrentWhAmt !== null && item.CurrentWhAmt !== ""), ); 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, Type: "Variant", ProductDetails: filteredCurrentAmtData?.map((item) => ({ ProdId: item?.ProdId, NewMRP: item?.CurrentMRP, NewSellPrice: item?.CurrentAmt, AdjComment: "string", InwardDtlId: item?.InwardDtlId, NewWholeSalePrice: item.CurrentWhAmt, })), }; let response = await dispatch(bulkPriceUpdate(Postdata)).unwrap(); if (response?.data?.statusCode == 1) { setProductName(); setMessageType("success"); setMessageData(response?.data?.response); fetchData(); setBulksearchedText(""); setStockDetails([]); setBulkProductData([]); } else { setMessageType("error"); setMessageData(response?.data?.response); } } else { setMessageType("error"); setMessageData("Please give all details"); } } else { const filteredStockDetails = StockDetails?.filter( (item) => item?.CurrentMRP && item?.CurrentMRP !== "" && item?.CurrentAmt && item?.CurrentAmt !== "", ); if (filteredStockDetails?.length === 0) { setMessageType("error"); setMessageData("Please enter price details for at least one product"); return; } let data = { CompId: CompId, BranchId: BranchId, ProductDetails: filteredStockDetails?.map((item) => ({ ProdId: item?.ProdId, MRP: item?.CurrentMRP, SellPrice: item?.CurrentAmt, AdjComment: "string", 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(); setMessageType("success"); setMessageData(response?.data?.response); fetchData(); } else { setMessageType("error"); 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); }; const handleExcelFieldSetup = () => { setExcelFieldSetup(true); }; const showPriceChangeModal = () => { setPriceChangeModalOpen(true); }; const handleExport = async (isStockVariantBased = "Yes") => { setExportLoading(true); setPriceChangeModalOpen(false); const uniqueBulkProductData = isStockVariantBased === "Yes" ? BulkProductData || [] : (BulkProductData || [])?.filter( (item, index, self) => index === self.findIndex((p) => p.ProdId === item.ProdId), ); if (!uniqueBulkProductData?.length) { setMessageType("error"); setMessageData("No data available to export"); setExportLoading(false); return; } const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet("Products"); /* ---------------- COLUMN DEFINITIONS ---------------- */ const columns = [ { 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 }] : []), ...(hasExcelField("Old MRP") ? [{ header: "Old MRP", key: "OldMRP", width: 10 }] : []), ...(hasExcelField("Old SP") ? [{ header: "Old SP", key: "OldSP", width: 10 }] : []), ...(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 }, ...(isStockVariantBased === "Yes" ? [{ header: "InwardDtlId", key: "InwardDtlId", width: 1 }] : []), { header: "key", key: "key", width: 1 }, { header: "downloadType", key: "downloadType", width: 1 }, ]; worksheet.columns = columns; worksheet.views = [{ state: "frozen", xSplit: 1, ySplit: 1 }]; const headerRow = worksheet.getRow(1); const newMRPCol = headerRow.values.indexOf("New MRP"); const newSPCol = headerRow.values.indexOf("New SP"); const hasNewMRPAndSP = newMRPCol > 0 && newSPCol > 0; /* ---------------- HEADER STYLE ---------------- */ worksheet.getRow(1).eachCell((cell) => { const header = cell.value; const isHiddenCol = header === "key" || header === "ProdId" || header === "InwardDtlId" || header === "downloadType"; cell.font = { bold: true, size: isHiddenCol ? 1 : 11, color: { argb: isHiddenCol ? "FFFFFFFF" : "FF000000" }, }; cell.alignment = { horizontal: "center", vertical: "middle", wrapText: true, // ✅ prevents overflow in header }; cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: isHiddenCol ? "FFFFFFFF" : "FF52C41A", }, }; cell.border = isHiddenCol ? undefined : { right: { style: "thin", color: { argb: "FF000000" } }, bottom: { style: "thin", color: { argb: "FF000000" } }, }; }); /* ---------------- ADD DATA ---------------- */ uniqueBulkProductData.forEach((product) => { worksheet.addRow({ ProdName: product?.ProdName, ProdVariantName: product?.ProdVariantName, BatchRef: product?.BatchRef, StockDate: product?.InwardDate, ExpDate: product?.ExpDate || "-", Stock: product?.BalanceQty, OldMRP: product?.MRP, OldSP: product?.SellPrice, WhSalePrice: product?.WhSalePrice, Size: product?.Size, StockAvailable: product?.StockAvailable, UOMName: product?.UOMName, key: product?.key, downloadType: isStockVariantBased === "Yes" ? "Variant" : "Product", NewMRP: "", NewSP: "", NewWhSalePrice: "", ProdId: product?.ProdId, InwardDtlId: isStockVariantBased === "Yes" ? product?.InwardDtlId : undefined, }); }); // ---------------- VALIDATION: New SP <= New MRP ---------------- 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", }; }); } /* ---------------- 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 = header === "key" || header === "ProdId" || header === "InwardDtlId" || header === "downloadType"; const isEditable = header === "New MRP" || header === "New SP" || header === "New Wholesale Price"; cell.protection = { locked: !isEditable }; cell.alignment = { vertical: "middle", wrapText: true, }; if (isHiddenCol) { cell.font = { size: 1, color: { argb: "FFFFFFFF" }, }; cell.fill = { type: "pattern", pattern: "solid", fgColor: { argb: "FFFFFFFF" }, }; } }); }); /* ---------------- PROTECT SHEET ---------------- */ await worksheet.protect("", { selectLockedCells: false, selectUnlockedCells: true, formatCells: false, formatColumns: false, insertRows: false, deleteRows: false, }); /* ---------------- DOWNLOAD ---------------- */ const buffer = await workbook.xlsx.writeBuffer(); const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.download = "PriceChange_Data.xlsx"; link.click(); setExportLoading(false); }; const handleClick = () => { fileInputRef.current.click(); }; const handleFileUpload = (e) => { setFileLoading(true); const file = e.target.files[0]; if (!file) { dispatch(emptyExcelData()); setFileLoading(false); return; } const isAllowed = allowedExcelTypes?.includes(file.type); if (!isAllowed) { Modal.error({ title: "Invalid File Type", content: "Only Excel files (.xls, .xlsx) are allowed.", }); handleCancelData(); setFileLoading(false); return; } const reader = new FileReader(); reader.onload = (event) => { const arrayBuffer = event.target.result; const extractedData = extractPriceChangeDataFromExcel(arrayBuffer); console.log(extractedData, "extractedData"); if ((extractedData || [])?.length === 0) { setMessageData("No Data Found in Uploaded Sheet"); setMessageType("error"); handleCancelData(); setFileLoading(false); return; } setUploadedData(extractedData); setFileLoading(false); // 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) => { const workbook = read(arrayBuffer, { type: "array" }); const worksheet = workbook.Sheets[workbook.SheetNames[0]]; const rows = utils.sheet_to_json(worksheet, { header: 1, raw: false, defval: "", }); if (!rows.length) return []; const header = rows[0]; setHeaders(header); const dataRows = rows.slice(1); // Helper to safely get column value const getVal = (row, colName) => { const idx = header.indexOf(colName); return idx !== -1 ? row[idx] : ""; }; const result = dataRows .map((row) => { const prodId = getVal(row, "ProdId")?.toString().trim(); if (!prodId) return null; const newMRP = getVal(row, "New MRP") !== "" ? Number(getVal(row, "New MRP")) : null; const newSP = getVal(row, "New SP") !== "" ? Number(getVal(row, "New SP")) : null; const newWholesale = getVal(row, "New Wholesale Price") !== "" ? Number(getVal(row, "New Wholesale Price")) : null; // ❌ Must have at least one change if (newMRP === null && newSP === null && newWholesale === null) { return null; } return { // 🔹 Product identity localId: uuidv4(), ProdId: prodId, InwardDtlId: getVal(row, "InwardDtlId") ? getVal(row, "InwardDtlId").toString() : null, // 🔹 Product info 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, // 🔹 Stock / dates StockDate: getVal(row, "Stock Date") || null, ExpDate: getVal(row, "Exp Date") || null, downloadType: getVal(row, "downloadType") || null, Stock: getVal(row, "Stock") !== "" ? Number(getVal(row, "Stock")) : null, // 🔹 Old prices OldMRP: getVal(row, "Old MRP") !== "" ? Number(getVal(row, "Old MRP")) : null, OldSP: getVal(row, "Old SP") !== "" ? Number(getVal(row, "Old SP")) : null, OldWholeSalePrice: getVal(row, "Old Wholesale Price") !== "" ? Number(getVal(row, "Old Wholesale Price")) : null, // 🔹 New prices (normalized) NewMRP: newMRP, NewSellPrice: newSP, NewWholeSalePrice: newWholesale, }; }) .filter(Boolean); return result; }; const handleCancelData = () => { dispatch(emptyExcelData()); if (fileInputRef.current) { fileInputRef.current.value = ""; } setUploadedData([]); }; const handleSubmit = async () => { try { setLoading(true); 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) { setMessageType("error"); setMessageData( "If New MRP is provided, New SP must also be provided", ); return; } // If SP is present, MRP must also be present if (newSP && !newMRP) { setMessageType("error"); setMessageData( "If New SP is provided, New MRP must also be provided", ); return; } // New SP cannot be greater than New MRP if (newMRP && newSP && parseFloat(newSP) > parseFloat(newMRP)) { setMessageType("error"); setMessageData("New SP cannot be greater than New MRP"); 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, AdjComment: "string", })); 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) { setMessageData(res?.data?.response || "Price Updated Successfully"); setMessageType("success"); setUploadedData([]); handleCancelData(); setExcelModalOpen(false); await fetchData(); } else { setMessageData(res?.data?.response); setMessageType("error"); } // If validation passes, proceed with submission console.log("Form validation passed", updatedData); } catch (error) { 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)); } }; return (
{RadioSelection == "Bulk" && (
} />
)}
{RadioSelection == "Single" && (
HandleStockNames(value, option) } style={{ width: "240px" }} options={DataSource} isOnchanges={ProductName ? true : false} />
)} {/* {RadioSelection == "Bulk" &&
} */}
onRadioChange(e)} />
{(RadioSelection == "Bulk" || (RadioSelection == "Single" && StockDetails.length > 0)) && (
} disabled={addnewAccess} >
)}
{RadioSelection == "Single" && (
)} {RadioSelection == "Bulk" && (
)}
{ setExcelModalOpen(false); handleCancelData(); }} width={uploadedData?.length > 0 ? 1200 : 600} children={ <> {uploadedData?.length === 0 && (
{ } : () => showPriceChangeModal() } >
Export Excel
)} {(!uploadedData || uploadedData?.length === 0) && ( <> {!fileLoading && (
{/* */}
)} {fileLoading && (

Processing file...

)} )} {uploadedData && uploadedData?.length > 0 && !loading ? (
record.localId} // components={components} // bordered dataSource={uploadedData} // className="tableExcelUpload" // onChange={handleTableChange} className="price-change-data" />
} disabled={addnewAccess} />
) : (

)} {loading && (

Submitting...

)} setExcelFieldSetup(false)} footer={false} title={"Select the columns you want to include in the sheet"} children={
{/*
*/}
!selectedExcelFields?.some((s) => s === p.value), )} />
{selectedExcelFields ?.map((id) => tableExcelFieldPreferences?.find( (p) => p.value === id, ), ) .filter(Boolean) .map((field) => (
{field.label}
handleFieldRemove(field.value)} >
))}
} htmlType={true} />
} /> } /> Stock/Variant Based Price Change?

} footer={true} width={500} handleCancel={() => setPriceChangeModalOpen(false)} handleSubmit={() => handleExport(stockVariantBased)} children={
setStockVariantBased(e)} />
} /> setFieldSetup(false)} footer={false} title={"Select the fields you want to include in the table"} children={
{/*
*/}
!selectedFields?.some((s) => s === p.value), )} />
{selectedFields ?.map((id) => tableFieldPreferences?.find((p) => p.value === id), ) .filter(Boolean) .map((field) => (
{field.label}
handleFieldRemove(field.value)} >
))}
} htmlType={true} />
} /> ); }; export default StockPriceUpdate;