import React, {
useState,
useEffect,
useRef,
useContext,
useCallback,
useMemo,
} from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import {
ArrowRightOutlined,
PlusCircleOutlined,
SearchOutlined,
} from '@ant-design/icons';
import { Form, Tooltip, Table, Input, AutoComplete, Switch, Checkbox } from 'antd';
import { IoAddCircleSharp } from 'react-icons/io5';
import { InputField } from '../../Components/Forms/InputField.jsx';
import Buttons from '../../Components/Forms/Buttons.jsx';
import { Modal } from 'antd';
import { Messages } from '../../Components/Notifications/Messages.jsx';
import { DeleteFilled } from '@ant-design/icons';
import { changeBreadCrumb } from '../../Features/AppPage/CenterPage.js';
import FormHeader from '../PageComponents/FormHeader.jsx';
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
import { getSession, validateSafeInput } from '../../Services/Others.js';
import { DatePicProd } from '../../Components/Forms/DatePickerProduct.jsx';
import { RadioGrpButton } from '../../Components/Forms/RadioGroup.jsx';
import moment from 'moment';
import { DropDowns } from '../../Components/Forms/DropDown.jsx';
import { BsUpcScan } from 'react-icons/bs';
import { debounce } from 'lodash';
import {
getProductData,
getSupplierData,
getPurchaseTypeData,
getPurchaseTaxTypeData,
postPurchaseData,
putStockData,
} from '../../Features/StockMaster/StockMaster.js';
import '../../Styles/Stock/StockMaster.scss';
import {
getAdmin,
getUomData,
getProdCatData,
uomDataSelector,
postSupplier,
getProductTypeData,
bulkpostdata,
postFieldSetup,
getFieldSetupData,
} from '../../Features/ProductPage/ProductPage.js';
import SupplierProductMappingForm from '../SupplierProductMapping/SuplierProductMappingForm.jsx';
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
import FloatLabel from '../../Components/Forms/FloatLabel/index.jsx';
import { FaLink, FaEye } from 'react-icons/fa';
import { TbUpload } from 'react-icons/tb';
import {
getSupplaierIdBasedProducts,
getSupplaierIdwithTypeBasedProducts,
postSupplaierProducts,
} from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
import {
ApplicationPreferences,
getCommonAppPreference,
} from '../../Features/BrachLogin/BranchLogin.js';
import {
getConfigType,
getPaymentOptionFeatureApi,
PendingOrdersPE,
} from '../../Features/BookingScreen/BookingData/BookingData.js';
import InvoiceImageExtractorModal from './InvoiceImageExtractor.jsx';
import { v4 as uuidv4 } from 'uuid';
import AddAllProductsButton from './AddAllProductGrid.jsx';
import SettingsIconWithModal from './SettingsIconWithModal.jsx';
import VirtualizedTable from './VirtualizedTable.jsx';
import { useDebounce } from './UseDebounce.jsx';
const subDirectory = import.meta.env.BASE_URL;
const EditableContext = React.createContext(null);
const EditableRow = ({ 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 ? (
) : (
);
}
return {childNode} | ;
};
const StockForm = ({ formType }) => {
console.log('counttesttttttttttttttttttt');
const formRef = useRef(null);
const productAddInfoRef = useRef(null);
const formProductRef = useRef(null);
const formSupplierRef = useRef(null);
const dispatch = useDispatch();
const navigate = useNavigate();
const location = useLocation();
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState('');
const [index, setindex] = useState();
const state = location?.state;
const editstate = state?.editstate;
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const AppId = getSession('AppId');
const UserId = getSession('UserId');
const UomData = useSelector(uomDataSelector);
const appPreferences = useSelector(ApplicationPreferences);
const [applicationRestrictedFields, setApplicationRestrictedFields] =
useState({
DatesAndExpiry: false,
BatchAndModelDetails: false,
AmountPerPieceDetail: false,
});
const [editingQty, setEditingQty] = useState({});
const [selectedAdditionalColumn, setSelectedAdditionalColumn] = useState([]);
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
const [SupplierData, setSupplierData] = useState([]);
const [SupplierOpen, setSupplierOpen] = useState('own');
const [purchaseOrderList, setPurchaseOrderList] = useState([]);
const [selectedSupplierName, setSelectedSupplierName] = useState();
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const [searchText, setSearchText] = useState(null);
const [productSearchText, setProductSearchText] = useState('');
const [selectedInvoice, setSelectedInvoice] = useState(null);
const [orderType, setOrderType] = useState(true);
const [PurchaseTypeData, setPurchaseTypeData] = useState(null);
const [SelectedPurchaseType, setSelectedPurchaseType] = useState(null);
const [SelectedPurcTaxType, setSelectedPurcTaxType] = useState(null);
const [PurchaseData, setPurchaseData] = useState([]);
const [additionalInfoModal, setAdditionalInfoModal] = useState(false);
const [selectedRowIndex, setSelectedRowIndex] = useState(null);
const [selectedRowRecord, setSelectedRowRecord] = useState({});
const [purchaseOrderId, setPurchaseOrderId] = useState();
const [selectedProductName, setSelectedProductName] = useState(null);
const [scanner, setScanner] = useState(false);
const [Delete, setDelete] = useState(false);
const [selectedSupplierData, setSelectedSupplierData] = useState(null);
const [inwardDate, setInwardDate] = useState(new Date().toJSON());
const [SuppInvoiceDate, setSuppInvoiceDate] = useState();
const [invoiceType, setInvoiceType] = useState('I');
const [PurchaseDate, setPurchaseDate] = useState();
const [paymentAmount, setPaymentAmount] = useState(null);
const [OpenSupplierModel, setOpenSupplierModel] = useState(false);
const [zipCodeData, setZipCodeData] = useState(false);
const [imeiSerialOpen, setimeiSerialOpen] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [dataSourceBackup, setDataSourceBackup] = useState([]);
const [purchaseStatus, setPurchaseStatus] = useState('P');
const [isModalOpen, setIsModalOpen] = useState(false);
const [productData, setProductData] = useState([]);
const [message, setMessage] = useState({ type: null, data: null });
const [initialLoad, setInitialLoad] = useState(true);
const [deliveryPerformanceData, SetDeleveryPerformanceData] = useState([]);
const [DiscountData, setDiscountData] = useState([]);
const [QualityData, setQualityData] = useState([]);
const [Delivery, setDeliveryValue] = useState();
const [DicountValue, setDicountValue] = useState();
const [QualityValue, setQualityValue] = useState();
const [ViewDtl, setViewDtl] = useState(false);
const [paymentOptions, setPaymentOptions] = useState([]);
const [selectedPaymentMode, setSelectedPaymentMode] = useState(null);
const [payAmountDisable, setPayAmountDisable] = useState(
paymentOptions
?.find((option) => option?.ModeId === selectedPaymentMode)
?.ModeName?.toLowerCase() === 'credit'
);
const [extractorModalVisible, setExtractorModalVisible] = useState(false);
const [extractorData, setExtractorData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [loadingText, setLoadingText] = useState('');
// const [filteredPurchaseData, setFilteredPurchaseData] = useState([]);
const [searchValue, setSearchValue] = useState('');
const isSearching = Boolean(searchValue?.trim());
const [showAllSuppliers, setShowAllSuppliers] = useState(false);
const SelInvoiceAmount = useMemo(() => {
const total = PurchaseData?.reduce(
(acc, item) => acc + Number(item?.Amount || 0),
0
);
return !isNaN(total) && total !== 0 ? total : null;
}, [PurchaseData]);
const TotalTaxAmount = useMemo(() => {
return PurchaseData?.reduce(
(acc, item) => acc + Number(item?.TaxAmt || 0),
0
);
}, [PurchaseData]);
const filteredPurchaseData = useMemo(() => {
if (!searchValue?.trim()) return PurchaseData;
return PurchaseData.filter((item) =>
item?.ProdName?.toLowerCase().includes(searchValue.toLowerCase())
);
}, [PurchaseData, searchValue]);
const items = [
{
name: 'Home',
link: `${subDirectory}app-page/home`,
},
{
name: 'Product Receipt',
link: `${subDirectory}setting/purchase-entry`,
},
{
name: editstate ? 'Edit' : 'New',
link: null,
},
];
const categoryId = appPreferences?.find(
(p) => p?.PreferredCatName?.toLowerCase() === 'purchase entry'
)?.PreferredCatId;
useEffect(() => {
dispatch(changeBreadCrumb({ items: items }));
dispatch(
getProductData({ CompId: CompId, AppId: AppId, BranchId: BranchId })
).unwrap();
dispatch(getProductTypeData());
dispatch(getAdmin({ AppId: AppId, CompId: CompId }));
dispatch(getProdCatData({ AppId: AppId }));
dispatch(getUomData());
applicationApplicableFields();
getPurchaseType();
getPurchaseTaxType();
deliveryPerformance();
discountLevel();
qualityofSupp();
getSuplaierApi({ Type: null });
if (formType == 'add') {
formRef.current?.setFieldsValue({ SuppInvoiceDate: new Date().toJSON() });
setSuppInvoiceDate(new Date().toJSON());
formRef.current?.setFieldsValue({ InvoiceDate: new Date().toJSON() });
// setInvoiceDate(new Date().toJSON());
formRef.current?.setFieldsValue({ DueDate: new Date().toJSON() });
setPurchaseDate(new Date().toJSON());
formRef.current?.setFieldsValue({ InvoiceDate: new Date().toJSON() });
formRef.current?.setFieldsValue({ OrderType: 'N' });
}
if (formType == 'edit') {
formRef.current?.setFieldsValue({
ProdId: editstate?.ProdId,
ProdVariantName: editstate?.ProdVariantName,
SuppId: editstate?.SuppId,
InwardDate: editstate?.InwardDate + 'T00:00:00',
});
if (applicationRestrictedFields.DatesAndExpiry) {
formRef.current?.setFieldsValue({
ManufDate: editstate?.ManufDate,
ExpDate: editstate?.ExpDate,
});
}
handleSupplierBasedProduct(editstate?.SuppId);
// setSelectedProductData(editstate?.ProdId);
setSelectedSupplierData(editstate?.SuppId);
}
}, []);
useEffect(() => {
if (SupplierOpen !== 'own') {
getPurchaseOrders();
fetchPaymentOptions();
}
}, [SupplierOpen]);
useEffect(() => {
getFieldSetup();
}, [categoryId]);
useEffect(() => {
if (initialLoad && SupplierData?.length > 0) {
SetSelfSupplier();
setInitialLoad(false);
}
}, [SupplierData]);
useEffect(() => {
if (extractorData && selectedSupplierData) {
if (
extractorData?.invoiceNo !== null &&
extractorData?.invoiceNo !== ''
) {
formRef?.current?.setFieldsValue({
SuppInvoiceNo: extractorData?.invoiceNo,
});
}
formRef?.current?.setFieldsValue({
PaymentAmount: extractorData?.TotalAmtData,
});
setPaymentAmount(extractorData?.TotalAmtData);
onSuppInvoiceDateChange(
extractorData?.date,
extractorData?.date?.format('DD-MM-YYYY') || ''
);
}
}, [selectedSupplierData]);
useEffect(() => {
return () => {
debouncedScannerSearch.cancel();
};
}, []);
const SetSelfSupplier = async () => {
let SupplierId = SupplierData?.filter(
(item) => item.SuppName?.toLowerCase() === 'self'
)?.[0]?.['SuppId'];
let SupplierName = SupplierData?.filter(
(item) => item.SuppName?.toLowerCase() === 'self'
)?.[0]?.['SuppName'];
formRef.current?.setFieldsValue({ CustSuppId: SupplierId });
setSelectedSupplierData(SupplierId);
handleSupplierBasedProduct(SupplierId);
SupplierName === 'Self'
? setSelectedSupplierName(false)
: setSelectedSupplierName(true);
};
const getSuplaierApi = async ({ dataReturn = false, Type = null }) => {
const response = await dispatch(
getPurchaseSupplierAndWareHouseData({ CompId, AppId, BranchId, Type })
).unwrap();
if (response?.statusCode === 1) {
setSupplierData(response?.data);
if (dataReturn) {
return response?.data;
}
} else {
setSupplierData([]);
if (dataReturn) {
return [];
}
}
};
const getPurchaseOrders = async () => {
const { data: res } = await dispatch(
PendingOrdersPE({ CompId, AppId, BranchId })
).unwrap();
if (res?.statusCode === 1) {
setPurchaseOrderList(
res?.data?.PurchaseOrder?.map((item) => ({
...item,
localId: uuidv4(),
}))
);
} else {
setPurchaseOrderList([]);
setMessageType('error');
setMessageData('No pending purchase orders found.');
}
};
const fetchPaymentOptions = async () => {
try {
const response = await dispatch(
getPaymentOptionFeatureApi({ CompId, BranchId, AppId })
).unwrap();
if (response?.data?.statusCode === 1) {
const paymentDetails = response?.data?.data?.[0]?.PaymentDetails?.find(
(item) => item.FlowName === 'Sales'
)?.OptionDetails?.[0]?.ModeDetails?.filter(
(filter) =>
filter.ModeName?.toLowerCase() === 'cash' ||
filter.ModeName?.toLowerCase() === 'upi' ||
filter.ModeName?.toLowerCase() === 'credit'
);
setPaymentOptions(paymentDetails);
const modeId = paymentDetails?.find(
(item) => item.ModeName === 'Cash'
)?.ModeId;
setSelectedPaymentMode(modeId);
formRef.current?.setFieldsValue({ PaymentMode: modeId });
}
} catch (error) {
setMessage({
type: 'error',
data: error?.message || 'Failed to fetch payment options.',
});
}
};
const findMatchingSuppliers = async (name, mobile, supplierData) => {
let list = [];
if (mobile) {
const m = mobile;
list = supplierData.filter((x) =>
(x.SuppMobile || '').toString().includes(m)
);
}
// 2️⃣ If no mobile match or mobile empty → fallback to name
if (name) {
const n = name?.trim().toLowerCase(); // 🔥 trimmed + lowercase
list = supplierData.filter(
(x) => (x.SuppName || '').trim().toLowerCase() === n // 🔥 safe compare
);
}
let finalList = list?.length > 0 ? [list[0]] : [];
const mappedSupplierProducts = await handleSupplierDropDownChange(
finalList?.[0]?.SuppId,
null,
supplierData
);
return { mappedSupplierProducts, SuppId: finalList?.[0]?.SuppId };
};
const getFieldSetup = async () => {
try {
const response = await dispatch(
getFieldSetupData({ AppId, CompId, BranchId, categoryId, Type: 'PE' })
).unwrap();
if (response?.data?.statusCode === 1) {
setSelectedAdditionalColumn(
response?.data?.data?.[0]?.ConfigDtl?.filter(
(c) => c.ConfigId && c.Access === 'Y'
)?.map((c) => c.ConfigName) || []
);
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 AddSupplierimg = async (subSupplierData) => {
const addSupplierData = {
CompId: CompId,
AppId: AppId,
BranchId: BranchId,
SuppName: subSupplierData?.SuppName,
SuppGSTIN: subSupplierData?.SuppGSTIN,
SuppPOC: subSupplierData?.SuppPOC,
SuppMobile: subSupplierData?.SuppMobile,
SuppEmail: subSupplierData?.SuppEmail,
Address1: subSupplierData?.Address1,
Address2: subSupplierData?.Address1,
Zip: subSupplierData?.Zip,
City: subSupplierData?.City,
State: subSupplierData?.State,
Dist: subSupplierData?.Dist,
CreatedBy: UserId,
};
let response = {};
response = await dispatch(postSupplier(addSupplierData)).unwrap();
if (response?.data?.statusCode == 1) {
setMessageType('success');
setMessageData(response?.data?.response);
let response1 = await dispatch(
getSupplierData({
CompId: CompId,
AppId: AppId,
BranchId: BranchId,
ActiveStatus: 'A',
})
).unwrap();
const suppliers = await getSuplaierApi({ dataReturn: true });
if (response1?.data?.statusCode == 1) {
setZipCodeData(null);
const mappedSupplierProducts = await findMatchingSuppliers(
subSupplierData?.SuppName,
subSupplierData?.SuppMobile,
suppliers
);
return mappedSupplierProducts;
}
} else {
setMessageType('error');
setMessageData(response?.data?.response);
return { mappedSupplierProducts: null, SuppId: null };
}
};
const handleExtractorApply = async (data) => {
setIsLoading(true);
setLoadingText('Processing extracted data...');
setExtractorData(data);
let supplierProducts = [];
let suppId = null;
if (data?.supplierSuggestions?.length > 0) {
setLoadingText('Loading supplier products...');
supplierProducts = await handleSupplierDropDownChange(
data?.supplierSuggestions?.[0]?.SuppId
);
suppId = data?.supplierSuggestions?.[0]?.SuppId;
}
if (data?.supplierSuggestions?.length === 0) {
setLoadingText('Creating new supplier...');
const Address = await getPincodeValues(data?.pincode);
let suppdata = {
SuppName: data?.name,
SuppMobile: data?.mobile,
SuppGSTIN: data?.gst,
Zip: data?.pincode,
City: Address?.City || '.',
State: Address?.State || '.',
Dist: Address?.Dist || '.',
Address1: data?.address || '.',
};
const { mappedSupplierProducts, SuppId } = await AddSupplierimg(suppdata);
suppId = SuppId;
supplierProducts = mappedSupplierProducts;
}
// check if the products from extractor exist in the supplier's products
setLoadingText('Matching products with supplier...');
let matchedProducts = data?.products?.map((imgItem) => {
const match = supplierProducts?.find(
(supp) =>
supp?.ProdName?.toLowerCase() === imgItem?.description?.toLowerCase()
);
return {
selectedProduct: match || null,
parsedData: imgItem,
matchFound: !!match,
selectedProdId: match?.ProdId || null,
};
});
const unmatchedProducts = matchedProducts.filter(
(item) => !item.matchFound
);
if (unmatchedProducts?.length > 0) {
setLoadingText('Mapping unmatched products...');
const response = await dispatch(
getSupplaierIdBasedProducts({ CompId, AppId, BranchId, SuppId: suppId })
).unwrap();
if (response?.data?.statusCode === 1) {
const allSupplierProducts = response?.data?.data || [];
const matchingProdIds = [];
const NewImageProducts = [];
console.log(unmatchedProducts, 'unmatchedProductsunmatchedProducts');
// check if the unmatched products exists in our products list
unmatchedProducts.forEach((item) => {
const match = allSupplierProducts?.[0]?.ProductDetails.find(
(supp) =>
supp?.ProdName?.toLowerCase() ===
item?.parsedData?.description?.toLowerCase()
);
if (match) {
matchingProdIds.push(match.ProdId);
} else {
NewImageProducts.push(item?.parsedData);
}
});
// Bulk upload new image products
if (NewImageProducts.length > 0) {
const newProductsData = NewImageProducts.map((product) => ({
AppId: AppId || 0,
CompId: CompId || '',
BranchId: BranchId || '',
CreatedBy: UserId || 0,
ProdName: product.description?.trim() || '',
ProdVariantName: '',
Size: 1 || '',
UOM: product.unit || '',
MRP: parseFloat(product.rate) || 0,
WhSalePrice: 0,
SellPrice: parseFloat(product.rate) || 0,
ProdCat: 'General',
ProdSubCat: '',
Brand: '',
AutoGenerateQr: '',
QRCode: '',
StockAvailable: 'No',
HSNCode: '',
PartNumber: '',
Rack: 0,
ManufDate: '',
ExpDate: '',
AvailableFrom: '',
AvailableTo: '',
ProdLogo: '',
OnePcsAvailable: 'No',
AutoGenerateSingleQr: 'No',
TaxId: 'NIL - 0%',
OnePcQR: '',
TokenAvailable: 'No',
OpeningQty: 0,
QtyBasedPrice: '',
InwardDate: '',
SuppId: suppId || '',
Reference: '',
ReceivedQty: 0,
AcceptedQty: 0,
RejectedQty: 0,
RejectionReason: '',
IssuedQty: 0,
BalanceQty: 0,
InwardPrice: 0,
OfferPrice: 0,
SpecialPrice: 0,
Cess: 0,
}));
const bulkResponse = await dispatch(
bulkpostdata({ ProdDetails: newProductsData })
).unwrap();
if (bulkResponse?.data?.statusCode === 1) {
// After successful bulk upload, check the condition again
const updatedResponse = await dispatch(
getSupplaierIdBasedProducts({
CompId,
AppId,
BranchId,
SuppId: suppId,
})
).unwrap();
if (updatedResponse?.data?.statusCode === 1) {
const updatedAllSupplierProducts =
updatedResponse?.data?.data || [];
const updatedMatchingProdIds = [];
unmatchedProducts.forEach((item) => {
const match =
updatedAllSupplierProducts?.[0]?.ProductDetails.find(
(supp) =>
supp?.ProdName?.toLowerCase() ===
item?.parsedData?.description?.toLowerCase()
);
if (match) {
updatedMatchingProdIds.push(match.ProdId);
}
});
if (updatedMatchingProdIds.length > 0) {
matchingProdIds.push(...updatedMatchingProdIds);
}
}
}
}
// if there is matching products, map them to the supplier
if (matchingProdIds.length > 0) {
setLoadingText('Mapping products to supplier...');
const payload = {
CompId,
BranchId,
AppId,
SuppId: suppId,
ProductDetails: matchingProdIds.map((item) => ({ ProdId: item })),
};
const response = await dispatch(
postSupplaierProducts(payload)
)?.unwrap();
if (response?.data?.statusCode === 1) {
const suppliers = await getSuplaierApi({ dataReturn: true });
const mappedSupplierProducts = await handleSupplierDropDownChange(
suppId,
null,
suppliers
);
// update matchedProducts with newly mapped products
matchedProducts = data?.products?.map((imgItem) => {
const match = mappedSupplierProducts?.find(
(supp) =>
supp?.ProdName?.toLowerCase() ===
imgItem?.description?.toLowerCase()
);
return {
selectedProduct: match || null,
parsedData: imgItem,
matchFound: !!match,
selectedProdId: match?.ProdId || null,
};
});
console.log(matchedProducts, 'matchedProductsmatchedProducts');
if (matchedProducts?.length > 0) {
setLoadingText('Adding products to purchase list...');
const newProducts = [];
for (const item of matchedProducts) {
if (item.matchFound) {
const newProduct = await ProductDropDownChange(
item?.selectedProduct.ProdVariantName,
item.selectedProdId,
{ label: item.selectedProduct.ProdName },
mappedSupplierProducts,
true,
item,
newProducts
);
if (newProduct) {
if (
!PurchaseData.some((p) => p.ProdId === newProduct.ProdId)
) {
newProducts.push(newProduct);
} else {
if (suppId !== selectedSupplierData) {
newProducts.push(newProduct);
} else {
setMessageType('error');
setMessageData(
`Product ${newProduct.ProdName} already added in the list.`
);
}
}
}
}
}
// if (newProducts.length > 0) {
const updatedPurchaseData = [...PurchaseData, ...newProducts];
const purchasedData =
selectedSupplierData === suppId
? updatedPurchaseData
: newProducts;
setPurchaseData(purchasedData);
if (purchasedData.length > 0) {
for (const item of purchasedData) {
// const index = purchasedData.indexOf(item);
const localId = item?.localId;
form.setFieldsValue({
...form.getFieldsValue(),
[`BalanceQty${localId}`]: item.BalanceQty,
[`ReceivedQty${localId}`]: item.ReceivedQty,
[`AcceptedQty${localId}`]: item.AcceptedQty,
[`RejectedQty${localId}`]: item?.RejectedQty,
[`InwardPrice${localId}`]: item?.InwardPrice,
[`Amount${localId}`]: item?.Amount,
});
}
}
// }
setMessageType('success');
setMessageData('Extracted data applied successfully!');
} else {
setMessageType('error');
setMessageData(
'No matching products found in your product list.'
);
console.log('Matching 1');
}
} else {
setMessageType('error');
setMessageData(
'Error Occurred while mapping products with supplier.'
);
}
} else {
setMessageType('error');
setMessageData('No matching products found in your product list.');
console.log('Matching 2');
}
} else {
setIsLoading(false);
setLoadingText('');
setMessageType('error');
setMessageData('Error Occurred while mapping products with supplier.');
return;
}
} else {
if (matchedProducts?.length > 0) {
setLoadingText('Adding products to purchase list...');
const newProducts = [];
for (const item of matchedProducts) {
if (item.matchFound) {
const newProduct = await ProductDropDownChange(
item?.selectedProduct?.ProdVariantName,
item.selectedProdId,
{ label: item.selectedProduct.ProdName },
supplierProducts,
true,
item,
newProducts
);
if (newProduct) {
if (!PurchaseData.some((p) => p.ProdId === newProduct.ProdId)) {
newProducts.push(newProduct);
} else {
if (suppId !== selectedSupplierData) {
newProducts.push(newProduct);
} else {
setMessageType('error');
setMessageData(
`Product ${newProduct.ProdName} already added in the list.`
);
}
}
}
}
}
// if (newProducts.length > 0) {
const updatedPurchaseData = [...PurchaseData, ...newProducts];
const purchasedData =
selectedSupplierData === suppId ? updatedPurchaseData : newProducts;
setPurchaseData(purchasedData);
if (purchasedData.length > 0) {
for (const item of purchasedData) {
// const index = purchasedData.indexOf(item);
const localId = item?.localId;
form.setFieldsValue({
...form.getFieldsValue(),
[`BalanceQty${localId}`]: item.BalanceQty,
[`ReceivedQty${localId}`]: item.ReceivedQty,
[`AcceptedQty${localId}`]: item.AcceptedQty,
[`RejectedQty${localId}`]: item?.RejectedQty,
[`InwardPrice${localId}`]: item?.InwardPrice,
[`Amount${localId}`]: item?.Amount,
});
}
}
// }
setMessageType('success');
setMessageData('Extracted data applied successfully!');
} else {
setMessageType('error');
setMessageData('No matching products found in your product list.');
console.log('Matching 3');
}
}
setExtractorModalVisible(false);
setIsLoading(false);
setLoadingText('');
};
const applicationApplicableFields = async () => {
const response = await dispatch(getCommonAppPreference(AppId)).unwrap();
if (response?.data?.statusCode === 1) {
const details = response?.data?.data?.[0]?.PreferenceDetails?.find(
(find) => find.PreferredCatName === 'Purchase Entry'
);
if (Object.keys(details || {})?.length > 0) {
if (details?.PreferenceCatDetails?.length > 0) {
setApplicationRestrictedFields({
DatesAndExpiry: details?.PreferenceCatDetails?.some(
(some) =>
some.PreferredSubCatName === 'Dates & Expiry' &&
some.PreferredStatus === 'Y'
),
BatchAndModelDetails: details?.PreferenceCatDetails?.some(
(some) =>
some.PreferredSubCatName === 'Batch & Model Details' &&
some.PreferredStatus === 'Y'
),
AmountPerPieceDetail: details?.PreferenceCatDetails?.some(
(some) =>
some.PreferredSubCatName === 'Amount Per Piece' &&
some.PreferredStatus === 'Y'
),
});
return;
}
}
setApplicationRestrictedFields({
DatesAndExpiry: null,
BatchAndModelDetails: null,
AmountPerPieceDetail: null,
});
}
};
const filteredOptions = useMemo(() => {
return (
purchaseOrderList?.map((data) => {
const purchaseInvoiceParts = data?.PurOrderId?.split('-');
return {
value: data?.PurOrderId,
label: purchaseInvoiceParts[purchaseInvoiceParts?.length - 1],
};
}) || []
);
}, [purchaseOrderList, selectedSupplierData]);
const getPurchaseType = async () => {
let res = await dispatch(getPurchaseTypeData()).unwrap();
if (res?.data?.statusCode === 1) {
setPurchaseTypeData(res?.data?.data);
let tempcash = res?.data?.data?.find(
(item) => item?.ConfigName?.toLowerCase() === 'cash'
);
setSelectedPurchaseType(tempcash?.ConfigId);
formRef.current?.setFieldsValue({ PaymentType: tempcash?.ConfigId });
} else {
setPurchaseTypeData(null);
}
};
const getPurchaseTaxType = async () => {
let res = await dispatch(getPurchaseTaxTypeData()).unwrap();
if (res?.data?.statusCode === 1) {
// setPurcTaxTypeData(res?.data?.data);
let tempniltax = res?.data?.data?.find(
(item) => item?.ConfigName?.toLowerCase() === 'inclusive'
);
setSelectedPurcTaxType(tempniltax?.ConfigId);
formRef.current?.setFieldsValue({ TaxType: tempniltax?.ConfigId });
}
// else {
// setPurcTaxTypeData(null);
// }
};
const pinCodeChange = async (e) => {
if (e.target.value?.length < 6) {
setZipCodeData(false);
return false;
}
await getPincodeValues(e?.target?.value);
};
const getPincodeValues = async (pinCode) => {
let response = '';
await fetch(`https://api.postalpincode.in/pincode/${pinCode}`)
.then((res) => res.text())
.then((text) => (response = JSON.parse(text)));
if (response[0]['Status'] === 'Success') {
setZipCodeData(true);
formSupplierRef.current?.setFieldsValue({
City: response[0]['PostOffice'][0]['Block'],
Dist: response[0]['PostOffice'][0]['District'],
State: response[0]['PostOffice'][0]['State'],
});
return {
City: response[0]['PostOffice'][0]['Block'],
Dist: response[0]['PostOffice'][0]['District'],
State: response[0]['PostOffice'][0]['State'],
};
} else {
setZipCodeData(false);
}
};
const handleMRP = () => {
formProductRef.current?.setFieldsValue({ SellPrice: null });
};
const handleSuppInvoiceNoChange = (e) => {
const value = e.target.value;
formRef.current?.setFieldsValue({ SuppInvoiceNo: value });
setExtractorData((prev) => (prev ? { ...prev, invoiceNo: value } : null));
};
const handleInvoiceTypeChange = (value) => {
setInvoiceType(value);
};
const handleInwardDateChange = (date) => {
setInwardDate(date);
};
// formRef?.current?.setFieldsValue({ SuppInvoiceNo: extractorData?.invoiceNo });
const handleSupplierDropDownChange = async (
SuppId,
option,
suppliers = null
) => {
let suppName = (suppliers || SupplierData)?.filter(
(item) => item.SuppId == SuppId
)?.[0]?.SuppName;
formRef?.current?.setFieldsValue({ CustSuppId: SuppId });
setSelectedSupplierData(SuppId);
const mappedSupplierProducts = await handleSupplierBasedProduct(SuppId);
formRef?.current?.resetFields(['VarProdId', 'ProdId']);
suppName === 'Self'
? setSelectedSupplierName(false)
: setSelectedSupplierName(true);
// setselectedProductVariantData(null);
// setSelectedProductData(null);
setSelectedProductName(null);
formRef?.current?.setFieldsValue({ ProdId: null });
setSearchText(null);
return mappedSupplierProducts;
};
const handlePurchaseTypeChange = (PurId) => {
formRef.current?.setFieldsValue({ PaymentType: PurId });
setSelectedPurchaseType(PurId);
};
const onSuppInvoiceDateChange = async (date, dateString) => {
if (dateString) {
const Date3 = moment(dateString, ['DD-MM-YYYY']).format(
'YYYY-MM-DDTHH:mm:ss'
);
formRef.current?.setFieldsValue({ SuppInvoiceDate: Date3 });
setSuppInvoiceDate(Date3);
} else if (dateString === '') {
setSuppInvoiceDate();
}
};
const onPurchaseDateChange = async (date, dateString) => {
if (dateString) {
const Date3 = moment(dateString, ['DD-MM-YYYY']).format(
'YYYY-MM-DDTHH:mm:ss'
);
formRef.current?.setFieldsValue({ DueDate: Date3 });
setPurchaseDate(Date3);
} else if (dateString === '') {
setPurchaseDate();
}
};
const ProductDropDownChange = async (
VariantName,
ProdId,
option,
productsList,
extractedProduct = false,
extractedItem,
existingProducts
) => {
setProductSearchText('');
setSelectedProductName(option?.label ? option?.label : '');
formRef?.current?.resetFields(['VarProdId']);
// setselectedProductVariantData(null);
if (true) {
formRef.current?.setFieldsValue({ ProdId: ProdId });
// await setSelectedProductData(ProdId);
if (
(existingProducts || PurchaseData)?.some(
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
)
) {
const existingProduct = (existingProducts || PurchaseData)?.find(
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
);
setMessageType('error');
setMessageData(
`Product "${existingProduct?.ProdName} - ${existingProduct?.ProdVariantName}" already exists`
);
return null;
} else {
let ProductData1 = (productsList || productData)?.find(
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
);
let DefaultVariant = ProductData1?.ProdVariantPriceDetails?.find(
(item) => item?.DefaultVariant === 'Y' && item?.ReceivedQty === 0
)?.DefaultVariant;
let ProduData2 = {
DefaultVariant: DefaultVariant,
ProdId: ProductData1?.ProdId,
MRP: ProductData1?.MRP,
ProdName: ProductData1?.ProdName,
UomName: ProductData1?.UomName,
SellPrice: ProductData1?.SellPrice,
StockAvailable: ProductData1?.StockAvailable,
OnePcsAvailable: ProductData1?.OnePcsAvailable,
OnePcsPrice: ProductData1?.OnePcsPrice,
NoOfPcs: ProductData1?.NoOfPcs,
TaxId: ProductData1?.TaxId,
TaxPercentage: ProductData1?.TaxPercentage,
ProdVariantName: ProductData1?.ProdVariantName,
};
const qty = extractedProduct
? parseFloat(extractedItem?.parsedData?.qty) || 0
: 0;
const acceptedQty = extractedProduct
? parseFloat(extractedItem?.parsedData?.qty) || 0
: 0;
const rate = extractedProduct
? parseFloat(extractedItem?.parsedData?.rate) || 0
: 0;
let tempPurData = {
...ProduData2,
PurchaseTax: parseFloat(extractedItem?.parsedData?.tax) || 0,
BalanceQty: qty,
InwardPrice: rate,
PurcDisc: 0,
Amount: isNaN(rate) || isNaN(acceptedQty) ? 0 : rate * acceptedQty,
WhSalePrice: 0,
ReceivedQty: qty,
AcceptedQty: acceptedQty,
RejectedQty: qty - acceptedQty,
OfferPrice: 0,
SpecialPrice: 0,
FreeItem: 0,
TaxAmt: 0,
TaxType: SelectedPurcTaxType ? SelectedPurcTaxType : 0,
PurcDiscType: 'P',
refImage: extractedItem?.parsedData?.image,
PurchaseHSNCode: extractedItem?.parsedData?.hsn || '',
localId: uuidv4(),
};
return tempPurData;
}
}
};
const handleProductSelect = async (value, option) => {
const [prodId, variantName] = value?.split('_');
const product = productData.find(
(p) => p.ProdId === prodId && p.ProdVariantName === variantName
);
if (!product) return;
// Check for duplicates
const exists = PurchaseData.some(
(p) => p.ProdId === prodId && p.ProdVariantName === variantName
);
if (exists) {
const existingProduct = PurchaseData.find(
(p) => p.ProdId === prodId && p.ProdVariantName === variantName
);
setMessageType('error');
setMessageData(
`Product "${existingProduct?.ProdName} - ${existingProduct?.ProdVariantName}" already exists`
);
return;
}
// Build product row
const defaultVariant = product.ProdVariantPriceDetails?.find(
(item) => item?.DefaultVariant === 'Y' && item?.ReceivedQty === 0
)?.DefaultVariant;
const newRow = {
ProdId: product.ProdId,
ProdName: product.ProdName,
ProdVariantName: product.ProdVariantName,
UomName: product.UomName,
MRP: product.MRP,
SellPrice: product.SellPrice,
OnePcsPrice: product.OnePcsPrice,
NoOfPcs: product.NoOfPcs,
StockAvailable: product.StockAvailable,
OnePcsAvailable: product.OnePcsAvailable,
TaxId: product.TaxId,
TaxPercentage: product.TaxPercentage,
DefaultVariant: defaultVariant,
PurchaseTax: 0,
BalanceQty: 0,
InwardPrice: 0,
ReceivedQty: 0,
AcceptedQty: 0,
RejectedQty: 0,
Amount: 0,
WhSalePrice: 0,
OfferPrice: 0,
SpecialPrice: 0,
FreeItem: 0,
TaxAmt: 0,
PurcDisc: 0,
PurcDiscType: 'P',
PurchaseHSNCode: product.PurchaseHSNCode || '',
refImage: product?.image || '',
localId: uuidv4(),
};
// ✅ Single state update: update PurchaseData + form fields together
setPurchaseData((prev) => [newRow, ...prev]);
form?.setFieldsValue({
[`SellPrice${newRow.localId}`]: newRow.SellPrice,
[`PurchaseTax${newRow.localId}`]: newRow.PurchaseTax,
ProdId: prodId,
});
// Reset search text
setProductSearchText('');
setSelectedProductName(option?.label || '');
};
const debouncedScannerSearch = useCallback(
debounce(async (value) => {
const qr = value?.trim();
const matchedProduct = productData.find(
(p) => p.QRCode?.toLowerCase() === qr?.toLowerCase()
);
if (matchedProduct) {
let productName = {};
productName.label = `${matchedProduct?.ProdName} (${matchedProduct.Size} ${matchedProduct.UomName})${matchedProduct?.BrandName ? ` - ${matchedProduct?.BrandName}` : ''}`;
const newProduct = await ProductDropDownChange(
matchedProduct?.ProdVariantName,
matchedProduct.ProdId,
productName
);
if (newProduct) {
setPurchaseData([newProduct, ...PurchaseData]);
}
if (matchedProduct?.ProdVariantPriceDetails?.length < 2) {
setSelectedProductName('');
// setSelectedProductData(null);
}
} else {
setMessageType('error');
setMessageData('The Scanned Product not Available in Product List');
}
}, 300),
[productData]
);
// Clean up debounce on unmount
const handleProductSearch = (value) => {
if (scanner) {
debouncedScannerSearch(value);
}
setProductSearchText(value);
setSelectedProductName(value);
};
const handleScanSearch = () => {
if (scanner === false) {
setMessageType('success');
setMessageData('Search by QrCode/BarCode Enabled');
} else {
setMessageType('success');
setMessageData('Search by QrCode/BarCode Disabled');
}
setScanner((prev) => !prev);
setSelectedProductName(null);
// setselectedProductVariantData(null);
// setVariants(null);
formRef?.current?.setFieldsValue({
ProdId: null,
VarProdId: null,
});
};
const addSupplier = () => {
setOpenSupplierModel(true);
};
const handleSupplier = () => {
setOpenSupplierModel(false);
};
const submitSupplier = async () => {
const subSupplierData = await formSupplierRef?.current?.validateFields();
const addSupplierData = {
CompId: CompId,
AppId: AppId,
BranchId: BranchId,
SuppName: subSupplierData?.SuppName,
SuppGSTIN: subSupplierData?.SuppGSTIN,
SuppPOC: subSupplierData?.SuppPOC,
SuppMobile: subSupplierData?.SuppMobile,
SuppEmail: subSupplierData?.SuppEmail,
Address1: subSupplierData?.Address1,
Address2: subSupplierData?.Address1,
Zip: subSupplierData?.Zip,
City: subSupplierData?.City,
State: subSupplierData?.State,
Dist: subSupplierData?.Dist,
SuppPOCMobile: subSupplierData?.SuppPOCMobile,
SuppPOCEmail: subSupplierData?.SuppPOCEmail,
DeliveryPerformance: subSupplierData?.DeliveryPerformance,
DiscountLevel: subSupplierData?.DiscountLevel,
QualityofSupp: subSupplierData?.QualityofSupp,
CreatedBy: UserId,
};
let response = {};
response = await dispatch(postSupplier(addSupplierData)).unwrap();
if (response?.data?.statusCode == 1) {
setMessageType('success');
setMessageData(response?.data?.response);
let response1 = await dispatch(
getSupplierData({
CompId: CompId,
AppId: AppId,
BranchId: BranchId,
ActiveStatus: 'A',
})
).unwrap();
if (response1?.data?.statusCode == 1) {
setOpenSupplierModel(false);
}
formSupplierRef?.current?.resetFields();
setZipCodeData(null);
} else {
setMessageType('error');
setMessageData(response?.data?.response);
formSupplierRef?.current?.resetFields();
}
};
useEffect(() => {
if (!editingKey) return;
const record = PurchaseData.find((item) => item.localId === editingKey);
if (!record) return;
const localId = record.localId;
const values = Delete
? {
[`BalanceQty${localId}`]: undefined,
[`ReceivedQty${localId}`]: undefined,
[`AcceptedQty${localId}`]: undefined,
[`RejectedQty${localId}`]: undefined,
[`Amount${localId}`]: undefined,
[`Freeqty${localId}`]: undefined,
[`InwardPrice${localId}`]: undefined,
[`MRP${localId}`]: undefined,
[`PurcDisc${localId}`]: undefined,
[`SellPrice${localId}`]: undefined,
[`WhSalePrice${localId}`]: undefined,
[`offerSalePrice${localId}`]: undefined,
[`splSalePrice${localId}`]: undefined,
[`NumberofPieceinside${localId}`]: undefined,
[`AmountPerPiece${localId}`]: undefined,
[`PurcDiscType${localId}`]: undefined,
[`ManufDate${localId}`]: undefined,
[`ExpDate${localId}`]: undefined,
[`OnePcsPrice${localId}`]: undefined,
[`NoOfPcs${localId}`]: undefined,
}
: {
[`BalanceQty${localId}`]: record.BalanceQty,
[`ReceivedQty${localId}`]: record.ReceivedQty,
[`AcceptedQty${localId}`]: record.AcceptedQty,
[`RejectedQty${localId}`]: record.RejectedQty,
[`Freeqty${localId}`]: record.FreeItem,
[`MRP${localId}`]: record.MRP,
[`ManufDate${localId}`]: record.ManufDate,
[`ExpDate${localId}`]: record.ExpDate,
[`SellPrice${localId}`]: record.SellPrice,
[`WhSalePrice${localId}`]: record.WhSalePrice,
[`PurcDiscType${localId}`]: record.PurcDiscType,
[`Amount${localId}`]: record.Amount,
[`InwardPrice${localId}`]: record.InwardPrice,
[`PurcDisc${localId}`]: record.PurcDisc,
[`offerSalePrice${localId}`]: record.OfferPrice,
[`splSalePrice${localId}`]: record.SpecialPrice,
[`OnePcsPrice${localId}`]: record.OnePcsPrice,
[`NoOfPcs${localId}`]: record.NoOfPcs,
};
if (!Delete && applicationRestrictedFields.BatchAndModelDetails) {
values[`BatchRef${localId}`] = record.BatchRef;
}
form.setFieldsValue(values);
setDelete(false);
}, [editingKey]);
const save = async (localId) => {
try {
const row = await form.validateFields();
const modifiedObject = {};
for (const key in row) {
// remove localId suffix from field names
if (key.endsWith(localId)) {
const newKey = key?.replace(localId, '');
modifiedObject[newKey] = row[key];
}
}
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === localId ? { ...item, ...modifiedObject } : item
)
);
setEditingKey('');
} catch (err) {
console.error('Save failed:', err);
}
};
const handleKeyPress = async (e, record) => {
if (e.key === 'Enter') {
try {
await form.validateFields();
save(record.localId);
} catch (error) {
console.error('Save failed:', error);
}
}
};
const formatDateForDisplay = (dateString) => {
if (!dateString) return '';
return moment(dateString).format('DD-MMM-YY');
};
const sellPriceValidator = useCallback((_, value) => {
if (value <= 0) return Promise.reject('Invalid price');
return Promise.resolve();
}, []);
const handleDecimalInput = (e) => {
let value = e.target.value?.replace(/[^0-9.]/g, '');
if (value.startsWith('.')) value = '0' + value;
const parts = value.split('.');
e.target.value =
parts?.length > 2 ? `${parts[0]}.${parts.slice(1).join('')}` : value;
};
const updateRowValues = (localId, updates) => {
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === localId ? { ...item, ...updates } : item
)
);
const formUpdates = {};
Object.keys(updates).forEach((key) => {
formUpdates[`${key}${localId}`] = updates[key];
});
form.setFieldsValue(formUpdates);
};
const updateRowValue = (localId, key, value) => {
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === localId ? { ...item, [key]: value } : item
)
);
form.setFieldsValue({
[`${key}${localId}`]: value,
});
};
const columns = useMemo(() => {
const baseColumns = [
{
title: 'SL.NO',
align: 'center',
key: 'sno',
width: 50,
render: (text, object, index) => (
{index + 1}
),
},
{
title: 'Name',
dataIndex: 'ProdName',
key: 'ProdName',
align: 'left',
width: 150,
render: (text, record, index) => (
{record?.ProdName}
),
},
{
title: 'Variant',
dataIndex: 'ProdVariantName',
key: 'ProdVariantName',
align: 'center',
width: 100,
render: (text, record, index) => (
{record?.ProdVariantName}
),
},
{
title: 'Uom',
dataIndex: 'UomName',
key: 'UOMName',
align: 'center',
width: 100,
},
{
title: 'Qty',
dataIndex: 'BalanceQty',
key: 'BalanceQty',
align: 'center',
editable: true,
width: 100,
render: (text, record, index) => {
return (
handleQtyTyping(e, record)}
onBlur={() => commitQtyChange(record)}
onPressEnter={() => commitQtyChange(record)}
inputMode="decimal"
onInput={(e) => {
let v = e.target.value.replace(/[^0-9.]/g, '');
if (v.startsWith('.')) v = '0' + v;
const parts = v.split('.');
e.target.value =
parts.length > 2
? `${parts[0]}.${parts.slice(1).join('')}`
: v;
}}
/>
);
},
},
{
title: 'Pur Rate / unit',
dataIndex: 'InwardPrice',
key: 'InwardPrice',
width: 120,
editable: true,
align: 'center',
render: (_, record) => {
const editable = true;
return editable ? (
handlePurrateTyping(e, record)}
/>
) : (
edit(record)} // ✅ THIS is required
style={{ cursor: 'pointer' }}
>
{record.InwardPrice || 0}
);
},
},
{
title: (
Tax (%)
),
dataIndex: 'PurchaseTax',
key: 'PurchaseTax',
editable: true,
align: 'center',
width: 100,
render: (_, record) => (
handleTaxTyping(e, record)}
onBlur={() => debouncedTaxCalc(record.PurchaseTax, record)}
/>
),
},
{
title: 'Amount',
dataIndex: 'Amount',
key: 'Amount',
editable: true,
align: 'right',
width: 100,
},
...(selectedAdditionalColumn.includes('Mrp')
? [
{
title: 'MRP',
dataIndex: 'MRP',
key: 'MRP',
editable: true,
width: 100,
align: 'center',
render: (_, record) => {
return (
edit(record)}
placeholder="MRP"
value={record?.MRP ?? ''}
maxLength={10}
inputMode="decimal"
onChange={(e) => handleMRPChange(e, record)}
onBlur={(e) => handleMRPBlur(e, record)}
onPressEnter={(e) => handleKeyPress(e, record)}
/>
);
},
},
]
: []),
{
title: (
Selling Price
),
dataIndex: 'SellPrice',
key: 'SellPrice',
width: 100,
editable: true,
align: 'center',
render: (_, record) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
value={record?.SellPrice ?? ''}
maxLength={10}
inputMode="decimal"
onChange={(e) => handleSellPriceChange(e, record)}
onBlur={(e) => handleSellPriceBlur(e, record)}
onPressEnter={(e) => handleKeyPress(e, record)}
onInput={handleDecimalInput}
/>
);
},
},
...(selectedAdditionalColumn.includes('Amount Per Piece')
? [
{
title: 'Amount per piece',
dataIndex: 'OnePcsPrice',
key: 'OnePcsPrice',
width: 125,
editable: true,
render: (_, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
disabled={record?.OnePcsAvailable === 'N'}
placeholder="OnePcsPrice"
value={record?.OnePcsPrice ?? ''}
maxLength={10}
inputMode="decimal"
onChange={(e) => handleOnePcsChange(e, record)}
onBlur={(e) => handleOnePcsBlur(e, record)}
onPressEnter={() => handleKeyPress(e, record)}
onInput={(e) => {
let v = e.target.value.replace(/[^0-9.]/g, '');
if (v.startsWith('.')) v = '0' + v;
const parts = v.split('.');
e.target.value =
parts.length > 2
? `${parts[0]}.${parts.slice(1).join('')}`
: v;
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Amount Per Piece')
? [
{
title: 'Number of piece',
dataIndex: 'NoOfPcs',
key: 'NoOfPcs',
width: 125,
editable: true,
render: (_, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
disabled={record?.OnePcsAvailable === 'N'}
placeholder="NoOfPcs"
value={record.NoOfPcs ?? ''}
maxLength={5}
inputMode="numeric"
onChange={(e) => handleNoOfPcsChange(e, record)}
onBlur={(e) => handleNoOfPcsBlur(e, record)}
onPressEnter={() => handleKeyPress(e, record)}
onInput={(e) => {
// remove invalid characters & leading zeros
let val = e.target.value.replace(/[^0-9]/g, '');
val = val.replace(/^0+(?=\d)/, ''); // removes leading zeros but keeps single 0
e.target.value = val;
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Wholesale Price')
? [
{
title: 'Wholesale price',
dataIndex: 'WhSalePrice',
key: 'WhSalePrice',
width: 125,
editable: true,
render: (_, record) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
placeholder="WhSalePrice"
value={record.WhSalePrice ?? ''}
inputMode="decimal"
maxLength={10}
onChange={(e) => handleWhSalePriceChange(e, record)}
onBlur={(e) => handleWhSalePriceBlur(e, record)}
onPressEnter={() => handleKeyPress(record)}
onInput={(e) => {
let val = e.target.value.replace(/[^0-9.]/g, ''); // remove invalid chars
if (val.startsWith('.')) val = '0' + val; // leading dot fix
const parts = val.split('.');
if (parts.length > 2)
val = `${parts[0]}.${parts.slice(1).join('')}`; // max one dot
val = val.replace(/^0+(?=\d)/, ''); // remove leading zeros
e.target.value = val;
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Manufacture Date')
? [
{
title: 'Manuf.Date',
dataIndex: 'ManufDate',
key: 'ManufDate',
editable: true,
width: 100,
render: (text, record, index) => {
return (
{
// Format date to your preferred format
const formattedDate = dateString
? moment(dateString, ['DD-MM-YYYY']).format(
'YYYY-MM-DDTHH:mm:ss'
)
: undefined;
// Update the row data immutably
const newData = PurchaseData.map((item) =>
item.localId === record.localId
? { ...item, ManufDate: formattedDate }
: item
);
setPurchaseData(newData);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Expiry Date')
? [
{
title: 'Exp.Date',
dataIndex: 'ExpDate',
key: 'ExpDate',
editable: true,
width: 100,
render: (text, record, index) => {
return (
handleExpDateChange(dateString, record)
}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Hsn')
? [
{
title: 'Hsn',
dataIndex: 'Hsn',
key: 'Hsn',
editable: true,
width: 100,
align: 'center',
render: (text, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
onPressEnter={() => handleKeyPress(record)}
onChange={(e) => {
const value = e.target.value;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, PurchaseHSNCode: value }
: item
)
);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Model No')
? [
{
title: 'Model',
dataIndex: 'Model',
key: 'Model',
editable: true,
width: 100,
align: 'center',
render: (text, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
onPressEnter={() => handleKeyPress(record)}
onChange={(e) => {
const value = e.target.value;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, ModelNumber: value }
: item
)
);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Batch No')
? [
{
title: 'Batch',
dataIndex: 'Batch',
key: 'Batch',
width: 100,
align: 'center',
editable: true,
render: (text, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
onPressEnter={() => handleKeyPress(record, index)}
onChange={(e) => {
const value = e.target.value;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, BatchRef: value }
: item
)
);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Rejected Qty')
? [
{
title: 'Rejected Qty',
dataIndex: 'RejectedQty',
key: 'RejectedQty',
editable: true,
width: 100,
align: 'center',
render: (text, record, index) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
onPressEnter={() => handleKeyPress(record, index)}
onChange={(e) => {
let inputValue = e.target.value.replace(/[^0-9.]/g, ''); // allow only numbers
if (inputValue.startsWith('0') && inputValue.length > 1) {
inputValue = inputValue.replace(/^0+/, ''); // remove leading zeros
}
const rejectedQty = parseFloat(inputValue) || 0;
const receivedQty = parseFloat(record.ReceivedQty) || 0;
// validation
if (rejectedQty >= receivedQty) {
setMessageType('error');
setMessageData(
'Rejected Qty cannot be greater than or equal to Received Qty'
);
return;
}
const acceptedQty = receivedQty - rejectedQty;
const price = parseFloat(record.InwardPrice) || 0;
const amount = acceptedQty * price;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? {
...item,
RejectedQty: rejectedQty,
AcceptedQty: acceptedQty,
Amount: amount,
}
: item
)
);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('Free Qty')
? [
{
title: 'Free Qty',
dataIndex: 'Freeqty',
key: 'Freeqty',
editable: true,
width: 100,
align: 'center',
render: (text, record) => {
return (
edit(record)}
onFocus={(e) => e.stopPropagation()}
onPressEnter={() => handleKeyPress(record)}
onChange={(e) => {
let value = e.target.value.replace(/[^0-9]/g, ''); // only digits
if (value.startsWith('0') && value.length > 1) {
value = value.replace(/^0+/, ''); // remove leading zeros
}
updateRowValue(record.localId, 'Freeqty', value);
}}
/>
);
},
},
]
: []),
...(selectedAdditionalColumn.includes('IMEI')
? [
{
title: 'IMEI',
dataIndex: 'AdditionalInfo',
key: 'AdditionalInfo',
width: 120,
align: 'center',
render: (text, record, index) => {
const receivedQty = parseFloat(record?.ReceivedQty) || 0;
const isClickable = receivedQty > 0;
return (
{
if (!isClickable) {
setMessageType('error');
setMessageData('Please Enter Qty');
return;
}
setSelectedRowIndex(index);
handleModelDataOpen(record);
}}
className="shape-preview"
/>
);
},
},
]
: []),
{
title: 'Action',
dataIndex: 'Action',
key: 'Action',
align: 'center',
width: 80,
render: (_, record, index) => (
{
e.stopPropagation();
}}
>
statusFormatters(record)}
/>
),
},
];
return baseColumns;
}, [editingKey, editingQty, selectedAdditionalColumn]);
const statusFormatters = (record) => {
const localId = record?.localId;
setPurchaseData((prev) => prev.filter((item) => item.localId !== localId));
const formValues = form.getFieldsValue();
const keysToRemove = Object.keys(formValues).filter((key) =>
key.endsWith(localId)
);
if (keysToRemove.length) {
const newValues = { ...formValues };
keysToRemove.forEach((key) => {
newValues[key] = undefined;
});
form.setFieldsValue(newValues);
}
// 3️⃣ Clear other single fields
formRef?.current?.setFieldsValue({
ProdId: null,
});
setDelete(true); // only if absolutely necessary
};
const handleQtyTyping = (e, record) => {
let value = e.target.value;
// allow only numbers + decimal
if (!/^\d*\.?\d*$/.test(value)) return;
// 🔥 remove leading zero (but keep "0." valid)
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
value = value.replace(/^0+/, '');
}
setEditingQty((prev) => ({
...prev,
[record.localId]: value,
}));
};
const commitQtyChange = (record) => {
const { localId } = record;
const qty = Number(editingQty[localId]) || 0;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === localId
? {
...item,
BalanceQty: qty,
ReceivedQty: qty,
AcceptedQty: qty,
RejectedQty: 0,
PurcDisc: 0,
Amount:
isNaN(item.InwardPrice) || isNaN(qty)
? 0
: item.InwardPrice * qty,
ProductIdentifierDtls: [],
}
: item
)
);
form.setFieldsValue({
[`BalanceQty${localId}`]: qty,
[`ReceivedQty${localId}`]: qty,
[`AcceptedQty${localId}`]: qty,
[`RejectedQty${localId}`]: 0,
[`PurcDisc${localId}`]: 0,
});
};
useEffect(() => {
const id = setTimeout(() => {
const total = PurchaseData.reduce(
(acc, d) => acc + Number(d.Amount || 0),
0
);
setPaymentAmount(total);
formRef?.current?.setFieldsValue({ PaymentAmount: total });
}, 150);
return () => clearTimeout(id);
}, [PurchaseData]);
const handleMRPChange = (e, record) => {
const value = e.target.value ?? '';
if (!/^\d*\.?\d*$/.test(value)) return;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? {
...item,
MRP: value,
SellPrice: value,
}
: item
)
);
};
const handleMRPBlur = (e, record) => {
const value = e.target.value ?? '';
const normalized = value === '' ? '' : String(Number(value));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? {
...item,
MRP: normalized,
SellPrice: normalized,
}
: item
)
);
};
const handlePurrateChange = useCallback((e, record) => {
let value = e?.target?.value ?? '';
// allow decimals only
if (!/^\d*\.?\d*$/.test(value)) return;
// 🔥 remove leading zero when user starts typing
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
value = value.replace(/^0+/, '');
}
setPurchaseData((prev) =>
prev.map((item) => {
if (item.localId !== record.localId) return item;
const qty = Number(item.AcceptedQty) || 0;
const rateNum = Number(value || 0);
const amount = rateNum * qty;
let discountAmt = 0;
if (item.PurcDiscType === 'P') {
discountAmt = (amount * Number(item.PurcDisc || 0)) / 100;
} else {
discountAmt = Number(item.PurcDisc || 0);
}
const taxPercent = Number(item.TaxPercentage || 0);
const taxAmt =
taxPercent > 0
? ((amount - discountAmt) * taxPercent) / (100 + taxPercent)
: 0;
return {
...item,
InwardPrice: value, // 👈 clean value
Amount: amount,
TaxAmt: +taxAmt.toFixed(2),
};
})
);
}, []);
const handlePurrateTyping = (e, record) => {
let value = e?.target?.value ?? '';
if (!/^\d*\.?\d*$/.test(value)) return;
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
value = value.replace(/^0+/, '');
}
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId ? { ...item, InwardPrice: value } : item
)
);
debouncedCalc(value, record);
};
const calculateRate = useCallback((value, record) => {
setPurchaseData((prev) =>
prev.map((item) => {
if (item.localId !== record.localId) return item;
const qty = Number(item.AcceptedQty) || 0;
const rateNum = Number(value || 0);
const amount = rateNum * qty;
let discountAmt = 0;
if (item.PurcDiscType === 'P') {
discountAmt = (amount * Number(item.PurcDisc || 0)) / 100;
} else {
discountAmt = Number(item.PurcDisc || 0);
}
const taxPercent = Number(item.TaxPercentage || 0);
const taxAmt =
taxPercent > 0
? ((amount - discountAmt) * taxPercent) / (100 + taxPercent)
: 0;
return {
...item,
Amount: amount,
TaxAmt: +taxAmt.toFixed(2),
};
})
);
}, []);
const debouncedCalc = useDebounce(calculateRate, 300);
const handleSellPriceChange = (e, record) => {
const value = e?.target?.value ?? '';
// allow smooth typing
if (!/^\d*\.?\d*$/.test(value)) return;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId ? { ...item, SellPrice: value } : item
)
);
};
const handleSellPriceBlur = (e, record) => {
const value = e?.target?.value ?? '';
const normalized = value === '' ? '' : String(Number(value));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, SellPrice: normalized }
: item
)
);
};
const handleOnePcsChange = (e, record) => {
const value = e?.target?.value ?? '';
if (!/^\d*\.?\d*$/.test(value)) return;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId ? { ...item, OnePcsPrice: value } : item
)
);
};
const handleOnePcsBlur = (e, record) => {
const value = e?.target?.value ?? '';
const normalized = value === '' ? '' : String(Number(value));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, OnePcsPrice: normalized }
: item
)
);
};
const handleNoOfPcsChange = (e, record) => {
const value = e?.target?.value ?? '';
// only whole numbers
if (!/^\d*$/.test(value)) return;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId ? { ...item, NoOfPcs: value } : item
)
);
};
const handleNoOfPcsBlur = (e, record) => {
const value = e?.target?.value ?? '';
const normalized = value === '' ? '' : String(parseInt(value, 10));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, NoOfPcs: normalized }
: item
)
);
};
const handleWhSalePriceChange = (e, record) => {
const value = e?.target?.value ?? '';
if (!/^\d*\.?\d*$/.test(value)) return;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId ? { ...item, WhSalePrice: value } : item
)
);
};
const handleWhSalePriceBlur = (e, record) => {
const value = e?.target?.value ?? '';
const normalized = value === '' ? '' : String(Number(value));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, WhSalePrice: normalized }
: item
)
);
};
const handleManufDateChange = (dateString, record) => {
const formattedDate =
!dateString || dateString === ''
? undefined
: moment(dateString, ['DD-MM-YYYY']).format('YYYY-MM-DDTHH:mm:ss');
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, ManufDate: formattedDate }
: item
)
);
};
const handleExpDateChange = (dateString, record) => {
const formattedDate =
!dateString || dateString === ''
? undefined
: moment(dateString, ['DD-MM-YYYY']).format('YYYY-MM-DDTHH:mm:ss');
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, ExpDate: formattedDate }
: item
)
);
};
const handleHSNChange = (value, record) => {
// optional: digits only (HSN is numeric)
const cleanValue = value.replace(/\D/g, '');
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, PurchaseHSNCode: cleanValue }
: item
)
);
};
const handleTaxTyping = (e, record) => {
let value = e?.target?.value ?? '';
// allow decimal typing only
if (!/^\d*\.?\d*$/.test(value)) return;
// fix ".5" → "0.5"
if (value.startsWith('.')) value = '0' + value;
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, PurchaseTax: value } // keep STRING
: item
)
);
debouncedTaxCalc(value, record);
};
const calculateTax = useCallback((value, record) => {
setPurchaseData((prev) =>
prev.map((item) => {
if (item.localId !== record.localId) return item;
const amount = Number(item.Amount) || 0;
const taxPercent = Number(value || 0);
const taxAmt =
taxPercent > 0 ? (amount * taxPercent) / (100 + taxPercent) : 0;
return {
...item,
TaxPercentage: taxPercent,
TaxAmt: +taxAmt.toFixed(2),
};
})
);
}, []);
const debouncedTaxCalc = useDebounce(calculateTax, 300);
// const handleTaxChange = (e, record) => {
// const { localId } = record;
// const value = e?.target?.value ?? '';
// // ✅ allow natural typing
// if (!/^\d*\.?\d*$/.test(value)) return;
// setPurchaseData((prev) =>
// prev.map((item) =>
// item.localId === localId
// ? {
// ...item,
// PurchaseTax: value, // 👈 KEEP STRING
// }
// : item
// )
// );
// // 👇 keep form in sync (string only)
// form.setFieldsValue({
// [`PurchaseTax${localId}`]: value,
// });
// };
const handleTaxBlur = (e, record) => {
const value = e?.target?.value ?? '';
const normalized = value === '' ? '' : String(Number(value));
setPurchaseData((prev) =>
prev.map((item) =>
item.localId === record.localId
? { ...item, PurchaseTax: normalized }
: item
)
);
form.setFieldsValue({
[`PurchaseTax${record.localId}`]: normalized,
});
};
const purchaseStatusChange = (value) => {
setPurchaseStatus(value);
};
const SupplierOpenfun = (value) => {
setSupplierOpen(value);
};
const getUniqueImageArray = (data = []) => {
const seen = new Set();
return data.reduce((acc, item) => {
const url = item?.refImage;
if (url && !seen.has(url)) {
seen.add(url);
acc.push({ ImageUrl: url });
}
return acc;
}, []);
};
const onFinish = async ({ PaymentType, PaymentAmount = 0, ...values }) => {
try {
// ===============================
// 1️⃣ TAX VALIDATION
// ===============================
const invalidTaxItems = PurchaseData?.filter((item) => {
const tax = item?.PurchaseTax;
if (tax === undefined || tax === '' || tax === null) return false;
const num = Number(tax);
return isNaN(num) || num < 0 || num > 99;
});
if (invalidTaxItems?.length > 0) {
setMessageType('error');
setMessageData(
'Please enter valid tax percentage (0–99%) for all items'
);
return;
}
if (
PurchaseData?.some(
(item) =>
item.SellPrice &&
item.MRP &&
Number(item.SellPrice) > Number(item.MRP)
)
) {
setMessageType('error');
setMessageData('Selling Price cannot be greater than MRP');
return;
}
if (!PurchaseData || PurchaseData?.length === 0) {
setMessageType('error');
setMessageData('No Product Selected');
return;
}
const validRows = [];
const invalidRowNumbers = [];
PurchaseData.forEach((item, index) => {
const qty = Number(item.BalanceQty) || 0;
const amount = Number(item.Amount) || 0;
if (qty > 0 && amount > 0) {
validRows.push(item);
} else {
invalidRowNumbers.push(index + 1);
}
});
if (validRows?.length === 0) {
setMessageType('error');
setMessageData('Please enter Qty and Amount for at least one product');
return;
}
// ===============================
// 5️⃣ CONFIRMATION FOR INVALID ROWS
// ===============================
if (invalidRowNumbers.length > 0) {
Modal.confirm({
title: '⚠️ Incomplete Product Rows',
width: 520,
centered: true,
content: (
Some products are missing Qty or Amount.
Affected row(s): {invalidRowNumbers.join(', ')}
Are you sure you want to continue without these products?
),
okText: 'Continue Anyway',
cancelText: 'Go Back',
okButtonProps: { danger: true },
onOk: () =>
proceedSubmit(validRows, values, PaymentType, PaymentAmount),
});
return;
}
// If all rows valid
await proceedSubmit(validRows, values, PaymentType, PaymentAmount);
} catch (error) {
console.error(error);
setMessageType('error');
setMessageData('Something went wrong');
}
};
const proceedSubmit = async (
filteredPurchaseData,
values,
PaymentType,
PaymentAmount
) => {
const images = getUniqueImageArray(filteredPurchaseData);
const postData = {
...values,
InvoiceAmount: filteredPurchaseData.reduce(
(acc, item) => acc + Number(item.Amount || 0),
0
),
CompId,
BranchId,
AppId,
CreatedBy: UserId,
PurOrderStatus: purchaseStatus,
TaxAmount: TotalTaxAmount?.toFixed(2),
BillAmount: (SelInvoiceAmount - TotalTaxAmount)?.toFixed(2),
TotalAmount: SelInvoiceAmount,
PurOrderInvoiceNo: purchaseOrderId,
PaymentStatus: 'S',
LocationType: SupplierData?.find(
(item) => item?.SuppId === selectedSupplierData
)?.Type,
ImageDetails: images || [],
};
const fieldsToRemove = [
'InwardDtlId',
'InwardId',
'UomName',
'ProdName',
'UOMName',
];
const processedData = filteredPurchaseData.map((item) => {
const cleanItem = { ...item };
fieldsToRemove.forEach((field) => delete cleanItem[field]);
return {
...cleanItem,
TaxType: SelectedPurcTaxType || 0,
BalanceQty: cleanItem.AcceptedQty,
OnePcsPrice: cleanItem.OnePcsPrice,
NoOfPcs: cleanItem.NoOfPcs,
};
});
const isPaidSelected = PurchaseTypeData?.some(
(item) =>
item.ConfigId === SelectedPurchaseType && item.ConfigName === 'Cash'
);
if (
(SupplierOpen !== 'own' || selectedSupplierName) &&
selectedSupplierData &&
isPaidSelected
) {
postData.PaymentAmount = PaymentAmount;
postData.PaymentType = selectedPaymentMode;
} else {
postData.PaymentType = PaymentType;
}
postData.ProdDetails = processedData;
if (formType === 'edit') {
postData.ProdId = editstate?.ProdId;
postData.InwardId = editstate?.InwardId;
postData.InwardDtlId = editstate?.InwardDtlId;
postData.UpdatedBy = UserId;
}
let response;
try {
response =
formType === 'add'
? await dispatch(postPurchaseData(postData)).unwrap()
: await dispatch(putStockData(postData)).unwrap();
} catch (err) {
response = {
data: {
statusCode: 0,
response: 'Please Give Required Fields',
},
};
}
if (response?.data?.statusCode === 1) {
navigate(`${subDirectory}setting/purchase-entry/`, {
state: {
Notiffy: {
messageType: 'success',
messageData: response?.data?.response,
},
},
});
} else {
setMessageType('error');
setMessageData(response?.data?.response);
}
};
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
const defaultColumns = [
{
title: 'IMEI 1',
dataIndex: 'imei1',
width: '30%',
editable: true,
},
{
title: 'IMEI 2',
dataIndex: 'imei2',
editable: true,
},
{
title: 'Serial No',
dataIndex: 'serialno',
editable: true,
},
{
title: 'Mac Id',
dataIndex: 'Macid',
editable: true,
},
];
const handleSave = (row) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const IMEIcolumns = defaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
}),
};
});
const handleInvoiceSearch = (value) => {
setSelectedSupplierData(null);
formRef?.current?.setFieldsValue({ CustSuppId: null });
setSelectedSupplierName(true);
setSearchText(value);
setPurchaseOrderId(null);
setSelectedInvoice(null);
setPurchaseData([]);
setProductData([]);
form?.resetFields();
};
const handleInvoiceSelect = async (value) => {
if (value === selectedInvoice) return;
const invoiceParts = value?.split('-');
const shortInvoice = invoiceParts[invoiceParts.length - 1];
formRef?.current?.setFieldsValue({ SuppInvoiceNo: value });
formRef?.current?.setFieldsValue({ PurchaseOrderNo: value });
const purchaseOrders = purchaseOrderList?.filter(
(order) => order?.PurOrderId === value
);
const supplierExists = SupplierData?.filter(
(item) => item?.SuppId === purchaseOrders?.[0]?.SuppId
);
console.log(supplierExists, 'supplierExists');
let supplierMappedProducts = [];
if (supplierExists?.length > 0) {
setSelectedSupplierData(purchaseOrders?.[0]?.SuppId);
supplierMappedProducts =
(await handleSupplierBasedProduct(purchaseOrders?.[0]?.SuppId)) || [];
formRef?.current?.setFieldsValue({
CustSuppId: purchaseOrders?.[0]?.SuppId,
});
} else {
setMessageType('error');
setMessageData("Supplier for this Order isn't Active");
return;
}
if (supplierExists?.[0]?.SuppName === 'Self') {
setSelectedSupplierName(false);
setSupplierOpen('own');
} else {
setSelectedSupplierName(true);
}
setSelectedInvoice(value);
setSearchText(shortInvoice);
if (!purchaseOrders?.[0]?.OrderDetails?.length) {
setPurchaseData([]);
return;
}
let unMappedProducts = [];
const orderedData = purchaseOrders[0].OrderDetails.map((order, index) => {
const orderedProduct = supplierMappedProducts?.find(
(prod) => prod?.ProdId === order?.ProdId
);
if (orderedProduct === undefined) {
unMappedProducts.push(`${order?.ProdName}`);
}
const DefaultVariant = orderedProduct?.ProdVariantPriceDetails?.find(
(item) =>
item?.ReceivedQty === 0 &&
item?.ProdVariantName === order?.ProdVariantName &&
item?.ProdId === order?.ProdId
)?.DefaultVariant;
const ProduData2 = {
DefaultVariant,
ProdId: orderedProduct?.ProdId,
MRP: orderedProduct?.MRP,
ProdName: orderedProduct?.ProdName,
UomName: orderedProduct?.UomName,
SellPrice: orderedProduct?.SellPrice,
StockAvailable: orderedProduct?.StockAvailable,
OnePcsAvailable: orderedProduct?.OnePcsAvailable,
NumberofPieceinside: orderedProduct?.NoOfPcs,
AmountPerPiece: orderedProduct?.OnePcsPrice,
TaxId: orderedProduct?.TaxId,
TaxPercentage: orderedProduct?.TaxPercentage,
PurOrderInvoiceNo: order?.PurOrderId,
};
const uniqueId = uuidv4();
const tempPurData = {
...ProduData2,
BalanceQty: JSON.stringify(order?.OrderQty),
InwardPrice: 0,
PurcDisc: 0,
Amount: 0,
WhSalePrice: 0,
ReceivedQty: order?.OrderQty,
AcceptedQty: JSON.stringify(order?.OrderQty),
RejectedQty: 0,
OfferPrice: 0,
SpecialPrice: 0,
ProdVariantName: order?.ProdVariantName,
FreeItem: 0,
TaxAmt: 0,
TaxType: SelectedPurcTaxType || 0,
PurcDiscType: 'P',
localId: uniqueId,
};
form.setFieldsValue({
[`BalanceQty${uniqueId}`]: JSON.stringify(order?.OrderQty),
[`ReceivedQty${uniqueId}`]: order?.OrderQty,
[`AcceptedQty${uniqueId}`]: JSON.stringify(order?.OrderQty),
});
return tempPurData;
});
const filterOrders = orderedData?.filter(
(order) => order?.ProdId !== null && order?.ProdId !== undefined
);
if (filterOrders?.length > 0) {
setPurchaseOrderId(filterOrders[0]?.PurOrderInvoiceNo);
}
setPurchaseData(filterOrders);
if (unMappedProducts?.length > 0) {
setMessageType('error');
setMessageData(
`Please map the products that are not mapped with the selected supplier.`
);
}
};
const handleOrderTypeChange = (checked) => {
const isNewOrder = checked;
const supplierData = isNewOrder
? SupplierData?.find((supplier) => supplier?.SuppName === 'Self')?.SuppId
: null;
setOrderType(isNewOrder);
setSelectedInvoice(null);
setSearchText(null);
setSelectedSupplierName(!isNewOrder);
setSupplierOpen(isNewOrder ? 'own' : null);
setSelectedSupplierData(supplierData);
setPurchaseData([]);
// setSelectedProductData(null);
setSelectedProductName(null);
// setselectedProductVariantData(null);
setInvoiceType('I');
setPurchaseStatus('P');
setProductData([]);
handleSupplierBasedProduct(supplierData);
formRef?.current?.setFieldsValue({
InvoiceType: 'I',
PurchaseOrderNo: null,
SuppInvoiceNo: null,
CustSuppId: supplierData,
ProdId: null,
OrderType: isNewOrder ? 'N' : 'O',
VarProdId: null,
});
form?.resetFields();
};
useEffect(() => {
if (additionalInfoModal) {
productAddInfoRef?.current?.setFieldsValue({
ReceivedQty: selectedRowRecord?.ReceivedQty,
RejectedQty: selectedRowRecord?.RejectedQty,
AcceptedQty: selectedRowRecord?.AcceptedQty,
FreeItem: selectedRowRecord?.FreeItem,
OfferPrice: selectedRowRecord?.OfferPrice,
WhSalePrice: selectedRowRecord?.WhSalePrice,
SpecialPrice: selectedRowRecord?.SpecialPrice,
MRP: selectedRowRecord?.MRP,
SellPrice: selectedRowRecord?.SellPrice,
AmountPerPiece: selectedRowRecord?.AmountPerPiece,
NumberofPieceinside: selectedRowRecord?.NumberofPieceinside,
});
if (applicationRestrictedFields.BatchAndModelDetails) {
productAddInfoRef?.current?.setFieldsValue({
BatchRef: selectedRowRecord?.BatchRef,
ModelNumber: selectedRowRecord?.ModelNumber,
});
}
if (applicationRestrictedFields.DatesAndExpiry) {
productAddInfoRef?.current?.setFieldsValue({
ManufDate: selectedRowRecord?.ManufDate,
ExpDate: selectedRowRecord?.ExpDate,
});
}
}
}, [additionalInfoModal]);
// command
const validateSellPrice = (record) => (_, value) => {
if (!value) {
return Promise.reject('Selling Price is required');
}
if (!/^[1-9]\d*(\.\d+)?$/.test(value)) {
return Promise.reject('Please enter a valid selling price');
}
const mrp = record?.MRP;
// const mrp = productAddInfoRef?.current?.getFieldValue('MRP');
if (parseFloat(value) > parseFloat(mrp)) {
return Promise.reject(
'Please enter selling price less than or equal to MRP'
);
}
return Promise.resolve();
};
const handleModelDataOpen = (selectedRowRecord) => {
const acceptedQty = parseInt(selectedRowRecord?.AcceptedQty) || 0;
const productIdentifiers = selectedRowRecord?.ProductIdentifierDtls || [];
let finalCombined = productIdentifiers.map((device, idx) => ({
key: idx,
column1: `Row ${idx + 1} Col 1`,
imei1: device?.IMEI1 || null,
imei2: device?.IMEI2 || null,
Macid: device?.MacId || null,
serialno: device?.SerialNumber || null,
}));
if (finalCombined.length > 0) {
if (finalCombined.length < acceptedQty) {
const rowsToAdd = acceptedQty - finalCombined.length;
for (let i = 0; i < rowsToAdd; i++) {
finalCombined.push({
key: finalCombined.length + i,
column1: `Row ${finalCombined.length + i + 1} Col 1`,
imei1: null,
imei2: null,
Macid: null,
serialno: null,
});
}
}
setDataSource(finalCombined);
setimeiSerialOpen(true);
} else {
if (acceptedQty > 0) {
if (dataSourceBackup.length === 0 || dataSource.length === 0) {
const newEmptyData = Array(acceptedQty)
.fill(null)
.map((_, index) => ({
key: index,
column1: `Row ${index + 1} Col 1`,
}));
setDataSource(newEmptyData);
} else {
setDataSource(dataSourceBackup);
}
setimeiSerialOpen(true);
} else {
setMessageType('error');
setMessageData('Enter Qty');
}
}
};
const handleModelDataSumbitOrClose = () => {
setimeiSerialOpen(false);
const productIdentifierDtls = dataSource
?.filter(
(item) => item.serialno || item.imei1 || item.imei2 || item.Macid
)
?.map((item) => ({
SerialNumber: item.serialno || '',
IMEI1: item.imei1 || '',
IMEI2: item.imei2 || '',
MacId: item.Macid || '',
}));
const newData = PurchaseData.map((item, index) =>
index === selectedRowIndex
? { ...item, ProductIdentifierDtls: productIdentifierDtls }
: item
);
setPurchaseData(newData);
};
const handleFieldSetupSubmit = async ({
selectedFields,
tempSelectedColumns,
closeModal,
resetTemp,
}) => {
const postData = {
AppId,
CompId,
BranchId,
Type: 'PE',
FormType: 'Purchase Entry',
TypeId: categoryId,
ConfigDtl: selectedFields.map((field) => ({
ConfigId: field,
Access: 'Y',
})),
CreatedBy: UserId,
};
const response = await dispatch(postFieldSetup(postData))?.unwrap();
if (response?.data?.statusCode === 1) {
setSelectedAdditionalColumn([...tempSelectedColumns]);
closeModal();
resetTemp();
setMessageType('success');
setMessageData(response?.data?.response);
await getFieldSetup();
} else {
setMessageType('error');
setMessageData('Failed to set up fields');
}
};
const handleModalSubmited = () => {
setIsModalOpen(false);
};
const handleSupplierBasedProduct = async (SuppId) => {
const Type = SupplierData?.find((find) => find.SuppId === SuppId)?.Type;
const LocationType =
Type === 'Supplier'
? 'S'
: Type === 'Branch'
? 'B'
: Type === 'WareHouse'
? 'W'
: '';
const productResponse = await dispatch(
getSupplaierIdwithTypeBasedProducts({
CompId,
AppId,
BranchId,
SuppId,
LocationType,
})
).unwrap();
setPurchaseData([]);
if (productResponse?.data?.statusCode === 1) {
setProductData(productResponse?.data?.data);
return productResponse?.data?.data;
} else {
setProductData([]);
return [];
}
};
const validatePhoneNumber = (rule, value, callback) => {
if (value && value?.length !== 10) {
callback();
} else {
callback();
}
};
const validateEmail = (rule, value, callback) => {
const regex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (!value || regex.test(value)) {
callback();
} else {
callback('Please enter a valid Mail Id');
}
};
const deliveryPerformance = async () => {
let response = await dispatch(
getConfigType({ TypeName: 'Delivery Performance' })
).unwrap();
SetDeleveryPerformanceData(response?.data?.data);
};
const discountLevel = async () => {
let response = await dispatch(
getConfigType({ TypeName: 'Discount Level' })
).unwrap();
setDiscountData(response?.data?.data);
};
const qualityofSupp = async () => {
let response = await dispatch(
getConfigType({ TypeName: 'Quality Of Supplier' })
).unwrap();
setQualityData(response?.data?.data);
};
const handleDeliveryPerformanceChange = (value) => {
formSupplierRef?.current?.setFieldsValue({ DeliveryPerformance: value });
setDeliveryValue(value);
};
const handleDiscountLevelChange = (value) => {
formSupplierRef?.current?.setFieldsValue({ DiscountLevel: value });
setDicountValue(value);
};
const handleQualityofSuppChange = (value) => {
formSupplierRef?.current?.setFieldsValue({ QualityofSupp: value });
setQualityValue(value);
};
const ViewMoreFields = () => setViewDtl((prev) => !prev);
const handlePaymentModeChange = (modeId) => {
setPayAmountDisable(
paymentOptions
?.find((option) => option?.ModeId === modeId)
?.ModeName?.toLowerCase() === 'credit'
);
setSelectedPaymentMode(modeId);
formRef.current?.setFieldsValue({ PaymentMode: modeId });
};
return (
{isLoading && (
{loadingText &&
{loadingText}
}
)}
setExtractorModalVisible(true)}
>
{' '}
Scan Receipt (Auto-Fill)
navigate(`${subDirectory}setting/purchase-entry`)
}
>
View Entry List
{OpenSupplierModel && (
)}
{imeiSerialOpen && (
'editable-row'}
bordered
dataSource={dataSource}
columns={IMEIcolumns}
pagination={{ showSizeChanger: false }}
/>
)}
setExtractorModalVisible(false)}
onApply={handleExtractorApply}
productData={productData}
supplierData={SupplierData}
uomData={UomData}
setVisible={setExtractorModalVisible}
/>
);
};
export default StockForm;