import React, { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { IoBagRemove } from 'react-icons/io5';
import { useDispatch } from 'react-redux';
import {
ArrowRightOutlined,
PlusCircleOutlined,
EditFilled,
} from '@ant-design/icons';
import { Form, Tooltip, Table, Input, Collapse, Select } from 'antd';
import { IoAddCircleSharp } from 'react-icons/io5';
import { InputField } from '../../Components/Forms/InputField.jsx';
import Buttons from '../../Components/Forms/Buttons.jsx';
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 } from '../../Services/Others.js';
import { DatePicProd } from '../../Components/Forms/DatePickerProduct.jsx';
import moment from 'moment';
import './openingStockForm.scss';
import {
getProductStockDetails,
postOpeningStock,
} from '../../Features/PurchaseOrder/PurchaseOrder.js';
const subDirectory = import.meta.env.BASE_URL;
const openingStockForm = () => {
const { Panel } = Collapse;
const formRef = useRef(null);
const productAddInfoRef = useRef(null);
const dispatch = useDispatch();
const navigate = useNavigate();
const location = useLocation();
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState('');
const [index, setindex] = useState();
const state = location?.state;
const editstate = state?.editstate;
const CompId = getSession('CompId');
const BranchId = getSession('BranchId');
const AppId = getSession('AppId');
const UserId = getSession('UserId');
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const [PurchaseData, setPurchaseData] = useState([]);
const [additionalInfoModal, setAdditionalInfoModal] = useState(false);
const [selectedRowRecord, setSelectedRowRecord] = useState({});
console.log(selectedRowRecord, 'selectedRowRecord');
const [Delete, setDelete] = useState(false);
const [ProductStockData, seProductStockData] = useState([]);
const [filteredProductStockData, setFilteredProductStockData] = useState([]);
const [eliminatedProducts, setEliminatedProducts] = useState([]);
const [eliminateModal, setEliminateModal] = useState(false);
const [additionalStockEntries, setAdditionalStockEntries] = useState([]);
const [searchText, setSearchText] = useState('');
const [activeAccordionKeys, setActiveAccordionKeys] = useState(['1']);
const [hasInitializedEditing, setHasInitializedEditing] = useState(false);
console.log(additionalStockEntries, 'additionalStockEntries');
console.log(filteredProductStockData, 'filteredProductStockData');
const items = [
{
name: 'Home',
link: `${subDirectory}app-page/home`,
},
{
name: 'Opening Stock',
link: `${subDirectory}setting/opening-stock`,
},
{
name: 'New',
link: null,
},
];
useEffect(() => {
dispatch(changeBreadCrumb({ items: items }));
ProductStockFun();
}, []);
const ProductStockFun = async () => {
try {
const Data = { AppId, CompId, BranchId, type: 'A' };
let response = await dispatch(getProductStockDetails(Data)).unwrap();
if (response?.data?.statusCode === 1) {
seProductStockData(response?.data?.data);
setFilteredProductStockData(response?.data?.data);
}
} catch (err) {
console.error('Error fetching stock details:', err);
}
};
const isEditing = (record, index) => index === editingKey;
const edit = (record, index) => {
form.setFieldsValue({ ...record });
setEditingKey(index);
setindex(index);
if (Delete) {
form.setFieldsValue({
TotalQty: { [index]: undefined },
TotalPiece: { [index]: undefined },
});
setDelete(false);
} else {
form.setFieldsValue({
TotalQty: { [index]: record?.TotalQty },
TotalPiece: { [index]: record?.TotalPiece },
});
}
};
useEffect(() => {
if (!hasInitializedEditing && filteredProductStockData?.length > 0) {
edit(filteredProductStockData[0], 0);
setHasInitializedEditing(true);
}
}, [filteredProductStockData, hasInitializedEditing]);
const save = async (index) => {
try {
const row = await form?.validateFields();
const modifiedObject = {};
for (const key in row) {
const newKey = key.slice(0, -1); // Remove the last character ("0") from the key
modifiedObject[newKey] = row[key];
}
const newData = [...filteredProductStockData];
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...modifiedObject });
setFilteredProductStockData(newData);
setEditingKey('');
}
} catch (err) {
console.error('Save failed:', err);
}
};
const handleKeyPress = async (e, record, index) => {
if (e.key === 'Enter') {
try {
await form.validateFields();
save(index);
} catch (error) {
console.error('Save failed:', error);
}
}
};
const openAdditionalInfoModal = (record, index) => {
console.log(record, 'recordrecord');
if (
!record?.TotalQty ||
record?.TotalQty === '' ||
record?.TotalQty === 0
) {
setMessageType('error');
setMessageData('Please enter Total Qty first');
return;
}
// if (!record?.TotalPiece || record?.TotalPiece === "" || record?.TotalPiece === 0) {
// setMessageType("error")
// setMessageData("Please enter Total Pieces first")
// return
// }
setSelectedRowRecord(record);
// Load existing modal details for this product
if (record.modalDetails && record.modalDetails.length > 0) {
setAdditionalStockEntries(record.modalDetails);
} else {
setAdditionalStockEntries([]);
}
setAdditionalInfoModal(true);
};
const columns = [
{
title: 'SI.NO',
align: 'center',
key: 'sno',
render: (text, object, index) => (
{index + 1}
),
},
{
title: 'Product Name',
dataIndex: 'ProdName',
key: 'ProdName',
align: 'left',
render: (text, record, index) => (
{record?.ProdName + '(' + record?.ProdVariantName + ')'}
),
},
// {
// title: 'Uom',
// dataIndex: 'UomName',
// key: 'UOMName',
// },
{
title: 'Total Qty',
dataIndex: 'TotalQty',
key: 'TotalQty',
editable: true,
render: (text, record, index) => {
return isEditing(record, index) ? (
{
if (value && value.toString().length > 10) {
return Promise.reject(
'Quantity cannot exceed 10 characters'
);
}
return Promise.resolve();
},
},
]}
>
handleKeyPress(e, record, index)}
onBlur={(e) => handleQtyChange(e, record)}
onChange={(e) => handleQtyChange(e, record, index)}
inputMode="decimal"
onInput={(e) => {
let value = e.target.value.replace(/[^0-9.]/g, '');
if (value.startsWith('.')) {
value = '0' + value;
}
const dotCount = (value.match(/\./g) || []).length;
if (dotCount > 1) {
const firstDotIndex = value.indexOf('.');
value =
value.substring(0, firstDotIndex + 1) +
value.substring(firstDotIndex + 1).replace(/\./g, '');
}
e.target.value = value;
}}
/>
) : (
text
);
},
},
{
title: 'Enter The Pieces',
dataIndex: 'TotalPiece',
key: 'TotalPiece',
editable: true,
render: (text, record, index) => {
return isEditing(record, index) ? (
{
if (value && value.toString().length > 10) {
return Promise.reject(
'Quantity cannot exceed 10 characters'
);
}
return Promise.resolve();
},
},
]}
>
handleKeyPress(e, record, index)}
onBlur={(e) => handleTotalPieceChange(e, record)}
onChange={(e) => handleTotalPieceChange(e, record, index)}
inputMode="decimal"
onInput={(e) => {
let value = e.target.value.replace(/[^0-9.]/g, '');
if (value.startsWith('.')) {
value = '0' + value;
}
const dotCount = (value.match(/\./g) || []).length;
if (dotCount > 1) {
const firstDotIndex = value.indexOf('.');
value =
value.substring(0, firstDotIndex + 1) +
value.substring(firstDotIndex + 1).replace(/\./g, '');
}
e.target.value = value;
}}
/>
) : (
text
);
},
},
// {
// title: 'Amount',
// dataIndex: 'Amount',
// key: 'Amount',
// editable: true,
// },
{
title: 'Additional Info',
dataIndex: 'AdditionalInfo',
key: 'AdditionalInfo',
width: 120,
align: 'center',
render: (text, record, index) => {
return (
<>
{' '}
openAdditionalInfoModal(record, index)}
/>
>
);
},
},
// {
// title: "Action",
// dataIndex: "Action",
// key: "Action",
// align: "center",
// render: (_, record, index) => (
// {
// e.stopPropagation();
// }}
// >
// statusFormatters(record, index)}
// />
//
// ),
// },
];
const statusFormatters = (record, index) => {
const Data = PurchaseData.filter((_, i) => i !== index);
setDelete(true);
form.setFieldsValue({
[`TotalQty${index}`]: undefined,
[`ReceivedQty${index}`]: undefined,
// [`AcceptedQty${index}`]: undefined,
// [`RejectedQty${index}`]: undefined,
// [`Amount${index}`]: undefined,
// [`FreeQty${index}`]: undefined,
// [`InwardPrice${index}`]: undefined,
// [`MRP${index}`]: undefined,
// [`PurcDisc${index}`]: undefined,
// [`SellPrice${index}`]: undefined,
// [`WhSalePrice${index}`]: undefined,
// [`offerSalePrice${index}`]: undefined,
// [`splSalePrice${index}`]: undefined
});
setPurchaseData(Data);
formRef?.current?.setFieldsValue({ ProdId: null });
};
const handleQtyChange = (e, record, index) => {
const inputValue = e.target.value;
// if (!inputValue) return;
if (!/^\d*\.?\d*$/.test(inputValue)) {
setMessageType('error');
setMessageData('Only numeric values are allowed');
return;
}
const qty = inputValue;
// Update the specific product by ProdId to avoid index mismatches when the
// displayed list is filtered (search). Using index from the filtered map
// can point to the wrong item in the underlying array.
const newData = filteredProductStockData.map((item) => {
if (
item?.ProdId === record?.ProdId &&
item?.ProdVariantName === record?.ProdVariantName
) {
const { modalDetails, ...rest } = item;
return {
...rest,
TotalQty: qty,
};
}
return item;
});
setFilteredProductStockData(newData);
// seProductStockData(newData);
};
const handleTotalPieceChange = (e, record, index) => {
if (record?.OnePcsAvailable !== 'Y') {
e.target.value = record?.TotalPiece ?? '';
return;
}
const inputValue = e.target.value;
if (!inputValue) return;
if (record?.OnePcsAvailable === 'N') {
setMessageType('error');
setMessageData('Total Piece entry not allowed when OnePcsAvailable is N');
return;
}
if (!/^\d*\.?\d*$/.test(inputValue)) {
setMessageType('error');
setMessageData('Only numeric values are allowed');
return;
}
const qty = inputValue;
// Update by ProdId instead of using the index from the filtered view.
const newData = filteredProductStockData.map((item) => {
if (
item?.ProdId === record?.ProdId &&
item?.ProdVariantName === record?.ProdVariantName
) {
return {
...item,
TotalPiece: qty,
};
}
return item;
});
setFilteredProductStockData(newData);
};
const onFinish = async () => {
let ProductDetails = filteredProductStockData
?.filter((item) => item?.TotalQty > 0 || item?.TotalPiece > 0)
?.map((item) => {
return {
ProdId: item?.ProdId,
ProdVariantName: item?.ProdVariantName,
OnePcsAvailable: item?.OnePcsAvailable || 'N',
TotalQty: item?.TotalQty,
TotalPcs: item?.TotalPiece || 0,
CreatedBy: UserId,
InwardDetails: item?.modalDetails
? item?.modalDetails?.map((item1) => {
return {
BatchRef: item1?.BatchRef,
AcceptedQty: item1?.Qty,
BalanceQty: item1?.Qty,
InwardPrice: item1?.SellPrice || 0,
MRP: item1?.MRP || 0,
SellPrice: item1?.SellPrice || 0,
WhSalePrice: item1?.WhSalePrice || 0,
OfferPrice: item1?.OfferPrice || 0,
SpecialPrice: item1?.SpecialPrice || 0,
InwardDate: item1?.ManufDate?.toISOString(),
ProdVariantName: item?.ProdVariantName,
OnePcsPrice: item1?.AmountPerPiece || 0,
NoOfPcs: item1?.OnePieceQty || 0,
ModelNumber: item1?.ModelNumber,
OnePcsAvailable: item?.OnePcsAvailable || 'N',
};
})
: [],
};
});
let PostData = {
AppId: AppId,
CompId: CompId,
BranchId: BranchId,
ProductDetails: ProductDetails,
};
try {
let Response = await dispatch(postOpeningStock(PostData))?.unwrap();
if (Response?.data?.statusCode === 1) {
setMessageType('success');
setMessageData('Stock added successfully');
navigate(`${subDirectory}setting/opening-stock/`, {
state: {
Notiffy: {
messageType: 'success',
messageData: 'Stock added successfully',
},
},
});
} else {
setMessageType('error');
setMessageData(
Response?.data?.message || 'Failed to add opening stock'
);
}
} catch (error) {
console.log(error, 'error');
}
};
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
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,
});
}
}, [additionalInfoModal]);
const handleMRPChange = (e) => {
let value = e?.target?.value === '' ? 0 : parseFloat(e?.target?.value);
productAddInfoRef?.current?.setFieldsValue({ SellPrice: null, MRP: value });
setSelectedRowRecord((prev) => ({ ...prev, SellPrice: null, MRP: value }));
productAddInfoRef?.current?.validateFields();
};
const handleAmountPerPiecechange = (e) => {
const inputValue = e?.target?.value;
const amountPerPiece = inputValue === '' ? '' : parseFloat(inputValue);
if (selectedRowRecord?.OnePcsAvailable === 'Y') {
setSelectedRowRecord((prev) => ({
...prev,
AmountPerPiece: amountPerPiece,
}));
}
};
const handleNumberofPieceinsidechange = (e) => {
const inputValue = e?.target?.value;
const numberOfPieceInside = inputValue === '' ? '' : parseFloat(inputValue);
if (selectedRowRecord?.OnePcsAvailable === 'Y') {
setSelectedRowRecord((prev) => ({
...prev,
NumberofPieceinside: numberOfPieceInside,
}));
}
};
const handleManufactureDate = (date, dateString) => {
const formattedDate =
dateString === ''
? undefined
: moment(dateString, ['DD-MM-YYYY']).format('YYYY-MM-DDTHH:mm:ss');
productAddInfoRef?.current?.setFieldsValue({
ManufDate: date,
});
setSelectedRowRecord((prev) => ({ ...prev, ManufDate: formattedDate }));
};
const handleBatchRefChange = (e) => {
const value = parseInt(e?.target?.value);
if (!/^\d*\.?\d*$/.test(value)) {
return;
}
productAddInfoRef?.current?.setFieldsValue({
BatchRef: value,
});
setSelectedRowRecord((prev) => ({ ...prev, BatchRef: value }));
};
const handleModelNoChange = (e) => {
const value = parseInt(e?.target?.value);
if (!/^\d*\.?\d*$/.test(value)) {
return;
}
productAddInfoRef?.current?.setFieldsValue({
ModelNumber: value,
});
setSelectedRowRecord((prev) => ({ ...prev, ModelNumber: value }));
};
const handleAddtnlDtlsSubmit = async (values) => {
const totalQty = parseFloat(selectedRowRecord?.TotalQty) || 0;
const currentQty = parseFloat(values?.Qty) || 0;
const existingQtySum = additionalStockEntries.reduce(
(sum, entry) => sum + (parseFloat(entry.Qty) || 0),
0
);
const totalUsedQty = existingQtySum + currentQty;
if (totalUsedQty !== totalQty) {
setMessageType('error');
setMessageData(
`Total quantity must equal ${totalQty}. Current total: ${totalUsedQty}`
);
return;
}
const newData = { ...values };
setAdditionalStockEntries((prev) => [...prev, newData]);
const updatedProductStockData = filteredProductStockData.map((product) => {
if (
product.ProdId === selectedRowRecord.ProdId &&
product.ProdVariantName === selectedRowRecord.ProdVariantName
) {
const details = [];
if (
Array.isArray(additionalStockEntries) &&
additionalStockEntries.length > 0
) {
details.push(...additionalStockEntries);
}
if (newData?.Qty) {
details.push(newData);
}
if (details.length > 0) {
return {
...product,
modalDetails: details,
};
}
}
return product;
});
setFilteredProductStockData(updatedProductStockData);
setAdditionalInfoModal(false);
setSelectedRowRecord({});
setActiveAccordionKeys([]);
await productAddInfoRef?.current?.resetFields();
// await handleAdditionalInfoClose();
};
const handleAdditionalInfoClose = async () => {
setAdditionalInfoModal(false);
setSelectedRowRecord({});
await productAddInfoRef?.current?.resetFields();
};
const handleAddNew = async () => {
try {
const values = await productAddInfoRef?.current?.validateFields();
if (!values?.Qty) {
setMessageType('error');
setMessageData('Please enter Qty before adding new entry');
return;
}
if (!values?.MRP) {
setMessageType('error');
setMessageData('Please enter MRP before adding new entry');
return;
}
if (!values?.SellPrice) {
setMessageType('error');
setMessageData('Please enter Selling Price before adding new entry');
return;
}
const newData = { ...selectedRowRecord, ...values };
const updatedEntries = [...additionalStockEntries, newData];
setAdditionalStockEntries(updatedEntries);
// Update ProductStockData with modal details
const updatedProductStockData = filteredProductStockData.map(
(product) => {
if (
product.ProdId === selectedRowRecord.ProdId &&
product.ProdVariantName === selectedRowRecord.ProdVariantName
) {
return {
...product,
modalDetails: updatedEntries,
};
}
return product;
}
);
seProductStockData(updatedProductStockData);
setFilteredProductStockData(
updatedProductStockData.filter(
(item) => !eliminatedProducts.includes(item.ProdId)
)
);
// Reset form for new entry
setSelectedRowRecord({
...selectedRowRecord,
Qty: '',
OnePieceQty: '',
MRP: '',
SellPrice: '',
BatchRef: '',
ModelNumber: '',
ManufDate: '',
AmountPerPiece: '',
NumberofPieceinside: '',
});
await productAddInfoRef?.current?.resetFields();
// Close all accordions after adding new entry
setActiveAccordionKeys([]);
} catch (error) {
console.error('Validation failed:', error);
}
};
const handleEditEntry = (index) => {
const entryToEdit = additionalStockEntries[index];
setSelectedRowRecord((prev) => ({ ...prev, ...entryToEdit }));
productAddInfoRef?.current?.setFieldsValue(entryToEdit);
setAdditionalStockEntries((prev) => prev.filter((_, i) => i !== index));
};
const handleDeleteEntry = (index) => {
setAdditionalStockEntries((prev) => prev.filter((_, i) => i !== index));
};
return (
{/*
handelAddButton()}
color="901D77"
icon={}
/>
*/}
{/*
}
/>
*/}
{/*
navigate(`${subDirectory}setting/purchase-entry`)}
>
View Entry List
*/}
{`${selectedRowRecord?.ProdName} (${selectedRowRecord?.ProdVariantName})`}