2026-01-27 18:27:29 +05:30
|
|
|
|
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,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
SearchOutlined,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
} from '@ant-design/icons';
|
2026-02-06 14:36:25 +05:30
|
|
|
|
import { Form, Tooltip, Table, Input, AutoComplete, Switch } from 'antd';
|
|
|
|
|
|
import { IoAddCircleSharp } from 'react-icons/io5';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
import { InputField } from '../../Components/Forms/InputField.jsx';
|
|
|
|
|
|
import Buttons from '../../Components/Forms/Buttons.jsx';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
import { Modal } from 'antd';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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,
|
2026-02-06 14:36:25 +05:30
|
|
|
|
putStockData,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
} from '../../Features/StockMaster/StockMaster.js';
|
|
|
|
|
|
import '../../Styles/Stock/StockMaster.scss';
|
|
|
|
|
|
import {
|
|
|
|
|
|
getAdmin,
|
|
|
|
|
|
getUomData,
|
|
|
|
|
|
getProdCatData,
|
|
|
|
|
|
uomDataSelector,
|
|
|
|
|
|
postSupplier,
|
|
|
|
|
|
getProductTypeData,
|
2026-01-28 15:50:57 +05:30
|
|
|
|
bulkpostdata,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
postFieldSetup,
|
|
|
|
|
|
getFieldSetupData,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
} 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';
|
2026-02-03 13:55:24 +05:30
|
|
|
|
import { FaLink, FaEye } from 'react-icons/fa';
|
|
|
|
|
|
import { TbUpload } from 'react-icons/tb';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
import {
|
|
|
|
|
|
getSupplaierIdBasedProducts,
|
|
|
|
|
|
getSupplaierIdwithTypeBasedProducts,
|
|
|
|
|
|
postSupplaierProducts,
|
|
|
|
|
|
} from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
|
2026-02-03 13:55:24 +05:30
|
|
|
|
import {
|
|
|
|
|
|
ApplicationPreferences,
|
|
|
|
|
|
getCommonAppPreference,
|
|
|
|
|
|
} from '../../Features/BrachLogin/BranchLogin.js';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
import {
|
|
|
|
|
|
getConfigType,
|
|
|
|
|
|
getPaymentOptionFeatureApi,
|
|
|
|
|
|
PendingOrdersPE,
|
|
|
|
|
|
} from '../../Features/BookingScreen/BookingData/BookingData.js';
|
|
|
|
|
|
import InvoiceImageExtractorModal from './InvoiceImageExtractor.jsx';
|
|
|
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
2026-02-06 14:36:25 +05:30
|
|
|
|
import AddAllProductsButton from './AddAllProductGrid.jsx';
|
|
|
|
|
|
import SettingsIconWithModal from './SettingsIconWithModal.jsx';
|
|
|
|
|
|
import VirtualizedTable from './VirtualizedTable.jsx';
|
|
|
|
|
|
import { useDebounce } from './UseDebounce.jsx';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
const subDirectory = import.meta.env.BASE_URL;
|
|
|
|
|
|
const EditableContext = React.createContext(null);
|
|
|
|
|
|
const EditableRow = ({ index, ...props }) => {
|
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Form form={form} component={false}>
|
|
|
|
|
|
<EditableContext.Provider value={form}>
|
|
|
|
|
|
<tr {...props} />
|
|
|
|
|
|
</EditableContext.Provider>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const 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 ? (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
style={{
|
|
|
|
|
|
margin: 0,
|
|
|
|
|
|
}}
|
|
|
|
|
|
name={dataIndex}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
|
onPressEnter={save}
|
|
|
|
|
|
onBlur={save}
|
|
|
|
|
|
onMouseLeave={save}
|
|
|
|
|
|
value={
|
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="editable-cell-value-wrap"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
paddingRight: 24,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
cursor: 'pointer',
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}}
|
|
|
|
|
|
onClick={toggleEdit}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
ref={inputRef}
|
|
|
|
|
|
onPressEnter={save}
|
|
|
|
|
|
onBlur={save}
|
|
|
|
|
|
value={
|
|
|
|
|
|
Array.isArray(record[dataIndex]) ? undefined : record[dataIndex]
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return <td {...restProps}>{childNode}</td>;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const StockForm = ({ formType }) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
console.log('counttesttttttttttttttttttt');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const formRef = useRef(null);
|
|
|
|
|
|
const productAddInfoRef = useRef(null);
|
|
|
|
|
|
const formProductRef = useRef(null);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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;
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const CompId = getSession('CompId');
|
|
|
|
|
|
const BranchId = getSession('BranchId');
|
|
|
|
|
|
const AppId = getSession('AppId');
|
|
|
|
|
|
const UserId = getSession('UserId');
|
|
|
|
|
|
const UomData = useSelector(uomDataSelector);
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const appPreferences = useSelector(ApplicationPreferences);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const [applicationRestrictedFields, setApplicationRestrictedFields] =
|
|
|
|
|
|
useState({
|
|
|
|
|
|
DatesAndExpiry: false,
|
|
|
|
|
|
BatchAndModelDetails: false,
|
|
|
|
|
|
AmountPerPieceDetail: false,
|
|
|
|
|
|
});
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
|
|
|
|
|
const [editingQty, setEditingQty] = useState({});
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const [selectedAdditionalColumn, setSelectedAdditionalColumn] = useState([]);
|
|
|
|
|
|
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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();
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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());
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const [SuppInvoiceDate, setSuppInvoiceDate] = useState();
|
|
|
|
|
|
const [invoiceType, setInvoiceType] = useState('I');
|
|
|
|
|
|
const [PurchaseDate, setPurchaseDate] = useState();
|
|
|
|
|
|
const [paymentAmount, setPaymentAmount] = useState(null);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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('');
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// const [filteredPurchaseData, setFilteredPurchaseData] = useState([]);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const [searchValue, setSearchValue] = useState('');
|
|
|
|
|
|
const isSearching = Boolean(searchValue?.trim());
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const SelInvoiceAmount = useMemo(() => {
|
|
|
|
|
|
const total = PurchaseData?.reduce(
|
|
|
|
|
|
(acc, item) => acc + Number(item?.Amount || 0),
|
|
|
|
|
|
0
|
|
|
|
|
|
);
|
|
|
|
|
|
return !isNaN(total) && total !== 0 ? total : null;
|
|
|
|
|
|
}, [PurchaseData]);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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())
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
}, [PurchaseData, searchValue]);
|
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const items = [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'Home',
|
|
|
|
|
|
link: `${subDirectory}app-page/home`,
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'Product Receipt',
|
|
|
|
|
|
link: `${subDirectory}setting/purchase-entry`,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: editstate ? 'Edit' : 'New',
|
|
|
|
|
|
link: null,
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const categoryId = appPreferences?.find(
|
2026-02-03 13:55:24 +05:30
|
|
|
|
(p) => p?.PreferredCatName?.toLowerCase() === 'purchase entry'
|
2026-01-30 19:09:15 +05:30
|
|
|
|
)?.PreferredCatId;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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({});
|
|
|
|
|
|
|
|
|
|
|
|
if (formType == 'add') {
|
|
|
|
|
|
formRef.current?.setFieldsValue({ SuppInvoiceDate: new Date().toJSON() });
|
|
|
|
|
|
setSuppInvoiceDate(new Date().toJSON());
|
|
|
|
|
|
formRef.current?.setFieldsValue({ InvoiceDate: new Date().toJSON() });
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setInvoiceDate(new Date().toJSON());
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setSelectedProductData(editstate?.ProdId);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setSelectedSupplierData(editstate?.SuppId);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (SupplierOpen !== 'own') {
|
|
|
|
|
|
getPurchaseOrders();
|
|
|
|
|
|
fetchPaymentOptions();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
}, [SupplierOpen]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
getFieldSetup();
|
|
|
|
|
|
}, [categoryId]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (initialLoad && SupplierData?.length > 0) {
|
|
|
|
|
|
SetSelfSupplier();
|
|
|
|
|
|
setInitialLoad(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
}, [SupplierData]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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') || ''
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
}, [selectedSupplierData]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
return () => {
|
|
|
|
|
|
debouncedScannerSearch.cancel();
|
|
|
|
|
|
};
|
|
|
|
|
|
}, []);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const getSuplaierApi = async ({ dataReturn = false }) => {
|
|
|
|
|
|
const response = await dispatch(
|
|
|
|
|
|
getPurchaseSupplierAndWareHouseData({ CompId, AppId, BranchId })
|
|
|
|
|
|
).unwrap();
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (response?.statusCode === 1) {
|
|
|
|
|
|
setSupplierData(response?.data);
|
|
|
|
|
|
if (dataReturn) {
|
|
|
|
|
|
return response?.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setSupplierData([]);
|
|
|
|
|
|
if (dataReturn) {
|
|
|
|
|
|
return [];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
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.');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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.',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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 };
|
|
|
|
|
|
};
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const getFieldSetup = async () => {
|
|
|
|
|
|
try {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const response = await dispatch(
|
|
|
|
|
|
getFieldSetupData({ AppId, CompId, BranchId, categoryId, Type: 'PE' })
|
|
|
|
|
|
).unwrap();
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (response?.data?.statusCode === 1) {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
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,
|
|
|
|
|
|
})) || []
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Error fetching field setup:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const AddSupplierimg = async (subSupplierData) => {
|
|
|
|
|
|
const addSupplierData = {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
CompId: CompId,
|
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
|
BranchId: BranchId,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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 = [];
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const NewImageProducts = [];
|
|
|
|
|
|
console.log(unmatchedProducts, 'unmatchedProductsunmatchedProducts');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
// 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);
|
2026-02-03 13:55:24 +05:30
|
|
|
|
} else {
|
2026-01-28 15:50:57 +05:30
|
|
|
|
NewImageProducts.push(item?.parsedData);
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
});
|
2026-01-28 15:50:57 +05:30
|
|
|
|
// Bulk upload new image products
|
|
|
|
|
|
if (NewImageProducts.length > 0) {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const newProductsData = NewImageProducts.map((product) => ({
|
2026-01-30 19:09:15 +05:30
|
|
|
|
AppId: AppId || 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
CompId: CompId || '',
|
|
|
|
|
|
BranchId: BranchId || '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
CreatedBy: UserId || 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
ProdName: product.description?.trim() || '',
|
|
|
|
|
|
ProdVariantName: '',
|
|
|
|
|
|
Size: 1 || '',
|
|
|
|
|
|
UOM: product.unit || '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
MRP: parseFloat(product.rate) || 0,
|
|
|
|
|
|
WhSalePrice: 0,
|
|
|
|
|
|
SellPrice: parseFloat(product.rate) || 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
ProdCat: 'General',
|
|
|
|
|
|
ProdSubCat: '',
|
|
|
|
|
|
Brand: '',
|
|
|
|
|
|
AutoGenerateQr: '',
|
|
|
|
|
|
QRCode: '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
StockAvailable: 'No',
|
2026-02-03 13:55:24 +05:30
|
|
|
|
HSNCode: '',
|
|
|
|
|
|
PartNumber: '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
Rack: 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
ManufDate: '',
|
|
|
|
|
|
ExpDate: '',
|
|
|
|
|
|
AvailableFrom: '',
|
|
|
|
|
|
AvailableTo: '',
|
|
|
|
|
|
ProdLogo: '',
|
|
|
|
|
|
OnePcsAvailable: 'No',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
AutoGenerateSingleQr: 'No',
|
|
|
|
|
|
TaxId: 'NIL - 0%',
|
2026-02-03 13:55:24 +05:30
|
|
|
|
OnePcQR: '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
TokenAvailable: 'No',
|
|
|
|
|
|
OpeningQty: 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
QtyBasedPrice: '',
|
|
|
|
|
|
InwardDate: '',
|
|
|
|
|
|
SuppId: suppId || '',
|
|
|
|
|
|
Reference: '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
ReceivedQty: 0,
|
|
|
|
|
|
AcceptedQty: 0,
|
|
|
|
|
|
RejectedQty: 0,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
RejectionReason: '',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
IssuedQty: 0,
|
|
|
|
|
|
BalanceQty: 0,
|
|
|
|
|
|
InwardPrice: 0,
|
|
|
|
|
|
OfferPrice: 0,
|
|
|
|
|
|
SpecialPrice: 0,
|
|
|
|
|
|
Cess: 0,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const bulkResponse = await dispatch(
|
|
|
|
|
|
bulkpostdata({ ProdDetails: newProductsData })
|
|
|
|
|
|
).unwrap();
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
|
|
|
|
|
if (bulkResponse?.data?.statusCode === 1) {
|
|
|
|
|
|
// After successful bulk upload, check the condition again
|
|
|
|
|
|
const updatedResponse = await dispatch(
|
2026-02-03 13:55:24 +05:30
|
|
|
|
getSupplaierIdBasedProducts({
|
|
|
|
|
|
CompId,
|
|
|
|
|
|
AppId,
|
|
|
|
|
|
BranchId,
|
|
|
|
|
|
SuppId: suppId,
|
|
|
|
|
|
})
|
2026-01-30 19:09:15 +05:30
|
|
|
|
).unwrap();
|
|
|
|
|
|
if (updatedResponse?.data?.statusCode === 1) {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const updatedAllSupplierProducts =
|
|
|
|
|
|
updatedResponse?.data?.data || [];
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const updatedMatchingProdIds = [];
|
|
|
|
|
|
|
|
|
|
|
|
unmatchedProducts.forEach((item) => {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const match =
|
|
|
|
|
|
updatedAllSupplierProducts?.[0]?.ProductDetails.find(
|
|
|
|
|
|
(supp) =>
|
|
|
|
|
|
supp?.ProdName?.toLowerCase() ===
|
|
|
|
|
|
item?.parsedData?.description?.toLowerCase()
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (match) {
|
|
|
|
|
|
updatedMatchingProdIds.push(match.ProdId);
|
2026-01-28 15:50:57 +05:30
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (updatedMatchingProdIds.length > 0) {
|
|
|
|
|
|
matchingProdIds.push(...updatedMatchingProdIds);
|
2026-01-28 15:50:57 +05:30
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-28 15:50:57 +05:30
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
// 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(
|
2026-01-30 19:09:15 +05:30
|
|
|
|
item?.selectedProduct.ProdVariantName,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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) {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// const index = purchasedData.indexOf(item);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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(
|
2026-01-30 19:09:15 +05:30
|
|
|
|
item?.selectedProduct?.ProdVariantName,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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) {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// const index = purchasedData.indexOf(item);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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) {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setPurcTaxTypeData(res?.data?.data);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
let tempniltax = res?.data?.data?.find(
|
|
|
|
|
|
(item) => item?.ConfigName?.toLowerCase() === 'inclusive'
|
|
|
|
|
|
);
|
|
|
|
|
|
setSelectedPurcTaxType(tempniltax?.ConfigId);
|
|
|
|
|
|
formRef.current?.setFieldsValue({ TaxType: tempniltax?.ConfigId });
|
|
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// else {
|
|
|
|
|
|
// setPurcTaxTypeData(null);
|
|
|
|
|
|
// }
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
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) => {
|
2026-01-28 15:50:57 +05:30
|
|
|
|
const value = e.target.value;
|
|
|
|
|
|
formRef.current?.setFieldsValue({ SuppInvoiceNo: value });
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setExtractorData((prev) => (prev ? { ...prev, invoiceNo: value } : null));
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setselectedProductVariantData(null);
|
|
|
|
|
|
// setSelectedProductData(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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 (
|
2026-01-30 19:09:15 +05:30
|
|
|
|
VariantName,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
ProdId,
|
|
|
|
|
|
option,
|
|
|
|
|
|
productsList,
|
|
|
|
|
|
extractedProduct = false,
|
|
|
|
|
|
extractedItem,
|
|
|
|
|
|
existingProducts
|
|
|
|
|
|
) => {
|
|
|
|
|
|
setProductSearchText('');
|
|
|
|
|
|
setSelectedProductName(option?.label ? option?.label : '');
|
|
|
|
|
|
formRef?.current?.resetFields(['VarProdId']);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setselectedProductVariantData(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (true) {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
formRef.current?.setFieldsValue({ ProdId: ProdId });
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// await setSelectedProductData(ProdId);
|
|
|
|
|
|
|
2026-02-03 13:55:24 +05:30
|
|
|
|
if (
|
|
|
|
|
|
(existingProducts || PurchaseData)?.some(
|
|
|
|
|
|
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
|
|
|
|
|
|
)
|
|
|
|
|
|
) {
|
|
|
|
|
|
const existingProduct = (existingProducts || PurchaseData)?.find(
|
|
|
|
|
|
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setMessageType('error');
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageData(
|
|
|
|
|
|
`Product "${existingProduct?.ProdName} - ${existingProduct?.ProdVariantName}" already exists`
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
return null;
|
2026-02-03 13:55:24 +05:30
|
|
|
|
} else {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
let ProductData1 = (productsList || productData)?.find(
|
2026-01-30 19:09:15 +05:30
|
|
|
|
(e) => e.ProdId == ProdId && e?.ProdVariantName == VariantName
|
2026-01-27 18:27:29 +05:30
|
|
|
|
);
|
|
|
|
|
|
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,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
OnePcsPrice: ProductData1?.OnePcsPrice,
|
|
|
|
|
|
NoOfPcs: ProductData1?.NoOfPcs,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
TaxId: ProductData1?.TaxId,
|
|
|
|
|
|
TaxPercentage: ProductData1?.TaxPercentage,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
ProdVariantName: ProductData1?.ProdVariantName,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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 || '');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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(
|
2026-01-30 19:09:15 +05:30
|
|
|
|
matchedProduct?.ProdVariantName,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
matchedProduct.ProdId,
|
|
|
|
|
|
productName
|
|
|
|
|
|
);
|
|
|
|
|
|
if (newProduct) {
|
|
|
|
|
|
setPurchaseData([newProduct, ...PurchaseData]);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (matchedProduct?.ProdVariantPriceDetails?.length < 2) {
|
|
|
|
|
|
setSelectedProductName('');
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setSelectedProductData(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData('The Scanned Product not Available in Product List');
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300),
|
|
|
|
|
|
[productData]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// Clean up debounce on unmount
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setselectedProductVariantData(null);
|
|
|
|
|
|
// setVariants(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
formRef?.current?.setFieldsValue({
|
|
|
|
|
|
ProdId: null,
|
|
|
|
|
|
VarProdId: null,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const addSupplier = () => {
|
|
|
|
|
|
setOpenSupplierModel(true);
|
|
|
|
|
|
};
|
|
|
|
|
|
const handleSupplier = () => {
|
|
|
|
|
|
setOpenSupplierModel(false);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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,
|
|
|
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!Delete && applicationRestrictedFields.BatchAndModelDetails) {
|
|
|
|
|
|
values[`BatchRef${localId}`] = record.BatchRef;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
|
|
|
|
|
form.setFieldsValue(values);
|
|
|
|
|
|
setDelete(false);
|
|
|
|
|
|
}, [editingKey]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const save = async (localId) => {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
try {
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const row = await form.validateFields();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
|
|
const modifiedObject = {};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
for (const key in row) {
|
2026-01-30 19:09:15 +05:30
|
|
|
|
// remove localId suffix from field names
|
|
|
|
|
|
if (key.endsWith(localId)) {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const newKey = key?.replace(localId, '');
|
2026-01-30 19:09:15 +05:30
|
|
|
|
modifiedObject[newKey] = row[key];
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
2026-02-03 13:55:24 +05:30
|
|
|
|
item.localId === localId ? { ...item, ...modifiedObject } : item
|
2026-01-30 19:09:15 +05:30
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
setEditingKey('');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('Save failed:', err);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const handleKeyPress = async (e, record) => {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await form.validateFields();
|
2026-01-30 19:09:15 +05:30
|
|
|
|
save(record.localId);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('Save failed:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const formatDateForDisplay = (dateString) => {
|
|
|
|
|
|
if (!dateString) return '';
|
|
|
|
|
|
return moment(dateString).format('DD-MMM-YY');
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
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);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const updateRowValue = (localId, key, value) => {
|
|
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === localId ? { ...item, [key]: value } : item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
|
[`${key}${localId}`]: value,
|
|
|
|
|
|
});
|
2026-02-03 13:55:24 +05:30
|
|
|
|
};
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const columns = useMemo(() => {
|
|
|
|
|
|
const baseColumns = [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'SL.NO',
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
key: 'sno',
|
|
|
|
|
|
width: 50,
|
|
|
|
|
|
render: (text, object, index) => (
|
|
|
|
|
|
<a style={{ color: 'black' }}>{index + 1}</a>
|
|
|
|
|
|
),
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{
|
|
|
|
|
|
title: 'Name',
|
|
|
|
|
|
dataIndex: 'ProdName',
|
|
|
|
|
|
key: 'ProdName',
|
|
|
|
|
|
align: 'left',
|
|
|
|
|
|
width: 150,
|
|
|
|
|
|
render: (text, record, index) => (
|
|
|
|
|
|
<a style={{ color: 'black' }}>{record?.ProdName}</a>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Variant',
|
|
|
|
|
|
dataIndex: 'ProdVariantName',
|
|
|
|
|
|
key: 'ProdVariantName',
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
render: (text, record, index) => (
|
|
|
|
|
|
<a style={{ color: 'black' }}>{record?.ProdVariantName}</a>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
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 (
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// autoFocus
|
|
|
|
|
|
value={editingQty[record.localId] ?? record.BalanceQty}
|
|
|
|
|
|
onChange={(e) => handleQtyTyping(e, record)}
|
|
|
|
|
|
onBlur={() => commitQtyChange(record)}
|
|
|
|
|
|
onPressEnter={() => commitQtyChange(record)}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
inputMode="decimal"
|
|
|
|
|
|
onInput={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
let v = e.target.value.replace(/[^0-9.]/g, '');
|
|
|
|
|
|
if (v.startsWith('.')) v = '0' + v;
|
|
|
|
|
|
const parts = v.split('.');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
e.target.value =
|
|
|
|
|
|
parts.length > 2
|
|
|
|
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
2026-02-06 14:36:25 +05:30
|
|
|
|
: v;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{
|
|
|
|
|
|
title: 'Pur Rate / unit',
|
|
|
|
|
|
dataIndex: 'InwardPrice',
|
|
|
|
|
|
key: 'InwardPrice',
|
|
|
|
|
|
width: 120,
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
|
const editable = true;
|
|
|
|
|
|
|
|
|
|
|
|
return editable ? (
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record.InwardPrice ?? 0}
|
|
|
|
|
|
maxLength={10}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
inputMode="decimal"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
onChange={(e) => handlePurrateTyping(e, record)}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
) : (
|
|
|
|
|
|
<div
|
|
|
|
|
|
// onClick={() => edit(record)} // ✅ THIS is required
|
|
|
|
|
|
style={{ cursor: 'pointer' }}
|
|
|
|
|
|
>
|
|
|
|
|
|
{record.InwardPrice || 0}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
title: (
|
|
|
|
|
|
<Tooltip title="GST (CGST + SGST or IGST)" placement="top">
|
|
|
|
|
|
Tax (%)
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
),
|
|
|
|
|
|
dataIndex: 'PurchaseTax',
|
|
|
|
|
|
key: 'PurchaseTax',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
|
<Input
|
|
|
|
|
|
value={record.PurchaseTax ?? ''}
|
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
|
onChange={(e) => 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 (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
placeholder="MRP"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record?.MRP ?? ''}
|
|
|
|
|
|
maxLength={10}
|
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
|
onChange={(e) => handleMRPChange(e, record)}
|
|
|
|
|
|
onBlur={(e) => handleMRPBlur(e, record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onPressEnter={(e) => handleKeyPress(e, record)}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
},
|
|
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
{
|
|
|
|
|
|
title: (
|
|
|
|
|
|
<Tooltip title="Selling price per unit" placement="top">
|
|
|
|
|
|
Selling Price
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
),
|
|
|
|
|
|
dataIndex: 'SellPrice',
|
|
|
|
|
|
key: 'SellPrice',
|
|
|
|
|
|
width: 100,
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
|
return (
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
value={record?.SellPrice ?? ''}
|
|
|
|
|
|
maxLength={10}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
inputMode="decimal"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
onChange={(e) => handleSellPriceChange(e, record)}
|
|
|
|
|
|
onBlur={(e) => handleSellPriceBlur(e, record)}
|
|
|
|
|
|
onPressEnter={(e) => handleKeyPress(e, record)}
|
|
|
|
|
|
onInput={handleDecimalInput}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
...(selectedAdditionalColumn.includes('Amount Per Piece')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Amount per piece',
|
|
|
|
|
|
dataIndex: 'OnePcsPrice',
|
|
|
|
|
|
key: 'OnePcsPrice',
|
|
|
|
|
|
width: 70,
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (_, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
disabled={record?.OnePcsAvailable === 'N'}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
placeholder="OnePcsPrice"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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;
|
|
|
|
|
|
}}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Amount Per Piece')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Number of piece',
|
|
|
|
|
|
dataIndex: 'NoOfPcs',
|
|
|
|
|
|
key: 'NoOfPcs',
|
|
|
|
|
|
width: 70,
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (_, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
disabled={record?.OnePcsAvailable === 'N'}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
placeholder="NoOfPcs"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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;
|
|
|
|
|
|
}}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Wholesale Price')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Wholesale price',
|
|
|
|
|
|
dataIndex: 'WhSalePrice',
|
|
|
|
|
|
key: 'WhSalePrice',
|
|
|
|
|
|
width: 70,
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (_, record) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
placeholder="WhSalePrice"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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;
|
2026-02-03 13:55:24 +05:30
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Manufacture Date')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Manuf.Date',
|
|
|
|
|
|
dataIndex: 'ManufDate',
|
|
|
|
|
|
key: 'ManufDate',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<DatePicProd
|
|
|
|
|
|
canSelectPast={true}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
cancelFuture={true}
|
|
|
|
|
|
valueData={record.ManufDate}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(date, dateString) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// 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
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const newData = PurchaseData.map((item) =>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
item.localId === record.localId
|
2026-02-03 13:55:24 +05:30
|
|
|
|
? { ...item, ManufDate: formattedDate }
|
|
|
|
|
|
: item
|
|
|
|
|
|
);
|
|
|
|
|
|
setPurchaseData(newData);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Expiry Date')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Exp.Date',
|
|
|
|
|
|
dataIndex: 'ExpDate',
|
|
|
|
|
|
key: 'ExpDate',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<DatePicProd
|
|
|
|
|
|
canSelectPast={false}
|
|
|
|
|
|
cancelFuture={false}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
valueData={record.ExpDate}
|
|
|
|
|
|
onChange={(date, dateString) =>
|
|
|
|
|
|
handleExpDateChange(dateString, record)
|
|
|
|
|
|
}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Hsn')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Hsn',
|
|
|
|
|
|
dataIndex: 'Hsn',
|
|
|
|
|
|
key: 'Hsn',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
// width: 130,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
placeholder="HSN code"
|
|
|
|
|
|
value={record.PurchaseHSNCode || ''}
|
|
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
onPressEnter={() => handleKeyPress(record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const value = e.target.value;
|
|
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, PurchaseHSNCode: value }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
2026-02-03 13:55:24 +05:30
|
|
|
|
);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Model No')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Model',
|
|
|
|
|
|
dataIndex: 'Model',
|
|
|
|
|
|
key: 'Model',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record.ModelNumber || ''}
|
|
|
|
|
|
placeholder="Model No"
|
|
|
|
|
|
// autoFocus={isEditing(record)} // autofocus only if this row is being edited
|
|
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
onPressEnter={() => handleKeyPress(record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const value = e.target.value;
|
|
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, ModelNumber: value }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
2026-02-03 13:55:24 +05:30
|
|
|
|
);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Batch No')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Batch',
|
|
|
|
|
|
dataIndex: 'Batch',
|
|
|
|
|
|
key: 'Batch',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record.BatchRef || ''}
|
|
|
|
|
|
placeholder="Batch No"
|
|
|
|
|
|
// autoFocus={isEditing(record, index)}
|
|
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
onPressEnter={() => handleKeyPress(record, index)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const value = e.target.value;
|
|
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, BatchRef: value }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
2026-02-03 13:55:24 +05:30
|
|
|
|
);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Rejected Qty')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Rejected Qty',
|
|
|
|
|
|
dataIndex: 'RejectedQty',
|
|
|
|
|
|
key: 'RejectedQty',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record.RejectedQty ?? 0}
|
|
|
|
|
|
placeholder="Rejected Qty"
|
|
|
|
|
|
// autoFocus={isEditing(record, index)}
|
|
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
onPressEnter={() => handleKeyPress(record, index)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const rejectedQty = parseFloat(inputValue) || 0;
|
|
|
|
|
|
const receivedQty = parseFloat(record.ReceivedQty) || 0;
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// validation
|
|
|
|
|
|
if (rejectedQty >= receivedQty) {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData(
|
2026-02-06 14:36:25 +05:30
|
|
|
|
'Rejected Qty cannot be greater than or equal to Received Qty'
|
2026-02-03 13:55:24 +05:30
|
|
|
|
);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const acceptedQty = receivedQty - rejectedQty;
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
)
|
2026-02-03 13:55:24 +05:30
|
|
|
|
);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
|
|
...(selectedAdditionalColumn.includes('Free Qty')
|
|
|
|
|
|
? [
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Free Qty',
|
|
|
|
|
|
dataIndex: 'Freeqty',
|
|
|
|
|
|
key: 'Freeqty',
|
|
|
|
|
|
editable: true,
|
|
|
|
|
|
render: (text, record) => {
|
|
|
|
|
|
return (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<Input
|
2026-02-06 14:36:25 +05:30
|
|
|
|
value={record.Freeqty ?? ''}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
placeholder="Free Qty"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// autoFocus={isEditing(record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
inputMode="numeric"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onClick={() => edit(record)}
|
|
|
|
|
|
onFocus={(e) => e.stopPropagation()}
|
|
|
|
|
|
onPressEnter={() => handleKeyPress(record)}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
onChange={(e) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
|
|
|
|
|
|
updateRowValue(record.localId, 'Freeqty', value);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
|
|
|
|
|
|
...(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 (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<IoAddCircleSharp
|
|
|
|
|
|
style={{
|
2026-02-06 14:36:25 +05:30
|
|
|
|
cursor: isClickable ? 'pointer' : 'not-allowed',
|
|
|
|
|
|
color: isClickable ? '#1890ff' : '#d9d9d9',
|
|
|
|
|
|
fontSize: 20,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
}}
|
|
|
|
|
|
onClick={() => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!isClickable) {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData('Please Enter Qty');
|
2026-02-06 14:36:25 +05:30
|
|
|
|
return;
|
2026-02-03 13:55:24 +05:30
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setSelectedRowIndex(index);
|
|
|
|
|
|
handleModelDataOpen(record);
|
2026-02-03 13:55:24 +05:30
|
|
|
|
}}
|
|
|
|
|
|
className="shape-preview"
|
|
|
|
|
|
/>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
);
|
|
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
2026-02-06 14:36:25 +05:30
|
|
|
|
]
|
|
|
|
|
|
: []),
|
|
|
|
|
|
{
|
|
|
|
|
|
title: 'Action',
|
|
|
|
|
|
dataIndex: 'Action',
|
|
|
|
|
|
key: 'Action',
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
width: 80,
|
|
|
|
|
|
render: (_, record, index) => (
|
|
|
|
|
|
<a
|
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
e.stopPropagation();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
>
|
|
|
|
|
|
<DeleteFilled
|
|
|
|
|
|
style={{
|
|
|
|
|
|
color: '#FF4D4F',
|
|
|
|
|
|
}}
|
|
|
|
|
|
onClick={() => statusFormatters(record)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
),
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
return baseColumns;
|
|
|
|
|
|
}, [editingKey, editingQty, selectedAdditionalColumn]);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const statusFormatters = (record) => {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const localId = record?.localId;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) => prev.filter((item) => item.localId !== localId));
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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);
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// 3️⃣ Clear other single fields
|
2026-01-30 19:09:15 +05:30
|
|
|
|
formRef?.current?.setFieldsValue({
|
|
|
|
|
|
ProdId: null,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setDelete(true); // only if absolutely necessary
|
|
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleQtyTyping = (e, record) => {
|
|
|
|
|
|
let value = e.target.value;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// allow only numbers + decimal
|
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// 🔥 remove leading zero (but keep "0." valid)
|
|
|
|
|
|
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
|
|
|
|
|
|
value = value.replace(/^0+/, '');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setEditingQty((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
[record.localId]: value,
|
|
|
|
|
|
}));
|
|
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const commitQtyChange = (record) => {
|
|
|
|
|
|
const { localId } = record;
|
|
|
|
|
|
const qty = Number(editingQty[localId]) || 0;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
|
[`BalanceQty${localId}`]: qty,
|
|
|
|
|
|
[`ReceivedQty${localId}`]: qty,
|
2026-02-06 14:36:25 +05:30
|
|
|
|
[`AcceptedQty${localId}`]: qty,
|
2026-01-30 19:09:15 +05:30
|
|
|
|
[`RejectedQty${localId}`]: 0,
|
2026-02-06 14:36:25 +05:30
|
|
|
|
[`PurcDisc${localId}`]: 0,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const id = setTimeout(() => {
|
|
|
|
|
|
const total = PurchaseData.reduce(
|
|
|
|
|
|
(acc, d) => acc + Number(d.Amount || 0),
|
|
|
|
|
|
0
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleMRPBlur = (e, record) => {
|
|
|
|
|
|
const value = e.target.value ?? '';
|
|
|
|
|
|
const normalized = value === '' ? '' : String(Number(value));
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
MRP: normalized,
|
|
|
|
|
|
SellPrice: normalized,
|
|
|
|
|
|
}
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
2026-01-30 19:09:15 +05:30
|
|
|
|
);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handlePurrateChange = useCallback((e, record) => {
|
|
|
|
|
|
let value = e?.target?.value ?? '';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// allow decimals only
|
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// 🔥 remove leading zero when user starts typing
|
|
|
|
|
|
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
|
|
|
|
|
|
value = value.replace(/^0+/, '');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) => {
|
|
|
|
|
|
if (item.localId !== record.localId) return item;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const qty = Number(item.AcceptedQty) || 0;
|
|
|
|
|
|
const rateNum = Number(value || 0);
|
|
|
|
|
|
const amount = rateNum * qty;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
let discountAmt = 0;
|
|
|
|
|
|
if (item.PurcDiscType === 'P') {
|
|
|
|
|
|
discountAmt = (amount * Number(item.PurcDisc || 0)) / 100;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
discountAmt = Number(item.PurcDisc || 0);
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const taxPercent = Number(item.TaxPercentage || 0);
|
|
|
|
|
|
const taxAmt =
|
|
|
|
|
|
taxPercent > 0
|
|
|
|
|
|
? ((amount - discountAmt) * taxPercent) / (100 + taxPercent)
|
|
|
|
|
|
: 0;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
InwardPrice: value, // 👈 clean value
|
|
|
|
|
|
Amount: amount,
|
|
|
|
|
|
TaxAmt: +taxAmt.toFixed(2),
|
|
|
|
|
|
};
|
|
|
|
|
|
})
|
2026-01-30 19:09:15 +05:30
|
|
|
|
);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
}, []);
|
|
|
|
|
|
const handlePurrateTyping = (e, record) => {
|
|
|
|
|
|
let value = e?.target?.value ?? '';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (value.length > 1 && value.startsWith('0') && !value.startsWith('0.')) {
|
|
|
|
|
|
value = value.replace(/^0+/, '');
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId ? { ...item, InwardPrice: value } : item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
debouncedCalc(value, record);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const calculateRate = useCallback((value, record) => {
|
|
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) => {
|
|
|
|
|
|
if (item.localId !== record.localId) return item;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const qty = Number(item.AcceptedQty) || 0;
|
|
|
|
|
|
const rateNum = Number(value || 0);
|
|
|
|
|
|
const amount = rateNum * qty;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
let discountAmt = 0;
|
|
|
|
|
|
if (item.PurcDiscType === 'P') {
|
|
|
|
|
|
discountAmt = (amount * Number(item.PurcDisc || 0)) / 100;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
discountAmt = Number(item.PurcDisc || 0);
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const taxPercent = Number(item.TaxPercentage || 0);
|
|
|
|
|
|
const taxAmt =
|
|
|
|
|
|
taxPercent > 0
|
|
|
|
|
|
? ((amount - discountAmt) * taxPercent) / (100 + taxPercent)
|
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
Amount: amount,
|
|
|
|
|
|
TaxAmt: +taxAmt.toFixed(2),
|
|
|
|
|
|
};
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
}, []);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const debouncedCalc = useDebounce(calculateRate, 300);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleSellPriceChange = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// allow smooth typing
|
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId ? { ...item, SellPrice: value } : item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleSellPriceBlur = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
|
|
|
|
|
const normalized = value === '' ? '' : String(Number(value));
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, SellPrice: normalized }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleOnePcsChange = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId ? { ...item, OnePcsPrice: value } : item
|
|
|
|
|
|
)
|
2026-01-30 19:09:15 +05:30
|
|
|
|
);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleOnePcsBlur = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
|
|
|
|
|
const normalized = value === '' ? '' : String(Number(value));
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, OnePcsPrice: normalized }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleNoOfPcsChange = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// only whole numbers
|
|
|
|
|
|
if (!/^\d*$/.test(value)) return;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId ? { ...item, NoOfPcs: value } : item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleNoOfPcsBlur = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
|
|
|
|
|
const normalized = value === '' ? '' : String(parseInt(value, 10));
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, NoOfPcs: normalized }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleWhSalePriceChange = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId ? { ...item, WhSalePrice: value } : item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleWhSalePriceBlur = (e, record) => {
|
|
|
|
|
|
const value = e?.target?.value ?? '';
|
|
|
|
|
|
const normalized = value === '' ? '' : String(Number(value));
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, WhSalePrice: normalized }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleManufDateChange = (dateString, record) => {
|
|
|
|
|
|
const formattedDate =
|
|
|
|
|
|
!dateString || dateString === ''
|
|
|
|
|
|
? undefined
|
|
|
|
|
|
: moment(dateString, ['DD-MM-YYYY']).format('YYYY-MM-DDTHH:mm:ss');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, ManufDate: formattedDate }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleExpDateChange = (dateString, record) => {
|
|
|
|
|
|
const formattedDate =
|
|
|
|
|
|
!dateString || dateString === ''
|
|
|
|
|
|
? undefined
|
|
|
|
|
|
: moment(dateString, ['DD-MM-YYYY']).format('YYYY-MM-DDTHH:mm:ss');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, ExpDate: formattedDate }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleHSNChange = (value, record) => {
|
|
|
|
|
|
// optional: digits only (HSN is numeric)
|
|
|
|
|
|
const cleanValue = value.replace(/\D/g, '');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, PurchaseHSNCode: cleanValue }
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleTaxTyping = (e, record) => {
|
|
|
|
|
|
let value = e?.target?.value ?? '';
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// allow decimal typing only
|
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(value)) return;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// fix ".5" → "0.5"
|
|
|
|
|
|
if (value.startsWith('.')) value = '0' + value;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
setPurchaseData((prev) =>
|
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
|
item.localId === record.localId
|
|
|
|
|
|
? { ...item, PurchaseTax: value } // keep STRING
|
|
|
|
|
|
: item
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
debouncedTaxCalc(value, record);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
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
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
|
[`PurchaseTax${record.localId}`]: normalized,
|
|
|
|
|
|
});
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const purchaseStatusChange = (value) => {
|
|
|
|
|
|
setPurchaseStatus(value);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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 {
|
2026-01-30 19:09:15 +05:30
|
|
|
|
// ===============================
|
|
|
|
|
|
// 1️⃣ TAX VALIDATION
|
|
|
|
|
|
// ===============================
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const invalidTaxItems = PurchaseData?.filter((item) => {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const tax = item?.PurchaseTax;
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (tax === undefined || tax === '' || tax === null) return false;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const num = Number(tax);
|
2026-01-30 19:09:15 +05:30
|
|
|
|
return isNaN(num) || num < 0 || num > 99;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (invalidTaxItems?.length > 0) {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setMessageType('error');
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageData(
|
|
|
|
|
|
'Please enter valid tax percentage (0–99%) for all items'
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
if (
|
|
|
|
|
|
PurchaseData?.some(
|
|
|
|
|
|
(item) =>
|
|
|
|
|
|
item.SellPrice &&
|
|
|
|
|
|
item.MRP &&
|
2026-01-30 19:09:15 +05:30
|
|
|
|
Number(item.SellPrice) > Number(item.MRP)
|
2026-01-27 18:27:29 +05:30
|
|
|
|
)
|
|
|
|
|
|
) {
|
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData('Selling Price cannot be greater than MRP');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (!PurchaseData || PurchaseData?.length === 0) {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData('No Product Selected');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
if (validRows?.length === 0) {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setMessageType('error');
|
2026-01-30 19:09:15 +05:30
|
|
|
|
setMessageData('Please enter Qty and Amount for at least one product');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
// ===============================
|
|
|
|
|
|
// 5️⃣ CONFIRMATION FOR INVALID ROWS
|
|
|
|
|
|
// ===============================
|
|
|
|
|
|
if (invalidRowNumbers.length > 0) {
|
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
|
title: '⚠️ Incomplete Product Rows',
|
|
|
|
|
|
width: 520,
|
|
|
|
|
|
centered: true,
|
|
|
|
|
|
content: (
|
|
|
|
|
|
<div style={{ fontSize: 14 }}>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
Some products are missing <b>Qty or Amount</b>.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
|
Affected row(s): <b>{invalidRowNumbers.join(', ')}</b>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<p style={{ marginTop: 8 }}>
|
|
|
|
|
|
Are you sure you want to continue without these products?
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
),
|
|
|
|
|
|
okText: 'Continue Anyway',
|
|
|
|
|
|
cancelText: 'Go Back',
|
|
|
|
|
|
okButtonProps: { danger: true },
|
|
|
|
|
|
onOk: () =>
|
|
|
|
|
|
proceedSubmit(validRows, values, PaymentType, PaymentAmount),
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
// 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',
|
|
|
|
|
|
];
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
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,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
});
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const isPaidSelected = PurchaseTypeData?.some(
|
|
|
|
|
|
(item) =>
|
|
|
|
|
|
item.ConfigId === SelectedPurchaseType && item.ConfigName === 'Cash'
|
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (
|
|
|
|
|
|
(SupplierOpen !== 'own' || selectedSupplierName) &&
|
|
|
|
|
|
selectedSupplierData &&
|
|
|
|
|
|
isPaidSelected
|
|
|
|
|
|
) {
|
|
|
|
|
|
postData.PaymentAmount = PaymentAmount;
|
|
|
|
|
|
postData.PaymentType = selectedPaymentMode;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
postData.PaymentType = PaymentType;
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
postData.ProdDetails = processedData;
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (formType === 'edit') {
|
|
|
|
|
|
postData.ProdId = editstate?.ProdId;
|
|
|
|
|
|
postData.InwardId = editstate?.InwardId;
|
|
|
|
|
|
postData.InwardDtlId = editstate?.InwardDtlId;
|
|
|
|
|
|
postData.UpdatedBy = UserId;
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
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',
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
|
navigate(`${subDirectory}setting/purchase-entry/`, {
|
|
|
|
|
|
state: {
|
|
|
|
|
|
Notiffy: {
|
|
|
|
|
|
messageType: 'success',
|
|
|
|
|
|
messageData: response?.data?.response,
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-01-30 19:09:15 +05:30
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setMessageType('error');
|
2026-01-30 19:09:15 +05:30
|
|
|
|
setMessageData(response?.data?.response);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const invoiceParts = value?.split('-');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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([]);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setSelectedProductData(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
setSelectedProductName(null);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// setselectedProductVariantData(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const handleModelDataOpen = (selectedRowRecord) => {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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 || '',
|
|
|
|
|
|
}));
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
|
|
|
|
|
const newData = PurchaseData.map((item, index) =>
|
2026-02-03 13:55:24 +05:30
|
|
|
|
index === selectedRowIndex
|
|
|
|
|
|
? { ...item, ProductIdentifierDtls: productIdentifierDtls }
|
|
|
|
|
|
: item
|
2026-01-30 19:09:15 +05:30
|
|
|
|
);
|
|
|
|
|
|
setPurchaseData(newData);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
};
|
2026-02-06 14:36:25 +05:30
|
|
|
|
const handleFieldSetupSubmit = async ({
|
|
|
|
|
|
selectedFields,
|
|
|
|
|
|
tempSelectedColumns,
|
|
|
|
|
|
closeModal,
|
|
|
|
|
|
resetTemp,
|
|
|
|
|
|
}) => {
|
2026-01-30 19:09:15 +05:30
|
|
|
|
const postData = {
|
2026-02-06 14:36:25 +05:30
|
|
|
|
AppId,
|
|
|
|
|
|
CompId,
|
|
|
|
|
|
BranchId,
|
2026-02-03 13:55:24 +05:30
|
|
|
|
Type: 'PE',
|
|
|
|
|
|
FormType: 'Purchase Entry',
|
|
|
|
|
|
TypeId: categoryId,
|
2026-02-06 14:36:25 +05:30
|
|
|
|
ConfigDtl: selectedFields.map((field) => ({
|
2026-02-03 13:55:24 +05:30
|
|
|
|
ConfigId: field,
|
|
|
|
|
|
Access: 'Y',
|
2026-01-30 19:09:15 +05:30
|
|
|
|
})),
|
2026-02-03 13:55:24 +05:30
|
|
|
|
CreatedBy: UserId,
|
|
|
|
|
|
};
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
|
|
|
|
|
const response = await dispatch(postFieldSetup(postData))?.unwrap();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
2026-01-30 19:09:15 +05:30
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
|
|
|
|
setSelectedAdditionalColumn([...tempSelectedColumns]);
|
2026-02-06 14:36:25 +05:30
|
|
|
|
closeModal();
|
|
|
|
|
|
resetTemp();
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageType('success');
|
2026-01-30 19:09:15 +05:30
|
|
|
|
setMessageData(response?.data?.response);
|
|
|
|
|
|
await getFieldSetup();
|
|
|
|
|
|
} else {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
setMessageData('Failed to set up fields');
|
2026-01-30 19:09:15 +05:30
|
|
|
|
}
|
2026-02-03 13:55:24 +05:30
|
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
|
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 (
|
|
|
|
|
|
<div className="pageOverAll" style={{ position: 'relative' }}>
|
|
|
|
|
|
{isLoading && (
|
|
|
|
|
|
<div className="loading-overlay">
|
|
|
|
|
|
<div className="loading-spinner" />
|
|
|
|
|
|
{loadingText && <div className="loading-text">{loadingText}</div>}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<div className="userPage">
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<div className="userPageContent" style={{ paddingBottom: '1rem' }}>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Messages
|
|
|
|
|
|
messageType={messageType}
|
|
|
|
|
|
messageData={messageData}
|
|
|
|
|
|
onComplete={onComplete}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div className="purchase-entry-fh">
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="formName"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
flexWrap: 'wrap',
|
|
|
|
|
|
gap: '10px',
|
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<FormHeader title={'Product Receipt'} />
|
|
|
|
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="header-buttons"
|
|
|
|
|
|
style={{ flexWrap: 'wrap', width: 'unset' }}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="pruchaseCatBTN scan-receipt-btn"
|
|
|
|
|
|
onClick={() => setExtractorModalVisible(true)}
|
|
|
|
|
|
>
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<TbUpload size={18} strokeWidth={3} />{' '}
|
|
|
|
|
|
<p> Scan Receipt (Auto-Fill)</p>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
className="pruchaseCatBTN"
|
|
|
|
|
|
onClick={() =>
|
|
|
|
|
|
navigate(`${subDirectory}setting/purchase-entry`)
|
|
|
|
|
|
}
|
|
|
|
|
|
>
|
|
|
|
|
|
<FaEye size={18} /> <p> View Entry List</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="formDiv">
|
|
|
|
|
|
<Form
|
|
|
|
|
|
ref={formRef}
|
|
|
|
|
|
initialValues={editstate}
|
|
|
|
|
|
className="formDivAnt"
|
|
|
|
|
|
onFinish={onFinish}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
style={{ width: '100%' }}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
>
|
|
|
|
|
|
<div className="purchase-entry-form">
|
|
|
|
|
|
<div className="formDivS">
|
2026-01-30 19:09:15 +05:30
|
|
|
|
<div className="inputFormSTOCKFORM">
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<div className="purchaseDetails">
|
|
|
|
|
|
<div className="supplierInfo">
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{/* <h2 className="supplier-dtls">Supplier Details</h2> */}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<div className="supplierInfo1">
|
|
|
|
|
|
{!orderType && (
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="PurchaseOrderNo"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Purchase Order No.',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<FloatLabel
|
|
|
|
|
|
label={
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<label className="required">
|
2026-01-27 18:27:29 +05:30
|
|
|
|
Purchase Order No.
|
|
|
|
|
|
</label>
|
|
|
|
|
|
}
|
|
|
|
|
|
isOnChange={searchText ? true : false}
|
|
|
|
|
|
>
|
|
|
|
|
|
<AutoComplete
|
|
|
|
|
|
style={{ width: '180px' }}
|
|
|
|
|
|
options={filteredOptions}
|
|
|
|
|
|
className="supplier-invoice-select"
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
allowClear
|
|
|
|
|
|
value={searchText}
|
|
|
|
|
|
onSelect={handleInvoiceSelect}
|
|
|
|
|
|
onSearch={handleInvoiceSearch}
|
|
|
|
|
|
filterOption={(inputValue, option) =>
|
|
|
|
|
|
option.label
|
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
|
.includes(inputValue?.toLowerCase())
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</FloatLabel>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="CustSuppId"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Supplier',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={
|
|
|
|
|
|
SupplierData
|
|
|
|
|
|
? SupplierData.filter(
|
2026-02-03 13:55:24 +05:30
|
|
|
|
(obj, index, self) =>
|
|
|
|
|
|
index ===
|
|
|
|
|
|
self.findIndex(
|
|
|
|
|
|
(t) => t.SuppId === obj.SuppId
|
|
|
|
|
|
) // remove dup SuppId
|
|
|
|
|
|
).map((option) => ({
|
|
|
|
|
|
key: `${option.SuppId}-${option.Type}`, // 👈 unique key
|
|
|
|
|
|
value: option.SuppId,
|
|
|
|
|
|
label:
|
|
|
|
|
|
option.Type === 'Branch'
|
|
|
|
|
|
? `${option.SuppName} (${option.Type}) [${option.SuppId}]`
|
|
|
|
|
|
: `${option.SuppName} (${option.Type})`,
|
|
|
|
|
|
}))
|
2026-01-27 18:27:29 +05:30
|
|
|
|
: []
|
|
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={
|
|
|
|
|
|
<label className="required">Supplier</label>
|
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
onChangeFunction={handleSupplierDropDownChange}
|
|
|
|
|
|
valueData={selectedSupplierData}
|
|
|
|
|
|
disabled={
|
|
|
|
|
|
editstate?.SuppId
|
|
|
|
|
|
? true
|
|
|
|
|
|
: !orderType
|
|
|
|
|
|
? true
|
|
|
|
|
|
: false
|
|
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<Tooltip title="Add Supplier" placement="top">
|
|
|
|
|
|
<PlusCircleOutlined
|
|
|
|
|
|
className="product-add-iconMargin"
|
|
|
|
|
|
onClick={addSupplier}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
{!selectedSupplierName && (
|
|
|
|
|
|
<RadioGrpButton
|
|
|
|
|
|
content={[
|
|
|
|
|
|
{ value: 'own', label: 'Own' },
|
|
|
|
|
|
{ value: 'paid', label: 'With paid' },
|
|
|
|
|
|
]}
|
|
|
|
|
|
fieldState={true}
|
|
|
|
|
|
defaultSelect={SupplierOpen}
|
|
|
|
|
|
// Header={"Stock Available"}
|
|
|
|
|
|
onSelectFuntion={(e) => SupplierOpenfun(e)}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
|
|
|
|
|
|
<div className="pe-inward-date">
|
|
|
|
|
|
<label className="required">Inward Date</label>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name={'InvoiceDate'}
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Inward Date',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DatePicProd
|
|
|
|
|
|
canSelectPast={true}
|
|
|
|
|
|
onChange={handleInwardDateChange}
|
|
|
|
|
|
valueData={inwardDate}
|
|
|
|
|
|
disabled={formType == 'edit' ? true : false}
|
|
|
|
|
|
cancelFuture={true}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="OrderType"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Order Type',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="switch-order-type">
|
|
|
|
|
|
<div className="switch-header required">
|
|
|
|
|
|
Order Type
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Switch
|
|
|
|
|
|
checked={orderType}
|
|
|
|
|
|
onChange={handleOrderTypeChange}
|
|
|
|
|
|
checkedChildren="New Order"
|
|
|
|
|
|
unCheckedChildren="Pending Orders"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form.Item>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</div>
|
|
|
|
|
|
<div className="supplierInfo2">
|
|
|
|
|
|
{(SupplierOpen !== 'own' || selectedSupplierName) &&
|
|
|
|
|
|
selectedSupplierData && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Form.Item name={'InvoiceType'}>
|
|
|
|
|
|
<RadioGrpButton
|
|
|
|
|
|
content={[
|
|
|
|
|
|
{ value: 'I', label: 'Invoice' },
|
|
|
|
|
|
{
|
|
|
|
|
|
value: 'DC',
|
|
|
|
|
|
label: 'Delivery Challan',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
defaultSelect={invoiceType}
|
|
|
|
|
|
onSelectFuntion={handleInvoiceTypeChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppInvoiceNo"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
// pattern:/^[1-9]\d*(\.\d+)?$/,
|
|
|
|
|
|
message:
|
|
|
|
|
|
invoiceType === 'I'
|
|
|
|
|
|
? 'Please Enter Invoice Number'
|
|
|
|
|
|
: 'Please Enter Delivery Challan',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
|
if (value?.length > 30) {
|
|
|
|
|
|
if (invoiceType === 'I') {
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Invoice Number cannot exceeds more than 30 chars'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Delivery Challan cannot exceeds more than 30 chars'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="stock-input">
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
label={
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<label className="required">
|
2026-01-27 18:27:29 +05:30
|
|
|
|
{invoiceType === 'I'
|
|
|
|
|
|
? 'Supplier Invoice Number'
|
|
|
|
|
|
: 'Delivery Challan No.'}
|
|
|
|
|
|
</label>
|
|
|
|
|
|
}
|
|
|
|
|
|
onChange={handleSuppInvoiceNoChange}
|
|
|
|
|
|
isOnChange={
|
|
|
|
|
|
extractorData?.invoiceNo ? true : false
|
|
|
|
|
|
}
|
|
|
|
|
|
value={extractorData?.invoiceNo}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item name="SuppInvoiceDate">
|
|
|
|
|
|
<div className="supplier-invoice-date">
|
|
|
|
|
|
<label className="required">
|
|
|
|
|
|
{invoiceType === 'I'
|
|
|
|
|
|
? 'Supplier Invoice Date'
|
|
|
|
|
|
: 'Delivery Challan Date'}
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<DatePicProd
|
|
|
|
|
|
canSelectPast={true}
|
|
|
|
|
|
onChange={onSuppInvoiceDateChange}
|
|
|
|
|
|
valueData={SuppInvoiceDate}
|
|
|
|
|
|
disabled={
|
|
|
|
|
|
formType == 'edit' ? true : false
|
|
|
|
|
|
}
|
|
|
|
|
|
cancelFuture={true}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{(SupplierOpen !== 'own' || selectedSupplierName) &&
|
|
|
|
|
|
selectedSupplierData && (
|
|
|
|
|
|
<div className="invoiceDetails">
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="PaymentType"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Pruchase Type ',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={PurchaseTypeData?.map((option) => ({
|
|
|
|
|
|
value: option.ConfigId,
|
|
|
|
|
|
label:
|
|
|
|
|
|
option.ConfigName === 'Cash'
|
|
|
|
|
|
? 'Paid'
|
|
|
|
|
|
: option.ConfigName,
|
|
|
|
|
|
}))}
|
|
|
|
|
|
label={
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<label className="required">
|
|
|
|
|
|
Payment Type
|
|
|
|
|
|
</label>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
onChangeFunction={handlePurchaseTypeChange}
|
|
|
|
|
|
valueData={SelectedPurchaseType}
|
|
|
|
|
|
disabled={editstate?.SuppId ? true : false}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
{PurchaseTypeData?.some(
|
|
|
|
|
|
(item) =>
|
|
|
|
|
|
item.ConfigId === SelectedPurchaseType &&
|
|
|
|
|
|
item.ConfigName === 'Cash'
|
|
|
|
|
|
) && (
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="PaymentMode"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please Select Payment Mode',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={paymentOptions?.map((mode) => ({
|
|
|
|
|
|
value: mode.ModeId,
|
|
|
|
|
|
label: mode.ModeName,
|
|
|
|
|
|
}))}
|
|
|
|
|
|
label={
|
|
|
|
|
|
<label className="required">
|
|
|
|
|
|
Payment Mode
|
|
|
|
|
|
</label>
|
|
|
|
|
|
}
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
onChangeFunction={handlePaymentModeChange}
|
|
|
|
|
|
valueData={selectedPaymentMode}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="PaymentAmount"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
message: 'Please enter Payment Amount',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: (_, value) => {
|
|
|
|
|
|
if (
|
|
|
|
|
|
value === undefined ||
|
|
|
|
|
|
value === null ||
|
|
|
|
|
|
value === ''
|
|
|
|
|
|
) {
|
2026-01-27 18:27:29 +05:30
|
|
|
|
return Promise.resolve();
|
2026-02-03 13:55:24 +05:30
|
|
|
|
}
|
|
|
|
|
|
if (Number(value) === 0) {
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Payment Amount cannot be 0'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (
|
|
|
|
|
|
isNaN(value) ||
|
|
|
|
|
|
Number(value) < 0
|
|
|
|
|
|
) {
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Payment Amount cannot be less than 0'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Promise.resolve();
|
2026-01-27 18:27:29 +05:30
|
|
|
|
},
|
2026-02-03 13:55:24 +05:30
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
label={
|
|
|
|
|
|
<label className="required">
|
|
|
|
|
|
Payment Amount
|
|
|
|
|
|
</label>
|
|
|
|
|
|
}
|
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
|
disable={!payAmountDisable}
|
|
|
|
|
|
isOnChange={paymentAmount ? true : false}
|
|
|
|
|
|
min={0}
|
|
|
|
|
|
type="number"
|
|
|
|
|
|
value={paymentAmount}
|
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
|
formRef?.current?.setFieldsValue({
|
|
|
|
|
|
PaymentAmount: e?.target?.value,
|
|
|
|
|
|
});
|
|
|
|
|
|
setPaymentAmount(e?.target?.value);
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Form.Item name="DueDate">
|
|
|
|
|
|
<label className="required">Due Date</label>
|
|
|
|
|
|
<br />
|
|
|
|
|
|
<DatePicProd
|
|
|
|
|
|
canSelectPast={true}
|
|
|
|
|
|
onChange={onPurchaseDateChange}
|
|
|
|
|
|
valueData={PurchaseDate}
|
|
|
|
|
|
disabled={formType == 'edit' ? true : false}
|
|
|
|
|
|
cancelFuture={false}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="stockDiv">
|
|
|
|
|
|
<Form.Item name="ProdId">
|
|
|
|
|
|
<div className="product-scan">
|
|
|
|
|
|
<FloatLabel
|
|
|
|
|
|
label={'Product Name'}
|
|
|
|
|
|
value={selectedProductName}
|
|
|
|
|
|
>
|
|
|
|
|
|
<AutoComplete
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
value={selectedProductName}
|
|
|
|
|
|
filterOption={(input, option) => {
|
2026-02-03 13:55:24 +05:30
|
|
|
|
const [prodId, variantName] =
|
2026-02-06 14:36:25 +05:30
|
|
|
|
option?.value?.split('_');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
const product = productData.find(
|
2026-02-03 13:55:24 +05:30
|
|
|
|
(p) =>
|
|
|
|
|
|
p.ProdId === prodId &&
|
|
|
|
|
|
(p.ProdVariantName || 'Variant1') ===
|
|
|
|
|
|
variantName
|
2026-01-27 18:27:29 +05:30
|
|
|
|
);
|
|
|
|
|
|
const nameMatch = option.label
|
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
|
.includes(productSearchText?.toLowerCase());
|
|
|
|
|
|
const qrMatch =
|
|
|
|
|
|
product?.QRCode?.toLowerCase() ==
|
|
|
|
|
|
productSearchText?.toLowerCase();
|
|
|
|
|
|
return nameMatch || qrMatch;
|
|
|
|
|
|
}}
|
|
|
|
|
|
options={
|
|
|
|
|
|
!scanner
|
|
|
|
|
|
? productData?.map((option) => ({
|
2026-02-03 13:55:24 +05:30
|
|
|
|
value: `${option.ProdId}_${option.ProdVariantName}`,
|
|
|
|
|
|
label: `${option.ProdName} (${option.Size} ${option.UomName})${option?.BrandName ? ` - ${option?.BrandName}` : ''} - ${option.ProdVariantName}`,
|
|
|
|
|
|
}))
|
2026-01-27 18:27:29 +05:30
|
|
|
|
: []
|
|
|
|
|
|
}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
// onSelect={async (value, option) => {
|
|
|
|
|
|
// const [prodId, variantName] = value?.split('_');
|
|
|
|
|
|
// const product = productData.find(
|
|
|
|
|
|
// (p) =>
|
|
|
|
|
|
// p.ProdId === prodId &&
|
|
|
|
|
|
// p.ProdVariantName === variantName
|
|
|
|
|
|
// );
|
|
|
|
|
|
// const newProduct = await ProductDropDownChange(
|
|
|
|
|
|
// product?.ProdVariantName,
|
|
|
|
|
|
// prodId,
|
|
|
|
|
|
// option
|
|
|
|
|
|
// );
|
|
|
|
|
|
// if (newProduct) {
|
|
|
|
|
|
// form?.setFieldsValue({
|
|
|
|
|
|
// [`SellPrice${newProduct?.localId}`]:
|
|
|
|
|
|
// newProduct?.SellPrice,
|
|
|
|
|
|
// [`PurchaseTax${newProduct?.localId}`]:
|
|
|
|
|
|
// newProduct?.PurchaseTax,
|
|
|
|
|
|
// });
|
|
|
|
|
|
// setPurchaseData([
|
|
|
|
|
|
// newProduct,
|
|
|
|
|
|
// ...PurchaseData,
|
|
|
|
|
|
// ]);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }}
|
|
|
|
|
|
|
|
|
|
|
|
onSelect={(value, option) => {
|
|
|
|
|
|
handleProductSelect(value, option);
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}}
|
2026-02-06 14:36:25 +05:30
|
|
|
|
onSearch={handleProductSearch}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
|
|
if (scanner && e.key === 'Enter') {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
style={{ width: '250px' }}
|
|
|
|
|
|
></AutoComplete>
|
|
|
|
|
|
</FloatLabel>
|
|
|
|
|
|
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
|
|
|
|
|
<BsUpcScan
|
|
|
|
|
|
strokeWidth={0.5}
|
|
|
|
|
|
color="#000"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
fontSize: '16px',
|
|
|
|
|
|
color: scanner ? '#52c41a' : '#888',
|
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
|
}}
|
|
|
|
|
|
className="product-scan-Icon"
|
|
|
|
|
|
onClick={handleScanSearch}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<Tooltip
|
|
|
|
|
|
title={'Supplier Product Mapping'}
|
|
|
|
|
|
placement={'top'}
|
|
|
|
|
|
>
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<FaLink
|
|
|
|
|
|
onClick={() => setIsModalOpen(true)}
|
|
|
|
|
|
size={18}
|
|
|
|
|
|
/>
|
2026-01-30 19:09:15 +05:30
|
|
|
|
</Tooltip>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<AddAllProductsButton
|
|
|
|
|
|
productData={productData}
|
|
|
|
|
|
purchaseData={PurchaseData}
|
|
|
|
|
|
setPurchaseData={setPurchaseData}
|
|
|
|
|
|
form={form}
|
|
|
|
|
|
ProductDropDownChange={ProductDropDownChange}
|
|
|
|
|
|
setIsLoading={setIsLoading}
|
|
|
|
|
|
setLoadingText={setLoadingText}
|
|
|
|
|
|
/>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</Form.Item>
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
{isModalOpen && (
|
|
|
|
|
|
<SupplierProductMappingForm
|
|
|
|
|
|
isModalOpen={isModalOpen}
|
|
|
|
|
|
setIsModalOpen={() => {
|
|
|
|
|
|
(setIsModalOpen(false),
|
|
|
|
|
|
handleSupplierDropDownChange(
|
|
|
|
|
|
selectedSupplierData
|
|
|
|
|
|
));
|
|
|
|
|
|
}}
|
|
|
|
|
|
CompId={CompId}
|
|
|
|
|
|
BranchId={BranchId}
|
|
|
|
|
|
AppId={AppId}
|
|
|
|
|
|
setMessage={setMessage}
|
|
|
|
|
|
onMappingAdded={handleModalSubmited}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<div className="productSearchRecipt">
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<SettingsIconWithModal
|
|
|
|
|
|
tableFieldPreferences={tableFieldPreferences}
|
|
|
|
|
|
selectedAdditionalColumn={selectedAdditionalColumn}
|
|
|
|
|
|
onSubmit={handleFieldSetupSubmit}
|
|
|
|
|
|
/>
|
2026-01-30 19:09:15 +05:30
|
|
|
|
<div style={{ marginBottom: '10px' }}>
|
|
|
|
|
|
<Input
|
|
|
|
|
|
placeholder="Search products..."
|
|
|
|
|
|
prefix={<SearchOutlined />}
|
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
|
const value = e.target.value.toLowerCase();
|
|
|
|
|
|
setSearchValue(value);
|
|
|
|
|
|
}}
|
|
|
|
|
|
style={{ width: '300px' }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{/* <div
|
2026-01-27 18:27:29 +05:30
|
|
|
|
className="Product-table stockformTabele"
|
|
|
|
|
|
style={{
|
|
|
|
|
|
maxwidth: '500px',
|
|
|
|
|
|
overflowX: 'auto',
|
|
|
|
|
|
scrollbarWidth: 'thin',
|
2026-02-03 13:55:24 +05:30
|
|
|
|
maxHeight: '50vh',
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}}
|
|
|
|
|
|
>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<Table
|
|
|
|
|
|
rowKey="localId"
|
|
|
|
|
|
className="purchase-receipt-table"
|
|
|
|
|
|
bordered
|
|
|
|
|
|
dataSource={
|
|
|
|
|
|
isSearching ? filteredPurchaseData : PurchaseData
|
|
|
|
|
|
}
|
|
|
|
|
|
columns={columns}
|
|
|
|
|
|
rowClassName="editable-row"
|
|
|
|
|
|
pagination={false}
|
|
|
|
|
|
locale={{
|
|
|
|
|
|
emptyText: isSearching
|
|
|
|
|
|
? 'No matching products found'
|
|
|
|
|
|
: 'No data',
|
|
|
|
|
|
}}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div> */}
|
|
|
|
|
|
|
|
|
|
|
|
<div className="Product-table stockformTabele">
|
|
|
|
|
|
<VirtualizedTable
|
|
|
|
|
|
rowKey="localId"
|
|
|
|
|
|
dataSource={
|
|
|
|
|
|
isSearching ? filteredPurchaseData : PurchaseData
|
|
|
|
|
|
}
|
|
|
|
|
|
columns={columns}
|
|
|
|
|
|
rowHeight={54} // same as your previous row height
|
|
|
|
|
|
height="50vh"
|
|
|
|
|
|
overscan={10}
|
|
|
|
|
|
/>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form>
|
|
|
|
|
|
</div>
|
2026-01-30 19:09:15 +05:30
|
|
|
|
<Form
|
|
|
|
|
|
ref={formRef}
|
|
|
|
|
|
initialValues={editstate}
|
|
|
|
|
|
className="finalSubmitPRBTN"
|
|
|
|
|
|
onFinish={onFinish}
|
|
|
|
|
|
>
|
|
|
|
|
|
{PurchaseData?.length > 0 && (
|
|
|
|
|
|
<div className="purchase-status-data">
|
|
|
|
|
|
<div className="total-purchase-amnt">
|
|
|
|
|
|
<label>Total Amount: </label>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
{PurchaseData.reduce(
|
|
|
|
|
|
(acc, data) => acc + data?.Amount,
|
|
|
|
|
|
0
|
|
|
|
|
|
)?.toFixed(2)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{!orderType && (
|
|
|
|
|
|
<div className="purchase-status">
|
|
|
|
|
|
<RadioGrpButton
|
|
|
|
|
|
content={[
|
|
|
|
|
|
{ value: 'P', label: 'Pending' },
|
|
|
|
|
|
{ value: 'C', label: 'Completed' },
|
|
|
|
|
|
]}
|
|
|
|
|
|
Header={'Purchase Status'}
|
|
|
|
|
|
defaultSelect={purchaseStatus}
|
|
|
|
|
|
onSelectFuntion={purchaseStatusChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<Buttons
|
|
|
|
|
|
buttonText="SUBMIT"
|
|
|
|
|
|
color="901D77"
|
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
</div>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{OpenSupplierModel && (
|
|
|
|
|
|
<DefaultModal
|
|
|
|
|
|
title="Add Supplier"
|
|
|
|
|
|
open={OpenSupplierModel}
|
|
|
|
|
|
footer={true}
|
|
|
|
|
|
buttonText="Submit"
|
|
|
|
|
|
handleSubmit={submitSupplier}
|
|
|
|
|
|
handleCancel={handleSupplier}
|
|
|
|
|
|
>
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Form ref={formSupplierRef} className="formDivAnt">
|
|
|
|
|
|
<div className="subRowFlex">
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppName"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
|
message: 'Please Enter Supplier Name',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
|
if (value?.length > 30) {
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Supplier Name cannot exceeds more than 30 chars'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="required">Supplier Name</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
autocomplete="off"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="Address1"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
|
message: 'Please Enter Address1',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
autoComplete="off"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="required">Address</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="Zip"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
|
message: 'Please Enter Zipcode',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
autoComplete="off"
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="required">Zipcode</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
maxLength="6"
|
|
|
|
|
|
onChange={pinCodeChange}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<p
|
|
|
|
|
|
style={{ color: '#1292ee', justifyContent: 'end' }}
|
|
|
|
|
|
onClick={ViewMoreFields}
|
|
|
|
|
|
>
|
|
|
|
|
|
{' '}
|
|
|
|
|
|
{ViewDtl ? 'Less More' : 'View More'}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
{ViewDtl && (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppGSTIN"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern:
|
|
|
|
|
|
/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Za-z]{1}[Z]{1}[0-9A-Za-z]{1}$/,
|
|
|
|
|
|
message: 'Enter a valid GSTIN',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
style={{ textTransform: 'uppercase' }}
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
label="GST No"
|
|
|
|
|
|
autocapitalize="on"
|
2026-02-03 13:55:24 +05:30
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppMobile"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern: /^\d{10}$/,
|
|
|
|
|
|
message: 'Please Enter a Valid Mobile Number',
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
{ validator: validatePhoneNumber },
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
label={<label>Mobile Number</label>}
|
|
|
|
|
|
maxLength="10"
|
|
|
|
|
|
autocomplete="off"
|
|
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
|
|
|
|
|
inputMode="numeric"
|
|
|
|
|
|
onInput={(e) =>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
(e.target.value = e.target.value?.replace(
|
2026-02-03 13:55:24 +05:30
|
|
|
|
/[^0-9]/g,
|
|
|
|
|
|
''
|
|
|
|
|
|
))
|
2026-01-27 18:27:29 +05:30
|
|
|
|
}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppEmail"
|
|
|
|
|
|
rules={[{ validator: validateEmail }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
label={<label>MailId</label>}
|
|
|
|
|
|
autocomplete="off"
|
2026-02-03 13:55:24 +05:30
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppPOC"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern: /^(?!\s*$).+/,
|
|
|
|
|
|
message: 'Please Enter Point of Contact Name',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value);
|
|
|
|
|
|
if (value?.length > 30) {
|
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
|
'Point of Contact cannot exceeds more than 30 chars'
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="">Point of Contact</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
autocomplete="off"
|
2026-02-03 13:55:24 +05:30
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppPOCMobile"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
pattern: /^\d{10}$/,
|
|
|
|
|
|
message: 'Please Enter a Valid Mobile Number',
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
// required: true,
|
|
|
|
|
|
message: 'Please Enter Mobile Number',
|
|
|
|
|
|
},
|
|
|
|
|
|
{ validator: validatePhoneNumber },
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="">POC Mobile Number</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
autocomplete="off"
|
|
|
|
|
|
maxLength="10"
|
2026-02-03 13:55:24 +05:30
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="SuppPOCEmail"
|
|
|
|
|
|
rules={[{ validator: validateEmail }]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
2026-02-06 14:36:25 +05:30
|
|
|
|
label={<label className="">POC MailId</label>}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
autocomplete="off"
|
2026-02-03 13:55:24 +05:30
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="DeliveryPerformance"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: false,
|
|
|
|
|
|
message: 'Please Select DeliveryPerformance',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={deliveryPerformanceData?.map((option) => ({
|
|
|
|
|
|
value: option.ConfigId,
|
|
|
|
|
|
label: option.ConfigName,
|
|
|
|
|
|
}))}
|
|
|
|
|
|
label={<label>Delivery Performance</label>}
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
id="DeliveryPerformance"
|
|
|
|
|
|
onChangeFunction={(e) =>
|
|
|
|
|
|
handleDeliveryPerformanceChange(e)
|
|
|
|
|
|
}
|
|
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
|
|
|
|
|
valueData={Delivery}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="DiscountLevel"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: false,
|
|
|
|
|
|
message: 'Please Select DiscountLevel',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={DiscountData?.map((option) => ({
|
|
|
|
|
|
value: option.ConfigId,
|
|
|
|
|
|
label: option.ConfigName,
|
|
|
|
|
|
}))}
|
|
|
|
|
|
label={<label>Discount Level</label>}
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
id="DiscountLevel"
|
|
|
|
|
|
onChangeFunction={(e) => handleDiscountLevelChange(e)}
|
|
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
|
|
|
|
|
valueData={DicountValue}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="QualityofSupp"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: false,
|
|
|
|
|
|
message: 'Please Select QualityofSupp',
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<DropDowns
|
|
|
|
|
|
options={QualityData?.map((option) => ({
|
|
|
|
|
|
value: option.ConfigId,
|
|
|
|
|
|
label: option.ConfigName,
|
|
|
|
|
|
}))}
|
|
|
|
|
|
label={<label>Quality of Supplier</label>}
|
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
|
id="QualityofSupp"
|
|
|
|
|
|
onChangeFunction={(e) => handleQualityofSuppChange(e)}
|
|
|
|
|
|
// isOnChange={formType == 'edit' ? true : false}
|
|
|
|
|
|
valueData={QualityValue}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{zipCodeData ? (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="City"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
disabled={true}
|
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
|
label="City"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="Dist"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
disabled={true}
|
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
|
label="District"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
|
name="State"
|
|
|
|
|
|
rules={[
|
|
|
|
|
|
{
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
|
await validateSafeInput(value); // To block HTML tags & SQL keywords
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
<InputField
|
|
|
|
|
|
disabled={true}
|
|
|
|
|
|
isOnChange={true}
|
|
|
|
|
|
label="State"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
</>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
''
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Form>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
</DefaultModal>
|
|
|
|
|
|
)}
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<div>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
{imeiSerialOpen && (
|
|
|
|
|
|
<DefaultModal
|
|
|
|
|
|
title="IMEI /Serial Number / Mac Id"
|
|
|
|
|
|
open={imeiSerialOpen}
|
|
|
|
|
|
footer={true}
|
|
|
|
|
|
width={600}
|
|
|
|
|
|
buttonText="Submit"
|
|
|
|
|
|
handleSubmit={handleModelDataSumbitOrClose}
|
|
|
|
|
|
handleCancel={handleModelDataSumbitOrClose}
|
|
|
|
|
|
>
|
2026-02-03 13:55:24 +05:30
|
|
|
|
<div className="imeiSNTable">
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<Table
|
|
|
|
|
|
components={components}
|
|
|
|
|
|
rowClassName={() => 'editable-row'}
|
|
|
|
|
|
bordered
|
|
|
|
|
|
dataSource={dataSource}
|
|
|
|
|
|
columns={IMEIcolumns}
|
|
|
|
|
|
pagination={{ showSizeChanger: false }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
</DefaultModal>
|
|
|
|
|
|
)}
|
2026-01-30 19:09:15 +05:30
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
|
<InvoiceImageExtractorModal
|
|
|
|
|
|
visible={extractorModalVisible}
|
|
|
|
|
|
onClose={() => setExtractorModalVisible(false)}
|
|
|
|
|
|
onApply={handleExtractorApply}
|
|
|
|
|
|
productData={productData}
|
|
|
|
|
|
supplierData={SupplierData}
|
|
|
|
|
|
uomData={UomData}
|
|
|
|
|
|
setVisible={setExtractorModalVisible}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-02-06 14:36:25 +05:30
|
|
|
|
<style>{`
|
2026-01-27 18:27:29 +05:30
|
|
|
|
@keyframes spin {
|
|
|
|
|
|
0% {
|
|
|
|
|
|
transform: rotate(0deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
100% {
|
|
|
|
|
|
transform: rotate(360deg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
`}</style>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export default StockForm;
|