1758 lines
54 KiB
JavaScript
1758 lines
54 KiB
JavaScript
import React, {
|
|
useState,
|
|
useRef,
|
|
useEffect,
|
|
useContext,
|
|
useCallback,
|
|
} from 'react';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import { read, utils } from 'xlsx';
|
|
import ExcelJS from 'exceljs';
|
|
import { Table, Form, Input, Button, Tooltip, Modal } from 'antd';
|
|
import {
|
|
emptyExcelData,
|
|
excelDataSelector,
|
|
excelFileSelector,
|
|
excelFileErrorSelector,
|
|
fileInputRefSelector,
|
|
uploadExcel,
|
|
} from '../../Features/ExcelUploadPage/ExcelUploadPage.js';
|
|
import '../../Styles/Stock/StockBulkUpload.scss';
|
|
import { AiFillDelete } from 'react-icons/ai';
|
|
import upldimg from '../../Images/upldimg.png';
|
|
import { FiDelete, FiDownload } from 'react-icons/fi';
|
|
import { MdOutlineAppRegistration } from 'react-icons/md';
|
|
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
|
|
import Buttons from '../../Components/Forms/Buttons.jsx';
|
|
import { IoClose } from 'react-icons/io5';
|
|
import { ArrowRightOutlined } from '@ant-design/icons';
|
|
import { ApplicationPreferences } from '../../Features/BrachLogin/BranchLogin.js';
|
|
import FormHeader from '../PageComponents/FormHeader.jsx';
|
|
import { DropDowns } from '../../Components/Forms/DropDown.jsx';
|
|
import { getSession } from '../../Services/Others.js';
|
|
import {
|
|
getFieldSetupData,
|
|
postFieldSetup,
|
|
} from '../../Features/ProductPage/ProductPage.js';
|
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
|
import { getPurchaseSupplierAndWareHouseData } from '../../Features/PurchaseOrder/PurchaseOrder.js';
|
|
import { getSupplaierIdwithTypeBasedProducts } from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
|
|
|
|
const allowedExcelTypes = [
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
|
'application/vnd.ms-excel', // .xls
|
|
];
|
|
|
|
const StockExcel = ({
|
|
handleSubmit,
|
|
SupplierNames,
|
|
ProductId,
|
|
ProductName,
|
|
VarientName,
|
|
InwardDtlIds,
|
|
StockProductId,
|
|
TaxDatas,
|
|
Allproductdatas,
|
|
ProductSize,
|
|
ProductUomName,
|
|
}) => {
|
|
// const formatted_list = ProductName.slice(0,13).map((item, index) => {
|
|
// return item;
|
|
// });
|
|
|
|
// const formatted_list = ProductName.map((item, index) => {
|
|
// return item;
|
|
// });
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const AppId = getSession('AppId');
|
|
const CompId = getSession('CompId');
|
|
const BranchId = getSession('BranchId');
|
|
const UserId = getSession('UserId');
|
|
|
|
const formRef = useRef(null);
|
|
const fileInputRef = useRef(fileInputRefSelector);
|
|
|
|
const excelData = useSelector(excelDataSelector);
|
|
const excelFile = useSelector(excelFileSelector);
|
|
const excelFileError = useSelector(excelFileErrorSelector);
|
|
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
|
|
const purchaseReceiptBulkUploadCatId = ApplicationPreferenceData?.find(
|
|
(p) => p?.PreferredCatName?.toLowerCase() === 'purchase receipt bulk'
|
|
)?.PreferredCatId;
|
|
|
|
const [worksheet1, setWorksheet1] = useState(null);
|
|
const [editdelete, seteditdelete] = useState('');
|
|
|
|
const [Datas, setDatas] = useState();
|
|
console.log(Datas, 'Datas');
|
|
const [showSupplierModal, setShowSupplierModal] = useState(false);
|
|
const [suppliers, setSuppliers] = useState([]);
|
|
const [selectedSupplier, setSelectedSupplier] = useState(null);
|
|
const [selectedSupplierData, setSelectedSupplierData] = useState(null);
|
|
const [supplierProducts, setSupplierProducts] = useState([]);
|
|
const [messageType, setMessageType] = useState(null);
|
|
const [messageData, setMessageData] = useState(null);
|
|
const [fieldSetup, setFieldSetup] = useState(false);
|
|
const [FieldValues, setFieldValues] = useState([]);
|
|
const [tableFieldPreferences, setTableFieldPreferences] = useState([]);
|
|
const [selectedFields, setSelectedFields] = useState([]);
|
|
|
|
const handleTableChange = (pagination, filters, sorter) => {
|
|
setCurrentPage(pagination.current);
|
|
};
|
|
|
|
useEffect(() => {
|
|
getFieldSetup();
|
|
}, [purchaseReceiptBulkUploadCatId]);
|
|
|
|
const onComplete = useCallback(() => {
|
|
setMessageData(null);
|
|
setMessageType(null);
|
|
}, []);
|
|
|
|
const getFieldSetup = async () => {
|
|
try {
|
|
const response = await dispatch(
|
|
getFieldSetupData({
|
|
AppId,
|
|
CompId,
|
|
BranchId,
|
|
categoryId: purchaseReceiptBulkUploadCatId,
|
|
Type: 'EB',
|
|
})
|
|
).unwrap();
|
|
if (response?.data?.statusCode === 1) {
|
|
console.log(response?.data?.data?.[0]?.ConfigDtl, 'Field Setup Data');
|
|
setSelectedFields(
|
|
response?.data?.data?.[0]?.ConfigDtl?.filter(
|
|
(c) => c.ConfigId && c.Access === 'Y'
|
|
)?.map((c) => c.ConfigId) || []
|
|
);
|
|
setTableFieldPreferences(
|
|
response?.data?.data?.[0]?.ConfigDtl?.map((c) => ({
|
|
value: c.ConfigId,
|
|
label: c.ConfigName,
|
|
access: c.Access,
|
|
})) || []
|
|
);
|
|
setFieldValues(response?.data?.data?.[0]?.ConfigDtl);
|
|
} else {
|
|
setMessageType('error');
|
|
setMessageData('Failed to fetch field setup');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching field setup:', error);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (excelData && excelData.length > 0) {
|
|
let ExcelToJsConversion = [];
|
|
let slicedData = excelData.slice(1); // Skip header row
|
|
|
|
slicedData.forEach((item, index) => {
|
|
// Skip empty rows
|
|
if (!item || Object.values(item).every((val) => !val)) return;
|
|
|
|
const rowData = {
|
|
key: index,
|
|
InwardDate: item['0'],
|
|
Supplier: item['1'],
|
|
InvoiceDeliveryChallan: item['3'],
|
|
SupplierInvoiceNumber: item['4'],
|
|
SupplierInvoiceDate: item['5'],
|
|
DeliveryChallanNo: item['6'],
|
|
DeliveryInvoiceDate: item['7'],
|
|
PaymentType: item['8'],
|
|
PaymentMode: item['9'],
|
|
PaymentAmount: item['10'],
|
|
DueDate: item['11'],
|
|
ProductName: item['12'],
|
|
VariantName: item['13'],
|
|
Quantity: item['14'],
|
|
PurchaseRate: item['15'],
|
|
Amount: item['16'],
|
|
ReceivedQty: item['17'],
|
|
AcceptedQty: item['18'],
|
|
MRP: item['19'],
|
|
SalesPrice: item['20'],
|
|
AmountPerPiece: item['21'],
|
|
NumberofPieceInside: item['22'],
|
|
};
|
|
|
|
// Handle conditional 'Own / With Paid' column
|
|
const supplierValue = item['1'];
|
|
if (String(supplierValue).trim() === 'Self') {
|
|
rowData.OwnWithPaid = item['2'];
|
|
// Shift all subsequent columns by 1
|
|
Object.keys(rowData).forEach((key) => {
|
|
if (
|
|
!['key', 'InwardDate', 'Supplier', 'OwnWithPaid'].includes(key)
|
|
) {
|
|
const currentIndex = parseInt(Object.keys(rowData).indexOf(key));
|
|
rowData[key] = item[currentIndex.toString()];
|
|
}
|
|
});
|
|
}
|
|
|
|
// Add optional fields based on column presence
|
|
let currentColIndex = 23;
|
|
|
|
// Check for optional fields in order they appear in handleDownload
|
|
const optionalFields = [
|
|
{ key: 'ManufactureDate', header: 'Manufacture Date' },
|
|
{ key: 'ExpireDate', header: 'Expire Date' },
|
|
{ key: 'BatchNo', header: 'Batch No.' },
|
|
{ key: 'ModelNo', header: 'Model No.' },
|
|
{ key: 'RejectedQty', header: 'Rejected Qty' },
|
|
{ key: 'FreeQty', header: 'Free Qty' },
|
|
{ key: 'WholesalePrice', header: 'Wholesale Price' },
|
|
];
|
|
|
|
// Get headers from first row to determine which optional fields exist
|
|
const headers = excelData[0];
|
|
optionalFields.forEach((field) => {
|
|
if (headers.includes(field.header)) {
|
|
rowData[field.key] = item[currentColIndex.toString()];
|
|
currentColIndex++;
|
|
}
|
|
});
|
|
if (
|
|
rowData?.PurchaseRate &&
|
|
rowData?.Amount &&
|
|
rowData?.MRP &&
|
|
rowData?.SalesPrice &&
|
|
rowData?.ProductName &&
|
|
rowData?.PaymentAmount
|
|
) {
|
|
ExcelToJsConversion.push(rowData);
|
|
}
|
|
});
|
|
|
|
setDatas(ExcelToJsConversion);
|
|
}
|
|
}, [excelData]);
|
|
|
|
useEffect(() => {
|
|
if (Datas) {
|
|
handleSubmit(Datas);
|
|
}
|
|
}, [Datas, handleSubmit]);
|
|
|
|
useEffect(() => {
|
|
if (supplierProducts?.length > 0 && selectedSupplierData) {
|
|
handleDownload();
|
|
}
|
|
}, [supplierProducts, selectedSupplierData]);
|
|
|
|
const handleFileUpload = (e) => {
|
|
const file = e.target.files[0];
|
|
if (file) {
|
|
const isAllowed = allowedExcelTypes.includes(file.type);
|
|
if (!isAllowed) {
|
|
Modal.error({
|
|
title: 'Invalid File Type',
|
|
content: 'Only Excel files (.xls, .xlsx) are allowed.',
|
|
});
|
|
handleCancelData();
|
|
} else {
|
|
uploadAndProcessExcel(file);
|
|
}
|
|
} else {
|
|
dispatch(emptyExcelData());
|
|
}
|
|
};
|
|
const handleClick = () => {
|
|
// Programmatically trigger the file input click event
|
|
fileInputRef.current.click();
|
|
};
|
|
|
|
const uploadAndProcessExcel = (file) => {
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = (e) => {
|
|
const data = new Uint8Array(e.target.result);
|
|
|
|
const workbook = read(data, { type: 'array' });
|
|
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
|
|
|
const jsonData = utils.sheet_to_json(worksheet, {
|
|
header: 1,
|
|
raw: false,
|
|
dateNF: 'DD/MM/YY',
|
|
});
|
|
|
|
const nonEmptyRows = jsonData.filter((row) =>
|
|
row.some((cell) => cell !== '')
|
|
);
|
|
const header = nonEmptyRows[0];
|
|
const rows = nonEmptyRows.slice(1);
|
|
|
|
const dateFields = ['Manufacture Date', 'Expire Date', 'Stock Date'];
|
|
|
|
function convertToDisplayFormat(dateString) {
|
|
const date = new Date(dateString);
|
|
const day = date.getDate().toString().padStart(2, '0');
|
|
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
const year = date.getFullYear().toString();
|
|
return `${day}-${month}-${year}`;
|
|
}
|
|
|
|
const formattedData = rows.map((row) => {
|
|
let rowData = header.reduce((acc, col, columnIndex) => {
|
|
if (dateFields.includes(col)) {
|
|
acc[col] = convertToDisplayFormat(row[columnIndex]);
|
|
} else {
|
|
acc[col] = row[columnIndex];
|
|
}
|
|
|
|
return acc;
|
|
}, {});
|
|
|
|
return rowData;
|
|
});
|
|
|
|
dispatch(uploadExcel({ file, jsonData: nonEmptyRows }));
|
|
setWorksheet1(worksheet1);
|
|
setDatas(formattedData);
|
|
};
|
|
|
|
reader.readAsArrayBuffer(file);
|
|
};
|
|
|
|
// ...existing code...
|
|
const handleDownload = async () => {
|
|
try {
|
|
if (
|
|
!supplierProducts ||
|
|
supplierProducts.length === 0 ||
|
|
!selectedSupplierData
|
|
) {
|
|
setMessageData('No products available to generate Excel.');
|
|
setMessageType('warning');
|
|
return;
|
|
}
|
|
const supplierDisplayName =
|
|
getSupplierDisplayName(selectedSupplierData) || 'Supplier';
|
|
// Fetch excelColumns config (optional fields access)
|
|
let excelColumns = [];
|
|
try {
|
|
const response = await dispatch(
|
|
getFieldSetupData({
|
|
AppId,
|
|
CompId,
|
|
BranchId,
|
|
categoryId: purchaseReceiptBulkUploadCatId,
|
|
Type: 'EB',
|
|
})
|
|
).unwrap();
|
|
if (response?.data?.statusCode === 1) {
|
|
excelColumns = response?.data?.data?.[0]?.ConfigDtl || [];
|
|
}
|
|
} catch (err) {
|
|
console.warn(
|
|
'Failed to fetch excelColumns config, proceeding with defaults',
|
|
err
|
|
);
|
|
excelColumns = [];
|
|
}
|
|
|
|
const isOptionalFieldAllowed = (name) => {
|
|
const found = excelColumns.find(
|
|
(c) => String(c.ConfigName).trim() === String(name).trim()
|
|
);
|
|
return found ? found.Access === 'Y' : false;
|
|
};
|
|
|
|
const addNumberValidation = (cell, allowBlank = true, minValue = 0) => {
|
|
cell.dataValidation = {
|
|
type: 'decimal',
|
|
operator: 'greaterThanOrEqual',
|
|
formulae: [minValue],
|
|
allowBlank: allowBlank,
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Number',
|
|
error: 'Please enter a valid number',
|
|
};
|
|
};
|
|
|
|
const workbook = new ExcelJS.Workbook();
|
|
const worksheet = workbook.addWorksheet('Sheet1');
|
|
const hiddenSheet = workbook.addWorksheet('ProductVariantMap');
|
|
workbook.addWorksheet('ValidationHelper');
|
|
|
|
const requiredBg = 'FF2929';
|
|
const headerFontColor = { argb: 'FF000000' };
|
|
|
|
const columns = [];
|
|
const pushCol = (header, key, required = true) => {
|
|
columns.push({ header, key, required });
|
|
};
|
|
|
|
pushCol('Inward Date', 'InwardDate', true);
|
|
pushCol('Supplier', 'Supplier', true);
|
|
if (String(selectedSupplierData?.SuppName).trim() === 'Self') {
|
|
pushCol('Own / With Paid', 'OwnWithPaid', true);
|
|
}
|
|
pushCol('Invoice / Delivery Challan', 'InvoiceDeliveryChallan', true);
|
|
pushCol('Supplier Invoice Number', 'SupplierInvoiceNumber', true);
|
|
pushCol('Supplier Invoice Date', 'SupplierInvoiceDate', true);
|
|
pushCol('Delivery Challan No.', 'DeliveryChallanNo', true);
|
|
pushCol('Delivery Challan Date', 'DeliveryInvoiceDate', true);
|
|
pushCol('Payment Type', 'PaymentType', true);
|
|
pushCol('Payment Mode', 'PaymentMode', true);
|
|
pushCol('Payment Amount', 'PaymentAmount', true);
|
|
pushCol('Due Date', 'DueDate', true);
|
|
pushCol('Product Name', 'ProdName', true);
|
|
pushCol('Variant Name', 'VariantName', true);
|
|
pushCol('Quantity', 'Quantity', true);
|
|
pushCol('Purchase Rate', 'PurchaseRate', true);
|
|
pushCol('Amount', 'Amount', true);
|
|
pushCol('Received Qty', 'ReceivedQty', true);
|
|
pushCol('Accepted Qty', 'AcceptedQty', true);
|
|
pushCol('MRP', 'MRP', true);
|
|
pushCol('Sales Price', 'SalesPrice', true);
|
|
pushCol('Amount Per Piece', 'AmountPerPiece', true);
|
|
pushCol('Number of Piece Inside', 'NumberofPieceInside', true);
|
|
|
|
if (isOptionalFieldAllowed('Manufacture Date'))
|
|
pushCol('Manufacture Date', 'ManufDate', false);
|
|
if (isOptionalFieldAllowed('Expire Date'))
|
|
pushCol('Expire Date', 'ExpDate', false);
|
|
if (isOptionalFieldAllowed('Batch No.'))
|
|
pushCol('Batch No.', 'BatchNo', false);
|
|
if (isOptionalFieldAllowed('Model No.'))
|
|
pushCol('Model No.', 'ModelNo', false);
|
|
if (isOptionalFieldAllowed('Rejected Qty'))
|
|
pushCol('Rejected Qty', 'RejectedQty', false);
|
|
if (isOptionalFieldAllowed('Free Qty'))
|
|
pushCol('Free Qty', 'FreeQty', false);
|
|
if (isOptionalFieldAllowed('Wholesale Price'))
|
|
pushCol('Wholesale Price', 'WholesalePrice', false);
|
|
|
|
worksheet.columns = columns.map((c) => ({
|
|
header: c.header,
|
|
key: c.key,
|
|
width:
|
|
c.key === 'ProdName' || c.key === 'VariantName'
|
|
? 40
|
|
: c.key === 'Quantity'
|
|
? 10
|
|
: c.key === 'Supplier' ||
|
|
c.key === 'InvoiceDeliveryChallan' ||
|
|
c.key === 'SupplierInvoiceNumber'
|
|
? 30
|
|
: 20,
|
|
}));
|
|
|
|
worksheet.getRow(1).eachCell((cell, colNumber) => {
|
|
const col = columns[colNumber - 1];
|
|
const bgColor = col.required ? requiredBg : 'FF52C41A';
|
|
cell.fill = {
|
|
type: 'pattern',
|
|
pattern: 'solid',
|
|
fgColor: { argb: bgColor },
|
|
};
|
|
cell.font = { bold: true, color: headerFontColor };
|
|
cell.alignment = { horizontal: 'center', vertical: 'middle' };
|
|
cell.border = {
|
|
top: { style: 'thin' },
|
|
left: { style: 'thin' },
|
|
bottom: { style: 'thin' },
|
|
right: { style: 'thin' },
|
|
};
|
|
});
|
|
|
|
hiddenSheet.addRow([
|
|
'ProductName',
|
|
'VariantName',
|
|
'MRP',
|
|
'SellPrice',
|
|
'Number of Piece Inside',
|
|
'Amount Per Piece',
|
|
]);
|
|
let currentRow = 2;
|
|
const productNames = supplierProducts.map((p) => p.ProdName);
|
|
|
|
supplierProducts.forEach((product) => {
|
|
const activeVariants = (product.ProdVariantPriceDetails || []).filter(
|
|
(v) => v.ActiveStatus === 'A'
|
|
);
|
|
const uniqueVariantsMap = new Map();
|
|
activeVariants.forEach((variant) => {
|
|
const variantName = variant.ProdVariantName;
|
|
if (!uniqueVariantsMap.has(variantName)) {
|
|
uniqueVariantsMap.set(variantName, variant);
|
|
}
|
|
});
|
|
const uniqueVariants = Array.from(uniqueVariantsMap.values());
|
|
if (uniqueVariants.length === 0) return;
|
|
const startRow = currentRow;
|
|
uniqueVariants.forEach((variant) => {
|
|
hiddenSheet.addRow([
|
|
product.ProdName,
|
|
variant.ProdVariantName,
|
|
variant.MRP || 0,
|
|
variant.SellPrice || 0,
|
|
variant.NoOfPcs || 0,
|
|
variant.OnePcsPrice || 0,
|
|
]);
|
|
currentRow++;
|
|
});
|
|
const endRow = currentRow - 1;
|
|
let safeName = String(product.ProdName || '')
|
|
.trim()
|
|
.replace(/[^A-Za-z0-9_]/g, '_')
|
|
.replace(/^(\d)/, '_$1');
|
|
if (!safeName)
|
|
safeName = `Product_${Math.random().toString(36).slice(2, 8)}`;
|
|
const rangeRef = `ProductVariantMap!$B$${startRow}:$B$${endRow}`;
|
|
try {
|
|
workbook.definedNames.add(rangeRef, safeName);
|
|
} catch (err) {
|
|
console.warn(`Could not add named range for ${safeName}`, err);
|
|
}
|
|
});
|
|
|
|
const startDataRow = 2;
|
|
const today = new Date();
|
|
|
|
// Pre-populate all products and variants as rows
|
|
supplierProducts.forEach((product) => {
|
|
const activeVariants = (product.ProdVariantPriceDetails || []).filter(
|
|
(v) => v.ActiveStatus === 'A'
|
|
);
|
|
const uniqueVariantsMap = new Map();
|
|
activeVariants.forEach((variant) => {
|
|
const variantName = variant.ProdVariantName;
|
|
if (!uniqueVariantsMap.has(variantName)) {
|
|
uniqueVariantsMap.set(variantName, variant);
|
|
}
|
|
});
|
|
const uniqueVariants = Array.from(uniqueVariantsMap.values());
|
|
|
|
uniqueVariants.forEach((variant) => {
|
|
const rowData = {
|
|
InwardDate: today,
|
|
Supplier: supplierDisplayName,
|
|
ProdName: product.ProdName,
|
|
VariantName: variant.ProdVariantName,
|
|
MRP: variant.MRP || 0,
|
|
SalesPrice: variant.SellPrice || 0,
|
|
NumberofPieceInside: variant.NoOfPcs || 0,
|
|
AmountPerPiece: variant.OnePcsPrice || 0,
|
|
};
|
|
|
|
if (String(selectedSupplierData?.SuppName).trim() === 'Self') {
|
|
rowData.OwnWithPaid = '';
|
|
}
|
|
|
|
worksheet.addRow(rowData);
|
|
});
|
|
});
|
|
|
|
const colKeyToIndex = {};
|
|
worksheet.columns.forEach((c, idx) => {
|
|
colKeyToIndex[c.key] = idx + 1;
|
|
});
|
|
const colIndex = (key) => colKeyToIndex[key];
|
|
const colLetter = (idx) => {
|
|
let s = '';
|
|
let n = idx;
|
|
while (n > 0) {
|
|
const m = (n - 1) % 26;
|
|
s = String.fromCharCode(65 + m) + s;
|
|
n = Math.floor((n - 1) / 26);
|
|
}
|
|
return s;
|
|
};
|
|
|
|
const inwardDateCol = colIndex('InwardDate');
|
|
const numberOfRows = worksheet.rowCount;
|
|
|
|
for (let r = startDataRow; r <= numberOfRows; r++) {
|
|
if (colIndex('ProdName')) {
|
|
const cIdx = colIndex('ProdName');
|
|
const cell = worksheet.getCell(r, cIdx);
|
|
cell.protection = { locked: true };
|
|
}
|
|
if (colIndex('VariantName')) {
|
|
const cIdx = colIndex('VariantName');
|
|
const cell = worksheet.getCell(r, cIdx);
|
|
cell.protection = { locked: true };
|
|
}
|
|
if (colIndex('Quantity')) {
|
|
const cIdx = colIndex('Quantity');
|
|
const letter = colLetter(cIdx);
|
|
const cell = worksheet.getCell(`${letter}${r}`);
|
|
cell.protection = { locked: false };
|
|
addNumberValidation(cell, false, 0.01);
|
|
}
|
|
if (colIndex('PurchaseRate')) {
|
|
const cIdx = colIndex('PurchaseRate');
|
|
const letter = colLetter(cIdx);
|
|
const pCell = worksheet.getCell(`${letter}${r}`);
|
|
pCell.protection = { locked: false };
|
|
addNumberValidation(pCell, false, 0);
|
|
pCell.numFmt = '#,##0.00';
|
|
}
|
|
if (colIndex('RejectedQty')) {
|
|
const cIdx = colIndex('RejectedQty');
|
|
const letter = colLetter(cIdx);
|
|
const rejCell = worksheet.getCell(`${letter}${r}`);
|
|
const qtyLetter = colLetter(colIndex('Quantity'));
|
|
rejCell.dataValidation = {
|
|
type: 'decimal',
|
|
allowBlank: true,
|
|
formulae: [`${letter}${r}<${qtyLetter}${r}`],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Rejected Quantity',
|
|
error: 'Must be a valid number and less than total quantity',
|
|
showInputMessage: true,
|
|
promptTitle: 'Rejected Qty',
|
|
prompt:
|
|
'Enter rejected quantity (must be less than total quantity)',
|
|
};
|
|
rejCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('FreeQty')) {
|
|
const cIdx = colIndex('FreeQty');
|
|
const letter = colLetter(cIdx);
|
|
const cell = worksheet.getCell(`${letter}${r}`);
|
|
cell.protection = { locked: false };
|
|
addNumberValidation(cell, true, 0);
|
|
}
|
|
if (inwardDateCol) {
|
|
const letter = colLetter(inwardDateCol);
|
|
const dCell = worksheet.getCell(`${letter}${r}`);
|
|
dCell.numFmt = 'yyyy-mm-dd';
|
|
dCell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
dCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('Supplier')) {
|
|
const cIdx = colIndex('Supplier');
|
|
const cell = worksheet.getCell(r, cIdx);
|
|
cell.protection = { locked: true };
|
|
}
|
|
|
|
if (colIndex('OwnWithPaid')) {
|
|
const cIdx = colIndex('OwnWithPaid');
|
|
const cell = worksheet.getCell(r, cIdx);
|
|
|
|
cell.dataValidation = {
|
|
type: 'list',
|
|
formulae: ['"Own,With Paid"'],
|
|
allowBlank: true
|
|
};
|
|
|
|
if (!cell.value) {
|
|
cell.value = 'Own';
|
|
}
|
|
|
|
cell.protection = { locked: false };
|
|
}
|
|
|
|
if (colIndex('InvoiceDeliveryChallan')) {
|
|
const cIdx = colIndex('InvoiceDeliveryChallan');
|
|
const cell = worksheet.getCell(r, cIdx);
|
|
|
|
cell.dataValidation = {
|
|
type: 'list',
|
|
formulae: ['"Invoice,Delivery Challan"'],
|
|
allowBlank: true,
|
|
};
|
|
|
|
// ✅ Default value
|
|
if (!cell.value) {
|
|
cell.value = 'Invoice';
|
|
}
|
|
|
|
cell.protection = { locked: false };
|
|
}
|
|
|
|
if (colIndex('SupplierInvoiceNumber')) {
|
|
worksheet.getCell(r, colIndex('SupplierInvoiceNumber')).protection = {
|
|
locked: false,
|
|
};
|
|
}
|
|
if (colIndex('SupplierInvoiceDate')) {
|
|
const cell = worksheet.getCell(r, colIndex('SupplierInvoiceDate'));
|
|
cell.value = today;
|
|
cell.numFmt = 'yyyy-mm-dd';
|
|
cell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
cell.protection = { locked: false };
|
|
}
|
|
if (colIndex('DeliveryChallanNo')) {
|
|
worksheet.getCell(r, colIndex('DeliveryChallanNo')).protection = {
|
|
locked: false,
|
|
};
|
|
}
|
|
if (colIndex('DeliveryInvoiceDate')) {
|
|
const cell = worksheet.getCell(r, colIndex('DeliveryInvoiceDate'));
|
|
cell.value = today;
|
|
cell.numFmt = 'yyyy-mm-dd';
|
|
cell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
cell.protection = { locked: false };
|
|
}
|
|
if (colIndex('MRP')) {
|
|
const mrpCol = colIndex('MRP');
|
|
const mrpCell = worksheet.getCell(r, mrpCol);
|
|
mrpCell.numFmt = '#,##0.00';
|
|
mrpCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('SalesPrice')) {
|
|
const spCol = colIndex('SalesPrice');
|
|
const spCell = worksheet.getCell(r, spCol);
|
|
spCell.numFmt = '#,##0.00';
|
|
spCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('NumberofPieceInside')) {
|
|
const nopCol = colIndex('NumberofPieceInside');
|
|
const nopCell = worksheet.getCell(r, nopCol);
|
|
nopCell.numFmt = '#,##0';
|
|
nopCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('AmountPerPiece')) {
|
|
const appCol = colIndex('AmountPerPiece');
|
|
const appCell = worksheet.getCell(r, appCol);
|
|
appCell.numFmt = '#,##0.00';
|
|
appCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('PaymentType')) {
|
|
const cIdx = colIndex('PaymentType');
|
|
const letter = colLetter(cIdx);
|
|
const pCell = worksheet.getCell(`${letter}${r}`);
|
|
pCell.dataValidation = {
|
|
type: 'list',
|
|
allowBlank: false,
|
|
formulae: ['"Credit,Paid"'],
|
|
};
|
|
pCell.protection = { locked: false };
|
|
}
|
|
|
|
// Payment Mode - Fixed to show list based on Payment Type
|
|
if (colIndex('PaymentMode')) {
|
|
const cIdx = colIndex('PaymentMode');
|
|
const letter = colLetter(cIdx);
|
|
const pmCell = worksheet.getCell(`${letter}${r}`);
|
|
const paymentTypeLetter = colLetter(colIndex('PaymentType'));
|
|
|
|
// Create named range for payment mode options in ValidationHelper sheet
|
|
const validationHelper = workbook.getWorksheet('ValidationHelper');
|
|
if (r === startDataRow) {
|
|
// Add payment mode options to ValidationHelper sheet (only once)
|
|
validationHelper.getCell('A1').value = 'Cash';
|
|
validationHelper.getCell('A2').value = 'Credit';
|
|
validationHelper.getCell('A3').value = 'UPI';
|
|
}
|
|
|
|
// Use IF formula to show list based on Payment Type
|
|
pmCell.dataValidation = {
|
|
type: 'list',
|
|
allowBlank: true,
|
|
formulae: [
|
|
`IF(${paymentTypeLetter}${r}="Paid",ValidationHelper!$A$1:$A$3,"")`,
|
|
],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Payment Mode',
|
|
error: 'Select Cash, Credit, or UPI when Payment Type is Paid',
|
|
showInputMessage: true,
|
|
promptTitle: 'Payment Mode',
|
|
prompt:
|
|
'If Payment Type is Credit, leave empty. If Paid, select: Cash, Credit, or UPI',
|
|
};
|
|
pmCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('DueDate')) {
|
|
const cIdx = colIndex('DueDate');
|
|
const letter = colLetter(cIdx);
|
|
const dueCell = worksheet.getCell(`${letter}${r}`);
|
|
dueCell.numFmt = 'yyyy-mm-dd';
|
|
dueCell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
dueCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('ManufDate')) {
|
|
const cIdx = colIndex('ManufDate');
|
|
const letter = colLetter(cIdx);
|
|
const manufCell = worksheet.getCell(`${letter}${r}`);
|
|
manufCell.numFmt = 'yyyy-mm-dd';
|
|
manufCell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
manufCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('ExpDate')) {
|
|
const cIdx = colIndex('ExpDate');
|
|
const letter = colLetter(cIdx);
|
|
const expCell = worksheet.getCell(`${letter}${r}`);
|
|
expCell.numFmt = 'yyyy-mm-dd';
|
|
expCell.dataValidation = {
|
|
type: 'date',
|
|
operator: 'greaterThan',
|
|
formulae: [new Date(1900, 0, 1)],
|
|
showErrorMessage: true,
|
|
errorTitle: 'Invalid Date',
|
|
error: 'Please enter a valid date',
|
|
};
|
|
expCell.protection = { locked: false };
|
|
}
|
|
if (colIndex('ReceivedQty') && colIndex('Quantity')) {
|
|
const rIdx = colIndex('ReceivedQty');
|
|
const qIdx = colIndex('Quantity');
|
|
const rLetter = colLetter(rIdx);
|
|
const qLetter = colLetter(qIdx);
|
|
const recCell = worksheet.getCell(`${rLetter}${r}`);
|
|
recCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",${qLetter}${r})`,
|
|
};
|
|
addNumberValidation(recCell, true, 0);
|
|
}
|
|
if (colIndex('AcceptedQty') && colIndex('Quantity')) {
|
|
const aIdx = colIndex('AcceptedQty');
|
|
const qIdx = colIndex('Quantity');
|
|
const rjIdx = colIndex('RejectedQty');
|
|
const aLetter = colLetter(aIdx);
|
|
const qLetter = colLetter(qIdx);
|
|
const rejLetter = rjIdx ? colLetter(rjIdx) : null;
|
|
const formulaCell = worksheet.getCell(`${aLetter}${r}`);
|
|
if (rejLetter) {
|
|
formulaCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",MAX(0,${qLetter}${r}-IF(${rejLetter}${r}="",0,${rejLetter}${r})))`,
|
|
};
|
|
} else {
|
|
formulaCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",${qLetter}${r})`,
|
|
};
|
|
}
|
|
addNumberValidation(formulaCell, true, 0);
|
|
formulaCell.protection = { locked: true };
|
|
}
|
|
if (
|
|
colIndex('PaymentAmount') &&
|
|
colIndex('Quantity') &&
|
|
colIndex('PurchaseRate')
|
|
) {
|
|
const payIdx = colIndex('PaymentAmount');
|
|
const qIdx = colIndex('Quantity');
|
|
const pIdx = colIndex('PurchaseRate');
|
|
const rejIdx = colIndex('RejectedQty');
|
|
const payLetter = colLetter(payIdx);
|
|
const qLetter = colLetter(qIdx);
|
|
const pLetter = colLetter(pIdx);
|
|
const rejLetter = rejIdx ? colLetter(rejIdx) : null;
|
|
const formulaCell = worksheet.getCell(`${payLetter}${r}`);
|
|
if (rejLetter) {
|
|
formulaCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",IF(${rejLetter}${r}="",(${qLetter}${r})*${pLetter}${r},(${qLetter}${r}-${rejLetter}${r})*${pLetter}${r}))`,
|
|
};
|
|
} else {
|
|
formulaCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",(${qLetter}${r})*${pLetter}${r})`,
|
|
};
|
|
}
|
|
formulaCell.numFmt = '#,##0.00';
|
|
addNumberValidation(formulaCell, true, 0);
|
|
}
|
|
if (
|
|
colIndex('Amount') &&
|
|
colIndex('Quantity') &&
|
|
colIndex('PurchaseRate')
|
|
) {
|
|
const amtIdx = colIndex('Amount');
|
|
const qIdx = colIndex('Quantity');
|
|
const pIdx = colIndex('PurchaseRate');
|
|
const rejIdx = colIndex('RejectedQty');
|
|
const amtLetter = colLetter(amtIdx);
|
|
const qLetter = colLetter(qIdx);
|
|
const pLetter = colLetter(pIdx);
|
|
const rejLetter = rejIdx ? colLetter(rejIdx) : null;
|
|
const amtCell = worksheet.getCell(`${amtLetter}${r}`);
|
|
if (rejLetter) {
|
|
amtCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",IF(${rejLetter}${r}="",(${qLetter}${r})*${pLetter}${r},(${qLetter}${r}-${rejLetter}${r})*${pLetter}${r}))`,
|
|
};
|
|
} else {
|
|
amtCell.value = {
|
|
formula: `IF(${qLetter}${r}="","",(${qLetter}${r})*${pLetter}${r})`,
|
|
};
|
|
}
|
|
amtCell.numFmt = '#,##0.00';
|
|
addNumberValidation(amtCell, true, 0);
|
|
}
|
|
if (colIndex('WholesalePrice')) {
|
|
const cIdx = colIndex('WholesalePrice');
|
|
const letter = colLetter(cIdx);
|
|
const cell = worksheet.getCell(`${letter}${r}`);
|
|
cell.protection = { locked: false };
|
|
cell.numFmt = '#,##0.00';
|
|
addNumberValidation(cell, true, 0);
|
|
}
|
|
}
|
|
|
|
await worksheet.protect('', {
|
|
selectLockedCells: false,
|
|
selectUnlockedCells: true,
|
|
formatCells: false,
|
|
formatColumns: false,
|
|
formatRows: false,
|
|
insertColumns: false,
|
|
insertRows: false,
|
|
insertHyperlinks: false,
|
|
deleteColumns: false,
|
|
deleteRows: false,
|
|
});
|
|
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
const blob = new Blob([buffer], {
|
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
});
|
|
const filename = `PurchaseEntry_${supplierDisplayName}_${Date.now()}.xlsx`;
|
|
const link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = filename;
|
|
link.click();
|
|
|
|
setSupplierProducts([]);
|
|
setSelectedSupplierData(null);
|
|
handleModalCancel();
|
|
} catch (err) {
|
|
console.error('Failed to generate Purchase Entry Excel', err);
|
|
setMessageData('Failed to generate Excel. Check console for details.');
|
|
setMessageType('error');
|
|
}
|
|
};
|
|
|
|
const getSupplierDisplayName = useCallback((supplierData) => {
|
|
if (!supplierData) return '';
|
|
if (supplierData.Type === 'Supplier') {
|
|
return supplierData.SuppName || supplierData.label;
|
|
} else {
|
|
// For Branch or WareHouse
|
|
return `${supplierData.SuppName}-${supplierData.SuppAppId}-${supplierData.SuppCompId}-${supplierData.SuppBranchId}-${supplierData?.Type === 'Branch' ? 'B' : 'W'}`;
|
|
}
|
|
}, []);
|
|
|
|
const handleFileSubmit = (e) => {
|
|
e.preventDefault();
|
|
if (excelFile === null) {
|
|
excelFileError('Please select an Excel file.');
|
|
} else {
|
|
handleSubmit(Datas);
|
|
}
|
|
};
|
|
|
|
const handleCancelData = () => {
|
|
dispatch(emptyExcelData());
|
|
if (fileInputRef.current) {
|
|
fileInputRef.current.value = '';
|
|
}
|
|
};
|
|
|
|
const smallIconColumnTitle = 'SmallIcon';
|
|
|
|
const columns = [
|
|
{
|
|
title: 'Inward Date',
|
|
dataIndex: 'InwardDate',
|
|
key: 'InwardDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Supplier',
|
|
dataIndex: 'Supplier',
|
|
key: 'Supplier',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Own / With Paid',
|
|
dataIndex: 'OwnWithPaid',
|
|
key: 'OwnWithPaid',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Invoice / Delivery Challan',
|
|
dataIndex: 'InvoiceDeliveryChallan',
|
|
key: 'InvoiceDeliveryChallan',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Supplier Invoice Number',
|
|
dataIndex: 'SupplierInvoiceNumber',
|
|
key: 'SupplierInvoiceNumber',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Supplier Invoice Date',
|
|
dataIndex: 'SupplierInvoiceDate',
|
|
key: 'SupplierInvoiceDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Delivery Challan No.',
|
|
dataIndex: 'DeliveryChallanNo',
|
|
key: 'DeliveryChallanNo',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Delivery Challan Date',
|
|
dataIndex: 'DeliveryInvoiceDate',
|
|
key: 'DeliveryInvoiceDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Payment Type',
|
|
dataIndex: 'PaymentType',
|
|
key: 'PaymentType',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Payment Mode',
|
|
dataIndex: 'PaymentMode',
|
|
key: 'PaymentMode',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Payment Amount',
|
|
dataIndex: 'PaymentAmount',
|
|
key: 'PaymentAmount',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Due Date',
|
|
dataIndex: 'DueDate',
|
|
key: 'DueDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Product Name',
|
|
dataIndex: 'ProductName',
|
|
key: 'ProductName',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Variant Name',
|
|
dataIndex: 'VariantName',
|
|
key: 'VariantName',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Quantity',
|
|
dataIndex: 'Quantity',
|
|
key: 'Quantity',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Purchase Rate',
|
|
dataIndex: 'PurchaseRate',
|
|
key: 'PurchaseRate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Amount',
|
|
dataIndex: 'Amount',
|
|
key: 'Amount',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Received Qty',
|
|
dataIndex: 'ReceivedQty',
|
|
key: 'ReceivedQty',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Accepted Qty',
|
|
dataIndex: 'AcceptedQty',
|
|
key: 'AcceptedQty',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'MRP',
|
|
dataIndex: 'MRP',
|
|
key: 'MRP',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Sales Price',
|
|
dataIndex: 'SalesPrice',
|
|
key: 'SalesPrice',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Amount Per Piece',
|
|
dataIndex: 'AmountPerPiece',
|
|
key: 'AmountPerPiece',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Number of Piece Inside',
|
|
dataIndex: 'NumberofPieceInside',
|
|
key: 'NumberofPieceInside',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Manufacture Date',
|
|
dataIndex: 'ManufactureDate',
|
|
key: 'ManufactureDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Expire Date',
|
|
dataIndex: 'ExpireDate',
|
|
key: 'ExpireDate',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Batch No.',
|
|
dataIndex: 'BatchNo',
|
|
key: 'BatchNo',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Model No.',
|
|
dataIndex: 'ModelNo',
|
|
key: 'ModelNo',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Rejected Qty',
|
|
dataIndex: 'RejectedQty',
|
|
key: 'RejectedQty',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Free Qty',
|
|
dataIndex: 'FreeQty',
|
|
key: 'FreeQty',
|
|
editable: true,
|
|
},
|
|
{
|
|
title: 'Wholesale Price',
|
|
dataIndex: 'WholesalePrice',
|
|
key: 'WholesalePrice',
|
|
editable: true,
|
|
},
|
|
];
|
|
|
|
const column = columns?.map((col) => {
|
|
if (!col.editable) {
|
|
return col;
|
|
}
|
|
|
|
let onClickHandler = null;
|
|
|
|
if (editdelete === 'Delete') {
|
|
onClickHandler = (record) => removeFromTable(record);
|
|
}
|
|
|
|
return {
|
|
...col,
|
|
onCell: (record) => ({
|
|
record,
|
|
editable: col.editable,
|
|
dataIndex: col.dataIndex,
|
|
title: col.title,
|
|
handleSave,
|
|
onClick: () => onClickHandler(record),
|
|
}),
|
|
};
|
|
});
|
|
|
|
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) { }
|
|
};
|
|
|
|
let childNode = children;
|
|
|
|
if (editable) {
|
|
childNode = editing ? (
|
|
<Form.Item
|
|
style={{
|
|
margin: 0,
|
|
}}
|
|
name={dataIndex}
|
|
>
|
|
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
|
|
</Form.Item>
|
|
) : (
|
|
<div
|
|
className="editable-cell-value-wrap"
|
|
style={{
|
|
paddingRight: 24,
|
|
}}
|
|
onClick={toggleEdit}
|
|
>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return <td {...restProps}>{childNode}</td>;
|
|
};
|
|
|
|
const components = {
|
|
body: {
|
|
row: EditableRow,
|
|
cell: EditableCell,
|
|
},
|
|
};
|
|
|
|
const handleSave = (row) => {
|
|
const newDatas = [...Datas];
|
|
|
|
const item = newDatas.filter((item) => item.key === row.key);
|
|
|
|
const UpdatedData = {
|
|
Supplier: row?.Supplier,
|
|
SuppInvoiceNumber: row?.SuppInvoiceNumber,
|
|
SuppInvoiceDate: row?.SuppInvoiceDate,
|
|
InvoiceDate: row?.InvoiceDate,
|
|
InvoiceAmount: row?.InvoiceAmount,
|
|
PurchaseType: row?.PurchaseType,
|
|
DueDate: row?.DueDate,
|
|
ProductName: row?.ProductName,
|
|
Quantity: row?.Quantity,
|
|
PurchaseRate: row?.PurchaseRate,
|
|
PurchaseDiscount: row?.PurchaseDiscount,
|
|
Amount: row?.Amount,
|
|
ExpireDate: row?.ExpireDate,
|
|
ManufactureDate: row?.ManufactureDate,
|
|
MRP: row?.MRP,
|
|
RetailPrice: row?.RetailPrice,
|
|
AmountperPiece: row?.AmountperPiece,
|
|
NumberofPieceInside: row?.NumberofPieceInside,
|
|
WholesalePrice: row?.WholesalePrice,
|
|
Offer: row?.Offer,
|
|
SplPrice: row?.SplPrice,
|
|
ReceivedQuantity: row?.ReceivedQuantity,
|
|
RejectedQuantity: row?.RejectedQuantity,
|
|
AcceptedQuantity: row?.AcceptedQuantity,
|
|
FreeQuantity: row?.FreeQuantity,
|
|
key: row?.key,
|
|
};
|
|
newDatas.splice(item?.[0]?.key, 1, {
|
|
...item?.[0],
|
|
...UpdatedData,
|
|
});
|
|
setDatas(newDatas);
|
|
};
|
|
|
|
const handlechange22 = (index) => {
|
|
if (editdelete === 'Delete') {
|
|
seteditdelete('');
|
|
} else {
|
|
seteditdelete('Delete');
|
|
}
|
|
};
|
|
|
|
const removeFromTable = (record) => {
|
|
const indexToRemove = Datas.findIndex((item) => item.key === record.key);
|
|
|
|
if (indexToRemove !== -1) {
|
|
const updatedDataSource = [...Datas];
|
|
updatedDataSource.splice(indexToRemove, 1);
|
|
setDatas(updatedDataSource);
|
|
}
|
|
};
|
|
|
|
const handleFieldSetup = () => {
|
|
setFieldSetup(true);
|
|
};
|
|
|
|
const handleFieldSetupSubmit = async () => {
|
|
const postData = {
|
|
AppId: AppId,
|
|
CompId: CompId,
|
|
BranchId: BranchId,
|
|
Type: 'EB',
|
|
FormType: 'PurchaseEntry',
|
|
TypeId: purchaseReceiptBulkUploadCatId,
|
|
ConfigDtl: selectedFields?.map((field) => ({
|
|
ConfigId: field,
|
|
Access: 'Y',
|
|
})),
|
|
CreatedBy: UserId,
|
|
};
|
|
|
|
const response = await dispatch(postFieldSetup(postData))?.unwrap();
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
setMessageType('success');
|
|
setMessageData(response?.data?.response);
|
|
setFieldSetup(false);
|
|
await getFieldSetup();
|
|
} else {
|
|
setMessageType('error');
|
|
setMessageData('Failed to set up fields');
|
|
}
|
|
};
|
|
|
|
const handleFieldSelect = (value) => {
|
|
setSelectedFields((prev) => {
|
|
if (prev.includes(value)) {
|
|
return prev;
|
|
}
|
|
return [value, ...prev];
|
|
});
|
|
};
|
|
|
|
const handleFieldRemove = (id) => {
|
|
setSelectedFields((prev) => prev.filter((field) => field !== id));
|
|
};
|
|
|
|
const handleModalCancel = useCallback(() => {
|
|
setShowSupplierModal(false);
|
|
setSelectedSupplier(null);
|
|
setSelectedSupplierData(null);
|
|
}, []);
|
|
|
|
const handleSelectSupplier = useCallback(async () => {
|
|
setShowSupplierModal(true);
|
|
try {
|
|
const response = await dispatch(
|
|
getPurchaseSupplierAndWareHouseData({
|
|
CompId,
|
|
AppId,
|
|
BranchId,
|
|
})
|
|
).unwrap();
|
|
|
|
if (response?.statusCode === 1 && response?.data) {
|
|
const formattedSuppliers = response.data.map((supp) => ({
|
|
value:
|
|
supp?.Type?.toLowerCase() !== 'supplier'
|
|
? `${supp?.SuppAppId}-${supp?.SuppCompId}-${supp?.SuppBranchId}`
|
|
: supp?.SuppId,
|
|
label: supp?.SuppName || supp?.SuppMobile,
|
|
Type: supp?.Type,
|
|
SuppName: supp?.SuppName,
|
|
SuppAppId: supp?.SuppAppId,
|
|
SuppCompId: supp?.SuppCompId,
|
|
SuppBranchId: supp?.SuppBranchId,
|
|
SuppId: supp?.SuppId,
|
|
}));
|
|
setSuppliers(formattedSuppliers);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching suppliers:', error);
|
|
setMessageData('Failed to fetch suppliers.');
|
|
setMessageType('error');
|
|
}
|
|
}, [CompId, AppId, BranchId, dispatch]);
|
|
|
|
const getSupplierMappedProducts = async (supplierId) => {
|
|
try {
|
|
const supplierData = suppliers?.find((supp) => supp.value === supplierId);
|
|
if (!supplierData) return;
|
|
|
|
const type = supplierData.Type;
|
|
const LocationType =
|
|
type === 'Supplier'
|
|
? 'S'
|
|
: type === 'Branch'
|
|
? 'B'
|
|
: type === 'WareHouse'
|
|
? 'W'
|
|
: '';
|
|
|
|
const response = await dispatch(
|
|
getSupplaierIdwithTypeBasedProducts({
|
|
CompId: LocationType === 'S' ? CompId : supplierData?.SuppCompId,
|
|
AppId: LocationType === 'S' ? AppId : supplierData?.SuppAppId,
|
|
BranchId:
|
|
LocationType === 'S' ? BranchId : supplierData?.SuppBranchId,
|
|
SuppId:
|
|
LocationType === 'S' ? supplierId : supplierData?.SuppBranchId,
|
|
LocationType,
|
|
})
|
|
)?.unwrap();
|
|
|
|
if (response?.data?.statusCode === 1) {
|
|
if (response?.data?.data?.length > 0) {
|
|
setSupplierProducts(response?.data?.data);
|
|
} else {
|
|
setSupplierProducts([]);
|
|
setMessageData('No products are mapped to this supplier.');
|
|
setMessageType('warning');
|
|
}
|
|
} else {
|
|
setSupplierProducts([]);
|
|
setMessageData('Failed to fetch supplier products.');
|
|
setMessageType('error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching supplier products:', error);
|
|
setMessageData('An error occurred while fetching products.');
|
|
setMessageType('error');
|
|
}
|
|
};
|
|
|
|
const handleSupplierBasedProducts = useCallback(async () => {
|
|
if (!selectedSupplier) {
|
|
setMessageData('Please select a supplier.');
|
|
setMessageType('warning');
|
|
return;
|
|
}
|
|
|
|
await getSupplierMappedProducts(selectedSupplier);
|
|
}, [selectedSupplier, getSupplierMappedProducts]);
|
|
|
|
const handleSupplierChange = useCallback(
|
|
(value) => {
|
|
const selected = suppliers.find((supp) => supp.value === value);
|
|
if (selected) {
|
|
formRef?.current?.setFieldsValue({ SuppId: value });
|
|
setSelectedSupplier(value);
|
|
setSelectedSupplierData(selected);
|
|
}
|
|
},
|
|
[suppliers]
|
|
);
|
|
|
|
return (
|
|
<div className="container">
|
|
<Messages
|
|
messageType={messageType}
|
|
messageData={messageData}
|
|
onComplete={onComplete}
|
|
/>
|
|
<div className="form">
|
|
<form
|
|
className="form-group"
|
|
autoComplete="off"
|
|
onSubmit={handleFileSubmit}
|
|
>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
<div className="upload-excel-header">
|
|
<h3>UPLOAD YOUR EXCEL</h3>
|
|
<Tooltip title="Field Setup">
|
|
<div
|
|
className="btn btn--info"
|
|
style={{
|
|
background: '#00694aff',
|
|
color: '#fff',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
padding: '5px 12px',
|
|
borderRadius: '4px',
|
|
cursor: 'pointer',
|
|
}}
|
|
onClick={handleFieldSetup}
|
|
>
|
|
<MdOutlineAppRegistration size={19} />
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
|
|
{excelData?.length > 0 && excelData && (
|
|
<div>
|
|
<Tooltip title="Delete">
|
|
<AiFillDelete
|
|
onClick={handlechange22}
|
|
style={{
|
|
fontSize: '23px',
|
|
color: editdelete ? '#52c41a' : '#1292ee',
|
|
}}
|
|
/>
|
|
</Tooltip>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<br />
|
|
{(!excelData || excelData?.length === 0) && (
|
|
<>
|
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
<div style={{ position: 'relative', display: 'inline-block' }}>
|
|
{/* <Imageupload size="2x" /> */}
|
|
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
}}
|
|
>
|
|
<img
|
|
src={upldimg}
|
|
width={'80px'}
|
|
style={{ cursor: 'pointer' }}
|
|
onClick={handleClick}
|
|
/>
|
|
|
|
<input
|
|
type="file"
|
|
className="form-control"
|
|
onChange={handleFileUpload}
|
|
ref={fileInputRef}
|
|
style={{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
height: '100%',
|
|
opacity: 0,
|
|
cursor: 'pointer',
|
|
}}
|
|
/>
|
|
<a style={{ color: '#000' }}> Upload File </a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
{excelFileError && (
|
|
<div className="text-danger" style={{ marginTop: '5px' }}>
|
|
{excelFileError}
|
|
</div>
|
|
)}
|
|
</form>
|
|
</div>
|
|
|
|
<div
|
|
className="viewerExcelupload"
|
|
style={{ maxHeight: '500px', overflow: 'scroll' }}
|
|
>
|
|
{excelData && excelData.length > 0 ? (
|
|
<Table
|
|
columns={column}
|
|
components={components}
|
|
bordered
|
|
dataSource={Datas}
|
|
onChange={handleTableChange}
|
|
></Table>
|
|
) : (
|
|
<p></p>
|
|
)}
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
width: '100%',
|
|
gap: '2rem',
|
|
margin: '1rem 0rem',
|
|
}}
|
|
>
|
|
<Tooltip title="Format Sheet" placement="bottom">
|
|
<div
|
|
className="download-link"
|
|
onClick={handleSelectSupplier}
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '.5rem',
|
|
padding: '0.3rem 0.4rem',
|
|
borderRadius: '6px',
|
|
backgroundColor: 'ghostwhite',
|
|
}}
|
|
>
|
|
<FiDownload style={{ fontSize: '20px' }} />
|
|
<a style={{ color: '#000' }}> Download</a>
|
|
</div>
|
|
</Tooltip>
|
|
{excelData && excelData?.length > 0 && (
|
|
<div
|
|
className="cancel-link"
|
|
onClick={handleCancelData}
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '.5rem',
|
|
padding: '0.3rem 0.4rem',
|
|
borderRadius: '6px',
|
|
backgroundColor: 'ghostwhite',
|
|
}}
|
|
>
|
|
<FiDelete style={{ fontSize: '20px', color: '#1292EE' }} />
|
|
<a style={{ color: '#000' }}> Remove File</a>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<DefaultModal
|
|
open={fieldSetup}
|
|
handleCancel={() => setFieldSetup(false)}
|
|
footer={false}
|
|
children={
|
|
<div className="field-setup-container">
|
|
<div className="field-setup-header">
|
|
<FormHeader
|
|
title={'Select the fields you want to include in the table'}
|
|
/>
|
|
</div>
|
|
<div className="field-setup-content">
|
|
<Form onFinish={handleFieldSetupSubmit} ref={formRef}>
|
|
<Form.Item name="fields">
|
|
<DropDowns
|
|
label="Select fields"
|
|
// valueData={selectedFields}
|
|
onChangeFunction={handleFieldSelect}
|
|
options={tableFieldPreferences?.filter(
|
|
(p) => !selectedFields?.some((s) => s === p.value)
|
|
)}
|
|
/>
|
|
</Form.Item>
|
|
<div className="field-setup-selected-fields">
|
|
{selectedFields
|
|
?.map((id) =>
|
|
tableFieldPreferences?.find((p) => p.value === id)
|
|
)
|
|
.filter(Boolean)
|
|
.map((field) => (
|
|
<div className="selected-field" key={field.value}>
|
|
<div>{field.label}</div>
|
|
<div
|
|
className="close-icon"
|
|
onClick={() => handleFieldRemove(field.value)}
|
|
>
|
|
<IoClose size={15} />
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
|
<Buttons
|
|
buttonText="SUBMIT"
|
|
color="901D77"
|
|
icon={<ArrowRightOutlined />}
|
|
htmlType={true}
|
|
/>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
</div>
|
|
}
|
|
/>
|
|
<DefaultModal
|
|
open={showSupplierModal}
|
|
handleCancel={handleModalCancel}
|
|
footer={false}
|
|
width={600}
|
|
children={
|
|
<div className="supplier-modal-container">
|
|
<div className="supplier-modal-header">
|
|
<FormHeader title={'Select Supplier'} />
|
|
</div>
|
|
<Form
|
|
layout="vertical"
|
|
className="supplier-modal-form"
|
|
onFinish={handleSupplierBasedProducts}
|
|
ref={formRef}
|
|
>
|
|
<div className="supplier-modal-body">
|
|
<Form.Item
|
|
name="SuppId"
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: 'Please select a supplier.',
|
|
},
|
|
]}
|
|
>
|
|
<DropDowns
|
|
label={'Select Supplier'}
|
|
onChangeFunction={handleSupplierChange}
|
|
options={suppliers}
|
|
valueData={selectedSupplier}
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
|
|
<Buttons
|
|
buttonText="SUBMIT"
|
|
color="901D77"
|
|
icon={<ArrowRightOutlined />}
|
|
htmlType={true}
|
|
/>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
export default StockExcel;
|