Merge pull request 'FIX #46: Add wholesale price and render all products with variants' (#53) from enhancement/productbulkupload into main

Reviewed-on: Pozomind/pozo-retail-app#53
This commit is contained in:
karthikalakshmi 2026-02-03 12:45:59 +05:30
commit 1a67e75151
2 changed files with 374 additions and 226 deletions

View File

@ -1,4 +1,10 @@
import React, { useState, useRef, useEffect, useContext, useCallback } from 'react';
import React, {
useState,
useRef,
useEffect,
useContext,
useCallback,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { read, utils } from 'xlsx';
import ExcelJS from 'exceljs';
@ -19,12 +25,15 @@ 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 { 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 {
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';
@ -57,10 +66,10 @@ const StockExcel = ({
const dispatch = useDispatch();
const AppId = getSession("AppId");
const CompId = getSession("CompId");
const BranchId = getSession("BranchId");
const UserId = getSession("UserId");
const AppId = getSession('AppId');
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const UserId = getSession('UserId');
const formRef = useRef(null);
const fileInputRef = useRef(fileInputRefSelector);
@ -70,14 +79,14 @@ const StockExcel = ({
const excelFileError = useSelector(excelFileErrorSelector);
const ApplicationPreferenceData = useSelector(ApplicationPreferences);
const purchaseReceiptBulkUploadCatId = ApplicationPreferenceData?.find(
p => p?.PreferredCatName?.toLowerCase() === "purchase receipt bulk"
(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")
console.log(Datas, 'Datas');
const [showSupplierModal, setShowSupplierModal] = useState(false);
const [suppliers, setSuppliers] = useState([]);
const [selectedSupplier, setSelectedSupplier] = useState(null);
@ -96,7 +105,7 @@ const StockExcel = ({
useEffect(() => {
getFieldSetup();
}, [purchaseReceiptBulkUploadCatId])
}, [purchaseReceiptBulkUploadCatId]);
const onComplete = useCallback(() => {
setMessageData(null);
@ -105,19 +114,33 @@ const StockExcel = ({
const getFieldSetup = async () => {
try {
const response = await dispatch(getFieldSetupData({ AppId, CompId, BranchId, categoryId: purchaseReceiptBulkUploadCatId, Type: 'EB' })).unwrap();
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
})) || []);
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");
setMessageType('error');
setMessageData('Failed to fetch field setup');
}
} catch (error) {
console.error('Error fetching field setup:', error);
@ -131,7 +154,7 @@ const StockExcel = ({
slicedData.forEach((item, index) => {
// Skip empty rows
if (!item || Object.values(item).every(val => !val)) return;
if (!item || Object.values(item).every((val) => !val)) return;
const rowData = {
key: index,
@ -164,8 +187,10 @@ const StockExcel = ({
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)) {
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()];
}
@ -182,18 +207,26 @@ const StockExcel = ({
{ key: 'BatchNo', header: 'Batch No.' },
{ key: 'ModelNo', header: 'Model No.' },
{ key: 'RejectedQty', header: 'Rejected Qty' },
{ key: 'FreeQty', header: 'Free 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 => {
optionalFields.forEach((field) => {
if (headers.includes(field.header)) {
rowData[field.key] = item[currentColIndex.toString()];
currentColIndex++;
}
});
if (rowData?.Amount && rowData?.MRP && rowData?.SalesPrice && rowData?.ProductName && rowData?.PaymentAmount) {
if (
rowData?.PurchaseRate &&
rowData?.Amount &&
rowData?.MRP &&
rowData?.SalesPrice &&
rowData?.ProductName &&
rowData?.PaymentAmount
) {
ExcelToJsConversion.push(rowData);
}
});
@ -292,12 +325,17 @@ const StockExcel = ({
// ...existing code...
const handleDownload = async () => {
try {
if (!supplierProducts || supplierProducts.length === 0 || !selectedSupplierData) {
if (
!supplierProducts ||
supplierProducts.length === 0 ||
!selectedSupplierData
) {
setMessageData('No products available to generate Excel.');
setMessageType('warning');
return;
}
const supplierDisplayName = getSupplierDisplayName(selectedSupplierData) || 'Supplier';
const supplierDisplayName =
getSupplierDisplayName(selectedSupplierData) || 'Supplier';
// Fetch excelColumns config (optional fields access)
let excelColumns = [];
try {
@ -314,12 +352,17 @@ const StockExcel = ({
excelColumns = response?.data?.data?.[0]?.ConfigDtl || [];
}
} catch (err) {
console.warn('Failed to fetch excelColumns config, proceeding with defaults', 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());
const found = excelColumns.find(
(c) => String(c.ConfigName).trim() === String(name).trim()
);
return found ? found.Access === 'Y' : false;
};
@ -331,7 +374,7 @@ const StockExcel = ({
allowBlank: allowBlank,
showErrorMessage: true,
errorTitle: 'Invalid Number',
error: 'Please enter a valid number'
error: 'Please enter a valid number',
};
};
@ -374,12 +417,20 @@ const StockExcel = ({
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('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,
@ -388,7 +439,11 @@ const StockExcel = ({
c.key === 'ProdName' || c.key === 'VariantName'
? 40
: c.key === 'Quantity'
? 10 : c.key === 'Supplier' || c.key === 'InvoiceDeliveryChallan' || c.key === 'SupplierInvoiceNumber' ? 30
? 10
: c.key === 'Supplier' ||
c.key === 'InvoiceDeliveryChallan' ||
c.key === 'SupplierInvoiceNumber'
? 30
: 20,
}));
@ -410,12 +465,21 @@ const StockExcel = ({
};
});
hiddenSheet.addRow(['ProductName', 'VariantName', 'MRP', 'SellPrice', 'Number of Piece Inside', 'Amount Per Piece']);
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 activeVariants = (product.ProdVariantPriceDetails || []).filter(
(v) => v.ActiveStatus === 'A'
);
const uniqueVariantsMap = new Map();
activeVariants.forEach((variant) => {
const variantName = variant.ProdVariantName;
@ -442,7 +506,8 @@ const StockExcel = ({
.trim()
.replace(/[^A-Za-z0-9_]/g, '_')
.replace(/^(\d)/, '_$1');
if (!safeName) safeName = `Product_${Math.random().toString(36).slice(2, 8)}`;
if (!safeName)
safeName = `Product_${Math.random().toString(36).slice(2, 8)}`;
const rangeRef = `ProductVariantMap!$B$${startRow}:$B$${endRow}`;
try {
workbook.definedNames.add(rangeRef, safeName);
@ -452,10 +517,41 @@ const StockExcel = ({
});
const startDataRow = 2;
const numberOfRows = 50;
for (let i = 0; i < numberOfRows; i++) {
worksheet.addRow({});
}
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) => {
@ -473,47 +569,19 @@ const StockExcel = ({
return s;
};
const today = new Date();
const inwardDateCol = colIndex('InwardDate');
if (inwardDateCol) {
const cell = worksheet.getCell(`${colLetter(inwardDateCol)}${startDataRow}`);
cell.value = today;
cell.numFmt = 'yyyy-mm-dd';
}
const numberOfRows = worksheet.rowCount;
const supplierName = selectedSupplierData?.SuppName || '';
const productNamesLiteral = productNames.join(',');
for (let r = startDataRow; r < startDataRow + numberOfRows; r++) {
for (let r = startDataRow; r <= numberOfRows; r++) {
if (colIndex('ProdName')) {
const cIdx = colIndex('ProdName');
const letter = colLetter(cIdx);
const prodCellRef = `${letter}${r}`;
const cell = worksheet.getCell(prodCellRef);
cell.dataValidation = {
type: 'list',
allowBlank: false,
formulae: [`"${productNamesLiteral}"`],
};
cell.protection = { locked: false };
const cell = worksheet.getCell(r, cIdx);
cell.protection = { locked: true };
}
if (colIndex('VariantName')) {
const cIdx = colIndex('VariantName');
const letter = colLetter(cIdx);
const varCellRef = `${letter}${r}`;
const productColLetter = colLetter(colIndex('ProdName'));
const productCellRef = `${productColLetter}${r}`;
const formula = `INDIRECT(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(${productCellRef}," ","_"),"-","_"),"&","_"),"/","_"),".","_"),"(","_"),")","_"),"[","_"),"]","_"),",","_"))`;
const cell = worksheet.getCell(varCellRef);
cell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [formula],
showErrorMessage: true,
errorTitle: 'Invalid Variant',
error: 'Please select a variant from the dropdown'
};
cell.protection = { locked: false };
const cell = worksheet.getCell(r, cIdx);
cell.protection = { locked: true };
}
if (colIndex('Quantity')) {
const cIdx = colIndex('Quantity');
@ -544,7 +612,8 @@ const StockExcel = ({
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)'
prompt:
'Enter rejected quantity (must be less than total quantity)',
};
rejCell.protection = { locked: false };
}
@ -565,31 +634,55 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid 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.dataValidation = { type: 'list', formulae: [`"${supplierDisplayName}"`] };
cell.value = supplierDisplayName;
cell.protection = { locked: false };
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"'] };
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"'] };
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 };
worksheet.getCell(r, colIndex('SupplierInvoiceNumber')).protection = {
locked: false,
};
}
if (colIndex('SupplierInvoiceDate')) {
const cell = worksheet.getCell(r, colIndex('SupplierInvoiceDate'));
@ -601,12 +694,14 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid date'
error: 'Please enter a valid date',
};
cell.protection = { locked: false };
}
if (colIndex('DeliveryChallanNo')) {
worksheet.getCell(r, colIndex('DeliveryChallanNo')).protection = { locked: false };
worksheet.getCell(r, colIndex('DeliveryChallanNo')).protection = {
locked: false,
};
}
if (colIndex('DeliveryInvoiceDate')) {
const cell = worksheet.getCell(r, colIndex('DeliveryInvoiceDate'));
@ -618,63 +713,33 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid date'
error: 'Please enter a valid date',
};
cell.protection = { locked: false };
}
if (colIndex('MRP')) {
const mrpCol = colIndex('MRP');
const prodCol = colIndex('ProdName');
const varCol = colIndex('VariantName');
const mrpCell = worksheet.getCell(r, mrpCol);
const prodLetter = colLetter(prodCol);
const varLetter = colLetter(varCol);
mrpCell.value = {
formula: `IF(OR(${prodLetter}${r}="",${varLetter}${r}=""),"",SUMPRODUCT((ProductVariantMap!$A$2:$A$1000=${prodLetter}${r})*(ProductVariantMap!$B$2:$B$1000=${varLetter}${r})*ProductVariantMap!$C$2:$C$1000))`
};
mrpCell.numFmt = '#,##0.00';
mrpCell.protection = { locked: false };
addNumberValidation(mrpCell, true, 0);
}
if (colIndex('SalesPrice')) {
const spCol = colIndex('SalesPrice');
const prodCol = colIndex('ProdName');
const varCol = colIndex('VariantName');
const spCell = worksheet.getCell(r, spCol);
const prodLetter = colLetter(prodCol);
const varLetter = colLetter(varCol);
spCell.value = {
formula: `IF(OR(${prodLetter}${r}="",${varLetter}${r}=""),"",SUMPRODUCT((ProductVariantMap!$A$2:$A$1000=${prodLetter}${r})*(ProductVariantMap!$B$2:$B$1000=${varLetter}${r})*ProductVariantMap!$D$2:$D$1000))`
};
spCell.numFmt = '#,##0.00';
spCell.protection = { locked: false };
addNumberValidation(spCell, true, 0);
}
if (colIndex('NumberofPieceInside')) {
const nopCol = colIndex('NumberofPieceInside');
const prodCol = colIndex('ProdName');
const varCol = colIndex('VariantName');
const nopCell = worksheet.getCell(r, nopCol);
const prodLetter = colLetter(prodCol);
const varLetter = colLetter(varCol);
nopCell.value = {
formula: `IF(OR(${prodLetter}${r}="",${varLetter}${r}=""),"",SUMPRODUCT((ProductVariantMap!$A$2:$A$1000=${prodLetter}${r})*(ProductVariantMap!$B$2:$B$1000=${varLetter}${r})*ProductVariantMap!$E$2:$E$1000))`
};
nopCell.numFmt = '#,##0';
addNumberValidation(nopCell, true, 0);
nopCell.protection = { locked: false };
}
if (colIndex('AmountPerPiece')) {
const appCol = colIndex('AmountPerPiece');
const prodCol = colIndex('ProdName');
const varCol = colIndex('VariantName');
const appCell = worksheet.getCell(r, appCol);
const prodLetter = colLetter(prodCol);
const varLetter = colLetter(varCol);
appCell.value = {
formula: `IF(OR(${prodLetter}${r}="",${varLetter}${r}=""),"",SUMPRODUCT((ProductVariantMap!$A$2:$A$1000=${prodLetter}${r})*(ProductVariantMap!$B$2:$B$1000=${varLetter}${r})*ProductVariantMap!$F$2:$F$1000))`
};
appCell.numFmt = '#,##0.00';
addNumberValidation(appCell, true, 0);
appCell.protection = { locked: false };
}
if (colIndex('PaymentType')) {
const cIdx = colIndex('PaymentType');
@ -708,13 +773,16 @@ const StockExcel = ({
pmCell.dataValidation = {
type: 'list',
allowBlank: true,
formulae: [`IF(${paymentTypeLetter}${r}="Paid",ValidationHelper!$A$1:$A$3,"")`],
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'
prompt:
'If Payment Type is Credit, leave empty. If Paid, select: Cash, Credit, or UPI',
};
pmCell.protection = { locked: false };
}
@ -729,7 +797,7 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid date'
error: 'Please enter a valid date',
};
dueCell.protection = { locked: false };
}
@ -744,7 +812,7 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid date'
error: 'Please enter a valid date',
};
manufCell.protection = { locked: false };
}
@ -759,7 +827,7 @@ const StockExcel = ({
formulae: [new Date(1900, 0, 1)],
showErrorMessage: true,
errorTitle: 'Invalid Date',
error: 'Please enter a valid date'
error: 'Please enter a valid date',
};
expCell.protection = { locked: false };
}
@ -769,7 +837,9 @@ const StockExcel = ({
const rLetter = colLetter(rIdx);
const qLetter = colLetter(qIdx);
const recCell = worksheet.getCell(`${rLetter}${r}`);
recCell.value = { formula: `IF(${qLetter}${r}="","",${qLetter}${r})` };
recCell.value = {
formula: `IF(${qLetter}${r}="","",${qLetter}${r})`,
};
addNumberValidation(recCell, true, 0);
}
if (colIndex('AcceptedQty') && colIndex('Quantity')) {
@ -782,15 +852,21 @@ const StockExcel = ({
const formulaCell = worksheet.getCell(`${aLetter}${r}`);
if (rejLetter) {
formulaCell.value = {
formula: `IF(${qLetter}${r}="","",MAX(0,${qLetter}${r}-IF(${rejLetter}${r}="",0,${rejLetter}${r})))`
formula: `IF(${qLetter}${r}="","",MAX(0,${qLetter}${r}-IF(${rejLetter}${r}="",0,${rejLetter}${r})))`,
};
} else {
formulaCell.value = { formula: `IF(${qLetter}${r}="","",${qLetter}${r})` };
formulaCell.value = {
formula: `IF(${qLetter}${r}="","",${qLetter}${r})`,
};
}
addNumberValidation(formulaCell, true, 0);
formulaCell.protection = { locked: true };
}
if (colIndex('PaymentAmount') && colIndex('Quantity') && colIndex('PurchaseRate')) {
if (
colIndex('PaymentAmount') &&
colIndex('Quantity') &&
colIndex('PurchaseRate')
) {
const payIdx = colIndex('PaymentAmount');
const qIdx = colIndex('Quantity');
const pIdx = colIndex('PurchaseRate');
@ -812,7 +888,11 @@ const StockExcel = ({
formulaCell.numFmt = '#,##0.00';
addNumberValidation(formulaCell, true, 0);
}
if (colIndex('Amount') && colIndex('Quantity') && colIndex('PurchaseRate')) {
if (
colIndex('Amount') &&
colIndex('Quantity') &&
colIndex('PurchaseRate')
) {
const amtIdx = colIndex('Amount');
const qIdx = colIndex('Quantity');
const pIdx = colIndex('PurchaseRate');
@ -827,11 +907,21 @@ const StockExcel = ({
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.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('', {
@ -1070,6 +1160,12 @@ const StockExcel = ({
key: 'FreeQty',
editable: true,
},
{
title: 'Wholesale Price',
dataIndex: 'WholesalePrice',
key: 'WholesalePrice',
editable: true,
},
];
const column = columns?.map((col) => {
@ -1205,7 +1301,7 @@ const StockExcel = ({
RetailPrice: row?.RetailPrice,
AmountperPiece: row?.AmountperPiece,
NumberofPieceInside: row?.NumberofPieceInside,
WholeSale: row?.WholeSale,
WholesalePrice: row?.WholesalePrice,
Offer: row?.Offer,
SplPrice: row?.SplPrice,
ReceivedQuantity: row?.ReceivedQuantity,
@ -1245,31 +1341,31 @@ const StockExcel = ({
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',
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
Type: 'EB',
FormType: 'PurchaseEntry',
TypeId: purchaseReceiptBulkUploadCatId,
ConfigDtl: selectedFields?.map((field) => ({
ConfigId: field,
Access: 'Y',
})),
"CreatedBy": UserId
}
CreatedBy: UserId,
};
const response = await dispatch(postFieldSetup(postData))?.unwrap();
if (response?.data?.statusCode === 1) {
setMessageType("success");
setMessageType('success');
setMessageData(response?.data?.response);
setFieldSetup(false);
await getFieldSetup();
} else {
setMessageType("error");
setMessageData("Failed to set up fields");
setMessageType('error');
setMessageData('Failed to set up fields');
}
}
};
const handleFieldSelect = (value) => {
setSelectedFields((prev) => {
@ -1320,7 +1416,7 @@ const StockExcel = ({
} catch (error) {
console.error('Error fetching suppliers:', error);
setMessageData('Failed to fetch suppliers.');
setMessageType('error')
setMessageType('error');
}
}, [CompId, AppId, BranchId, dispatch]);
@ -1331,14 +1427,22 @@ const StockExcel = ({
const type = supplierData.Type;
const LocationType =
type === 'Supplier' ? 'S' : type === 'Branch' ? 'B' : type === 'WareHouse' ? 'W' : '';
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,
BranchId:
LocationType === 'S' ? BranchId : supplierData?.SuppBranchId,
SuppId:
LocationType === 'S' ? supplierId : supplierData?.SuppBranchId,
LocationType,
})
)?.unwrap();
@ -1349,25 +1453,24 @@ const StockExcel = ({
} else {
setSupplierProducts([]);
setMessageData('No products are mapped to this supplier.');
setMessageType('warning')
setMessageType('warning');
}
} else {
setSupplierProducts([]);
setMessageData('Failed to fetch supplier products.');
setMessageType('error')
setMessageType('error');
}
} catch (error) {
console.error('Error fetching supplier products:', error);
setMessageData('An error occurred while fetching products.');
setMessageType('error')
setMessageType('error');
}
};
const handleSupplierBasedProducts = useCallback(async () => {
if (!selectedSupplier) {
setMessageData('Please select a supplier.');
setMessageType('warning')
setMessageType('warning');
return;
}
@ -1400,19 +1503,25 @@ const StockExcel = ({
onSubmit={handleFileSubmit}
>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div className='upload-excel-header'>
<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>
<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>
@ -1549,7 +1658,9 @@ const StockExcel = ({
children={
<div className="field-setup-container">
<div className="field-setup-header">
<FormHeader title={'Select the fields you want to include in the table'} />
<FormHeader
title={'Select the fields you want to include in the table'}
/>
</div>
<div className="field-setup-content">
<Form onFinish={handleFieldSetupSubmit} ref={formRef}>
@ -1558,11 +1669,16 @@ const StockExcel = ({
label="Select fields"
// valueData={selectedFields}
onChangeFunction={handleFieldSelect}
options={tableFieldPreferences?.filter(p => !selectedFields?.some(s => s === p.value))} />
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))
?.map((id) =>
tableFieldPreferences?.find((p) => p.value === id)
)
.filter(Boolean)
.map((field) => (
<div className="selected-field" key={field.value}>

View File

@ -11,7 +11,11 @@ import { Tables } from '../../Components/Tables/Table';
import FormHeader from '../PageComponents/FormHeader.jsx';
import Search from '../../Components/Forms/Search.jsx';
import Buttons from '../../Components/Forms/Buttons';
import { getSession, dateFormatChange, ExtractDateFormate } from '../../Services/Others';
import {
getSession,
dateFormatChange,
ExtractDateFormate,
} from '../../Services/Others';
import { Messages } from '../../Components/Notifications/Messages';
import {
getStockData,
@ -175,12 +179,16 @@ const StockList = () => {
};
const getPreference = async () => {
const data = { AppId: AppId, CompId: CompId, BranchId: BranchId };
const { data: res } = await dispatch(getPreferenceData(data)).unwrap()
const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find((setting) => setting?.SettingIdName?.toLowerCase() === "decimal" && setting?.SettingValue === 'Y');
const { data: res } = await dispatch(getPreferenceData(data)).unwrap();
const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find(
(setting) =>
setting?.SettingIdName?.toLowerCase() === 'decimal' &&
setting?.SettingValue === 'Y'
);
if (decimalSetting) {
setAllowDecimal(true)
setAllowDecimal(true);
}
}
};
const actionsFormatter = async (row, rowIndex) => {
navigate(
`${subDirectory}setting/purchase-entry/update`,
@ -200,11 +208,15 @@ const StockList = () => {
};
const handlePrevImage = () => {
setCurrentImageIndex(prev => prev > 0 ? prev - 1 : productImageDetails.length - 1);
setCurrentImageIndex((prev) =>
prev > 0 ? prev - 1 : productImageDetails.length - 1
);
};
const handleNextImage = () => {
setCurrentImageIndex(prev => prev < productImageDetails.length - 1 ? prev + 1 : 0);
setCurrentImageIndex((prev) =>
prev < productImageDetails.length - 1 ? prev + 1 : 0
);
};
const handleProductmodalCancel = () => {
@ -218,7 +230,7 @@ const StockList = () => {
setImageModal(false);
setProductImageDetails([]);
setCurrentImageIndex(0);
}
};
// WRITED BY SREE
function safeRound(amountStr) {
if (amountStr == null) return allowDecimal ? '0.00' : '0';
@ -254,7 +266,8 @@ const StockList = () => {
),
filteredValue: [searchedText],
onFilter: (value, record) => {
return extractLastNumberOrderId(record.InvoiceNo, record?.FYStatus)?.toString()
return extractLastNumberOrderId(record.InvoiceNo, record?.FYStatus)
?.toString()
.toLowerCase()
.includes(value.toLowerCase());
},
@ -273,11 +286,8 @@ const StockList = () => {
key: 'CustSuppName',
align: 'center',
render: (text, row) => (
<a style={{ color: 'black' }}>
{row?.CustSuppName || '-'}
</a>
<a style={{ color: 'black' }}>{row?.CustSuppName || '-'}</a>
),
},
{
title: 'Supp Invoice No',
@ -285,11 +295,8 @@ const StockList = () => {
key: 'SuppInvoiceNo',
align: 'center',
render: (text, row) => (
<a style={{ color: 'black' }}>
{row?.SuppInvoiceNo || '-'}
</a>
<a style={{ color: 'black' }}>{row?.SuppInvoiceNo || '-'}</a>
),
},
{
@ -323,17 +330,17 @@ const StockList = () => {
align: 'center',
render: (data, record) => {
if (data?.length > 0) {
return <IoEye
style={{ color: '#1292EE', fontSize: '25px', cursor: 'pointer' }}
onClick={() => viewImages(data)}
/>
return (
<IoEye
style={{ color: '#1292EE', fontSize: '25px', cursor: 'pointer' }}
onClick={() => viewImages(data)}
/>
);
} else {
return <p>-</p>
return <p>-</p>;
}
}
,
}
},
},
];
const Proddetailcolumns = [
{
@ -529,9 +536,11 @@ const StockList = () => {
useEffect(() => {
let updatedExceldatasubmit = Exceldatasubmit?.map((excelItem) => {
const [productName, sizeAndUom] = (excelItem?.ProductName?.split(' (')) || [];
const [size, uomName] = (sizeAndUom ? sizeAndUom.slice(0, -1).split(' ') : []);
const [productName, sizeAndUom] =
excelItem?.ProductName?.split(' (') || [];
const [size, uomName] = sizeAndUom
? sizeAndUom.slice(0, -1).split(' ')
: [];
const matchingProduct = Productdata?.find(
(product) =>
@ -584,17 +593,17 @@ const StockList = () => {
// Helper function to check if product already exists in ProdDetails
const isDuplicateProduct = (prodDetails, newItem) => {
return prodDetails.some(item =>
item.ProdName === newItem.ProdName &&
item.VariantName === newItem.VariantName &&
item.MRP === newItem.MRP &&
item.SalesPrice === newItem.SalesPrice &&
item.Quantity === newItem.Quantity &&
item.RejectedQty === newItem.RejectedQty
return prodDetails.some(
(item) =>
item.ProdName === newItem.ProdName &&
item.VariantName === newItem.VariantName &&
item.MRP === newItem.MRP &&
item.SalesPrice === newItem.SalesPrice &&
item.Quantity === newItem.Quantity &&
item.RejectedQty === newItem.RejectedQty
);
};
const handleSubmit = async () => {
let FilterData = Exceldatasubmit?.filter((a) => a['ProductName'] != '');
if (FilterData && FilterData.length > 0) {
@ -618,7 +627,7 @@ const StockList = () => {
DeliveryInvoiceDate: data.DeliveryInvoiceDate,
DueDate: data.DueDate,
},
products: []
products: [],
};
}
@ -636,7 +645,6 @@ const StockList = () => {
};
const formattedData = Object.values(groupedData).map((group) => {
const { groupInfo, products } = group;
// Calculate totals based on products
@ -666,25 +674,33 @@ const StockList = () => {
PaymentMode: groupInfo.PaymentMode,
PaymentAmount: PaymentAmount.toFixed(2),
InvoiceDate: groupInfo.InwardDate
? moment(groupInfo.InwardDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(groupInfo.InwardDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
SuppInvoiceNo: groupInfo.SupplierInvoiceNumber,
SuppInvoiceDate: groupInfo.SupplierInvoiceDate
? moment(groupInfo.SupplierInvoiceDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(groupInfo.SupplierInvoiceDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
DeliveryChallanNo: groupInfo.DeliveryChallanNo,
DeliveryInvoiceDate: groupInfo.DeliveryInvoiceDate
? moment(groupInfo.DeliveryInvoiceDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(groupInfo.DeliveryInvoiceDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
DueDate: groupInfo.DueDate
? moment(groupInfo.DueDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(groupInfo.DueDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
InvoiceAmount: Totalamount.toFixed(2),
TaxAmount: Totaltax.toFixed(2),
TotalAmount: Totalamount.toFixed(2),
BillAmount: Billamount.toFixed(2),
PaymentStatus: "S",
PurOrderStatus: "P",
PaymentStatus: 'S',
PurOrderStatus: 'P',
ProdDetails: products.map((item) => ({
ProdName: item.ProductName,
ProdVariantName: item.VariantName,
@ -694,10 +710,14 @@ const StockList = () => {
AcceptedQty: item.AcceptedQty,
FreeQty: item.FreeQty,
ManufDate: item.ManufactureDate
? moment(item.ManufactureDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(item.ManufactureDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
ExpDate: item.ExpireDate
? moment(item.ExpireDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss')
? moment(item.ExpireDate, 'YYYY-MM-DD').format(
'YYYY-MM-DDTHH:mm:ss'
)
: null,
BatchNo: item.BatchNo,
ModelNo: item.ModelNo,
@ -707,6 +727,7 @@ const StockList = () => {
SellPrice: item.SalesPrice,
OnePcsPrice: item.AmountPerPiece,
NoOfPcs: item.NumberofPieceInside,
WhSalePrice: item.WholesalePrice
})),
};
});
@ -905,31 +926,35 @@ const StockList = () => {
width={600}
className={'padding-less-modal'}
children={
<div >
<div>
{productImageDetails?.length > 0 && (
<div className='image-preview'>
<div className="image-preview">
{productImageDetails.length > 1 && (
<>
<button
onClick={handlePrevImage}
className='image-preview__nav-btn'
className="image-preview__nav-btn"
>
<FaAngleLeft />
</button>
</>
)}
<div className='image-preview__content'>
<div className="image-preview__content">
<Image
src={productImageDetails[currentImageIndex]?.ImageUrl}
alt="Preview"
style={{ maxWidth: '100%', maxHeight: '400px', objectFit: 'contain' }}
style={{
maxWidth: '100%',
maxHeight: '400px',
objectFit: 'contain',
}}
/>
</div>
{productImageDetails.length > 1 && (
<>
<button
onClick={handleNextImage}
className='image-preview__nav-btn'
className="image-preview__nav-btn"
>
<FaAngleRight />
</button>
@ -937,7 +962,14 @@ const StockList = () => {
)}
</div>
)}
<div style={{ marginTop: '10px', color: '#666', textAlign: 'center', fontFamily: 'Poppins' }}>
<div
style={{
marginTop: '10px',
color: '#666',
textAlign: 'center',
fontFamily: 'Poppins',
}}
>
{currentImageIndex + 1} of {productImageDetails.length}
</div>
</div>