Android_Retail/src/Pages/openingStock/openingstockForm.jsx

1528 lines
60 KiB
React
Raw Normal View History

2026-01-27 18:27:29 +05:30
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) => (
<a className="openingStock-sno-link">{index + 1}</a>
),
},
{
title: 'Product Name',
dataIndex: 'ProdName',
key: 'ProdName',
align: 'left',
render: (text, record, index) => (
<a className="openingStock-product-name-link">
{record?.ProdName + '(' + record?.ProdVariantName + ')'}
</a>
),
},
// {
// title: 'Uom',
// dataIndex: 'UomName',
// key: 'UOMName',
// },
{
title: 'Total Qty',
dataIndex: 'TotalQty',
key: 'TotalQty',
editable: true,
render: (text, record, index) => {
return isEditing(record, index) ? (
<Form.Item
name={'TotalQty' + index}
rules={[
{
required: true,
pattern: /^(?!0+$)(?!0+\.0*$)\d*\.?\d+$/,
message: 'Please enter valid quantity',
},
{
validator: (_, value) => {
if (value && value.toString().length > 10) {
return Promise.reject(
'Quantity cannot exceed 10 characters'
);
}
return Promise.resolve();
},
},
]}
>
<Input
onPressEnter={(e) => 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;
}}
/>
</Form.Item>
) : (
text
);
},
},
{
title: 'Enter The Pieces',
dataIndex: 'TotalPiece',
key: 'TotalPiece',
editable: true,
render: (text, record, index) => {
return isEditing(record, index) ? (
<Form.Item
name={'TotalPiece' + index}
rules={[
{
required: true,
pattern: /^(?!0+$)(?!0+\.0*$)\d*\.?\d+$/,
message: 'Please enter valid quantity',
},
{
validator: (_, value) => {
if (value && value.toString().length > 10) {
return Promise.reject(
'Quantity cannot exceed 10 characters'
);
}
return Promise.resolve();
},
},
]}
>
<Input
onPressEnter={(e) => 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;
}}
/>
</Form.Item>
) : (
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 (
<>
{' '}
<IoAddCircleSharp
className="openingStock-additional-info-icon shape-preview"
onClick={() => openAdditionalInfoModal(record, index)}
/>
</>
);
},
},
// {
// title: "Action",
// dataIndex: "Action",
// key: "Action",
// align: "center",
// render: (_, record, index) => (
// <a
// onClick={(e) => {
// e.stopPropagation();
// }}
// >
// <DeleteFilled
// style={{
// color: "#FF4D4F",
// }}
// onClick={() => statusFormatters(record, index)}
// />
// </a>
// ),
// },
];
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 (
<div className="pageOverAll">
<div className="userPage">
<div className="userPageContent">
<Messages
messageType={messageType}
messageData={messageData}
onComplete={onComplete}
/>
<div className="purchase-entry-fh">
<div className="formName">
<FormHeader title={'Opening Stock Entry'} />
{/* <div className="productMaster-input">
<Buttons
buttonText={ "Add New"}
handleSubmit={() => handelAddButton()}
color="901D77"
icon={<PlusOutlined />}
/>
</div> */}
{/* <div className="uploadexcelBtn">
<Buttons
buttonText="Upload Excel"
className="tertiary_Button"
handleSubmit={openModal}
disabled={false}
icon={<FiUploadCloud size={18} />}
/>
</div> */}
<Tooltip title="Ignore Products">
<button
onClick={() => setEliminateModal(true)}
className="openingStock-ignoreProductBTN"
>
<IoBagRemove />
{/* Ignore Products */}
</button>
</Tooltip>
{/* <div
style={{
display: 'flex',
alignItems: 'center',
gap: '7px',
padding: '6px 12px',
backgroundColor: '#059645',
borderRadius: '8px',
color: 'white',
cursor: 'pointer',
fontFamily: 'Poopies',
fontWeight: '400',
whiteSpace: "nowrap",
fontSize: "15px"
}}
onClick={() => navigate(`${subDirectory}setting/purchase-entry`)}
>
<FaEye /> <p> View Entry List</p>
</div> */}
</div>
</div>
<div className="formDiv">
<Form
ref={formRef}
initialValues={editstate}
className="formDivAnt"
onFinish={onFinish}
>
<div className="purchase-entry-form">
<div className="formDivS">
<div className="inputForm">
<div className="openingStock-search-input">
<Input
placeholder="Search products..."
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
className="openingStock-search-input-field"
allowClear
/>
</div>
<div className="Product-table openingStock-product-table">
<style>
{`
.Product-table .ant-form-item-explain-error {
display: none !important;
}
.Product-table .ant-form-item {
margin-bottom: 0 !important;
}
`}
</style>
<Form form={form} component={false}>
<table className="openingStock-table-wrapper">
<thead className="openingStock-table-header">
<tr className="openingStock-table-header-row">
<th
className="openingStock-table-header-cell"
style={{ width: '20px' }}
>
S.NO
</th>
<th className="openingStock-table-header-cell-left">
Product Name
</th>
<th className="openingStock-table-header-cell">
Total Qty
</th>
<th className="openingStock-table-header-cell">
Total Pieces
</th>
<th className="openingStock-table-header-cell">
Additional Info
</th>
</tr>
</thead>
<tbody>
{filteredProductStockData
.filter(
(record) =>
record.ProdName.toLowerCase().includes(
searchText.toLowerCase()
) ||
record.ProdVariantName.toLowerCase().includes(
searchText.toLowerCase()
)
)
.map((record, index) => (
<tr
key={index}
className="openingStock-table-row"
>
<td className="openingStock-table-cell">
{index + 1}
</td>
<td className="openingStock-table-cell-left">
{record?.ProdName} (
{record?.ProdVariantName})
</td>
<td className="openingStock-table-cell-input">
<Input
className="openingStock-input-field"
value={record?.TotalQty ?? ''}
onChange={(e) =>
handleQtyChange(e, record, index)
}
inputMode="decimal"
onBlur={(e) =>
handleQtyChange(e, record, index)
}
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;
}}
/>
</td>
<td className="openingStock-table-cell-input">
<Input
className="openingStock-input-field"
value={record?.TotalPiece ?? ''}
onChange={(e) =>
handleTotalPieceChange(e, record, index)
}
inputMode="decimal"
onBlur={(e) =>
handleTotalPieceChange(e, record, index)
}
disabled={record?.OnePcsAvailable !== 'Y'}
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;
}}
/>
</td>
<td className="openingStock-table-cell">
<IoAddCircleSharp
className="openingStock-add-icon"
onClick={(e) => {
e.stopPropagation();
openAdditionalInfoModal(record, index);
}}
/>
</td>
</tr>
))}
</tbody>
</table>
</Form>
</div>
{/* {
PurchaseData?.length > 0 && <div className="purchase-status-data">
<div className="total-purchase-amnt">
<label>Total Amount:&nbsp;</label>
<div>{PurchaseData.reduce((acc, data) => acc + data?.Amount, 0)}</div>
</div>
{!orderType &&
<div className="purchase-status">
<RadioGrpButton
content={[
{ value: "P", label: "Pending" },
{ value: "C", label: "Completed" },
]}
Header={"Purchase Status"}
defaultSelect={purchaseStatus}
onSelectFuntion={purchaseStatusChange}
/>
</div>}
</div>
} */}
</div>
</div>
</div>
</Form>
</div>
<Form
ref={formRef}
initialValues={editstate}
className="formDivAnt"
onFinish={onFinish}
>
<div className="openingStock-submitButton">
<Buttons
buttonText="SUBMIT"
color="901D77"
icon={<ArrowRightOutlined />}
/>
</div>
</Form>
</div>
<div>
<DefaultModal
open={additionalInfoModal}
className={'additional-dtls-modal'}
footer={false}
children={
<>
<div className="openingStock-modal-header">
<h3>{`${selectedRowRecord?.ProdName} (${selectedRowRecord?.ProdVariantName})`}</h3>
<button
onClick={handleAddNew}
className="openingStock-add-new-btn"
>
<PlusCircleOutlined />
Add New
</button>
</div>
<Form ref={productAddInfoRef} onFinish={handleAddtnlDtlsSubmit}>
<div className="collapse-data">
<div className="pricing-dtls">
<Collapse
activeKey={activeAccordionKeys}
onChange={setActiveAccordionKeys}
>
<Panel header="Pricing Details" key="1">
<div className="pricing-dtl-fields">
<Form.Item name="Qty">
<InputField
autoComplete="off"
label={
<label className="required">
Qty (Available:{' '}
{(() => {
const totalQty =
parseFloat(
selectedRowRecord?.TotalQty
) || 0;
const usedQty =
additionalStockEntries.reduce(
(sum, entry) =>
sum + (parseFloat(entry.Qty) || 0),
0
);
return totalQty - usedQty;
})()}
)
</label>
}
isOnChange={
selectedRowRecord?.Qty ? true : false
}
value={selectedRowRecord?.Qty}
onChange={(e) => {
const val = e?.target?.value;
setSelectedRowRecord((prev) => ({
...prev,
Qty: val,
}));
}}
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;
}}
/>
</Form.Item>
<Form.Item name="MRP">
<InputField
autoComplete="off"
label={<label>MRP</label>}
isOnChange={
selectedRowRecord?.MRP !== '' &&
selectedRowRecord.hasOwnProperty('MRP')
? true
: false
}
value={selectedRowRecord?.MRP}
onChange={handleMRPChange}
/>
</Form.Item>
<Form.Item name="SellPrice">
<InputField
autoComplete="off"
label={<label>Sales Price</label>}
isOnChange={
selectedRowRecord?.SellPrice !== '' &&
selectedRowRecord.hasOwnProperty('SellPrice')
? true
: false
}
value={selectedRowRecord?.SellPrice}
onChange={(e) => {
const val =
e?.target?.value === ''
? 0
: parseFloat(e?.target?.value);
setSelectedRowRecord((prev) => ({
...prev,
SellPrice: val,
}));
}}
/>
</Form.Item>
{/* {selectedRowRecord?.OnePcsAvailable === "Y" && (
<Form.Item name="OnePieceQty">
<InputField
autoComplete="off"
label={<label>One Piece Qty</label>}
isOnChange={
selectedRowRecord?.OnePieceQty
? true
: false
}
value={selectedRowRecord?.OnePieceQty}
onChange={(e) => {
const val = e?.target?.value;
setSelectedRowRecord((prev) => ({
...prev,
OnePieceQty: val,
}));
}}
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;
}}
/>
</Form.Item>
)} */}
{selectedRowRecord?.OnePcsAvailable === 'Y' && (
<>
<Form.Item name="NumberofPieceinside">
<InputField
autoComplete="off"
label={
<label>Number of Piece Inside</label>
}
onChange={(e) =>
handleNumberofPieceinsidechange(e)
}
isOnChange={false}
value={
selectedRowRecord?.NumberofPieceinside
}
/>
</Form.Item>
<Form.Item name="AmountPerPiece">
<InputField
autoComplete="off"
label={<label>Amount / Piece</label>}
onChange={(e) =>
handleAmountPerPiecechange(e)
}
isOnChange={false}
value={selectedRowRecord?.AmountPerPiece}
/>
</Form.Item>
</>
)}
</div>
</Panel>
</Collapse>
</div>
{true && (
<div className="pricing-dtls">
<Collapse
activeKey={
activeAccordionKeys.includes('2') ? ['2'] : []
}
onChange={(keys) =>
setActiveAccordionKeys((prev) =>
keys.length > 0
? [...prev.filter((k) => k !== '2'), '2']
: prev.filter((k) => k !== '2')
)
}
>
<Panel header="Dates" key="2">
<div className="pricing-dtl-fields">
<Form.Item name="ManufDate">
<div className="dates-and-expiry">
<label>Entry Date</label>
<DatePicProd
canSelectPast={true}
onPressEnter={(e) =>
handleKeyPress(e, record, index)
}
onChange={handleManufactureDate}
valueData={selectedRowRecord?.ManufDate}
/>
</div>
</Form.Item>
{/* <Form.Item name="ExpDate">
<div className="dates-and-expiry">
<label>Expire Date</label>
<DatePicProd
canSelectPast={false}
onPressEnter={(e) => handleKeyPress(e, record, index)}
onChange={handleExpireDate}
valueData={selectedRowRecord?.ExpDate}
/>
</div>
</Form.Item> */}
</div>
</Panel>
</Collapse>
</div>
)}
{true && (
<div className="pricing-dtls">
<Collapse
activeKey={
activeAccordionKeys.includes('3') ? ['3'] : []
}
onChange={(keys) =>
setActiveAccordionKeys((prev) =>
keys.length > 0
? [...prev.filter((k) => k !== '3'), '3']
: prev.filter((k) => k !== '3')
)
}
>
<Panel header="Batch & Model Details" key="3">
<div className="pricing-dtl-fields">
<Form.Item name="BatchRef">
<InputField
autoComplete="off"
isOnChange={
selectedRowRecord?.BatchRef &&
selectedRowRecord?.BatchRef !== ''
? true
: false
}
value={selectedRowRecord?.BatchRef}
label={'Batch No.'}
onChange={handleBatchRefChange}
/>
</Form.Item>
<Form.Item name="ModelNumber">
<InputField
autoComplete="off"
isOnChange={
selectedRowRecord?.ModelNumber &&
selectedRowRecord?.ModelNumber !== ''
? true
: false
}
value={selectedRowRecord?.ModelNumber}
label={'Model No.'}
onChange={handleModelNoChange}
/>
</Form.Item>
{/* <div className="model-data-add" onClick={handleModelDataOpen}>
<IoAddCircleSharp size={18} />
<span>Add Model Data</span>
</div> */}
</div>
</Panel>
</Collapse>
</div>
)}
{additionalStockEntries.length > 0 && (
<div className="openingStock-entries-table">
<h4>Added Entries:</h4>
<Table
size="small"
dataSource={additionalStockEntries.map(
(item, index) => ({ ...item, key: index })
)}
pagination={false}
columns={[
{ title: 'Qty', dataIndex: 'Qty', key: 'Qty' },
{
title: 'One Piece Qty',
dataIndex: 'OnePieceQty',
key: 'OnePieceQty',
render: (value) => value || '-',
},
{ title: 'MRP', dataIndex: 'MRP', key: 'MRP' },
{
title: 'Sales Price',
dataIndex: 'SellPrice',
key: 'SellPrice',
},
{
title: 'Batch No.',
dataIndex: 'BatchRef',
key: 'BatchRef',
render: (value) => value || '-',
},
{
title: 'Model No.',
dataIndex: 'ModelNumber',
key: 'ModelNumber',
render: (value) => value || '-',
},
{
title: 'Entry Date',
dataIndex: 'ManufDate',
key: 'ManufDate',
render: (date) =>
date ? date.format('DD-MM-YYYY') : '-',
},
{
title: 'Action',
key: 'action',
render: (_, record, index) => (
<div className="openingStock-entries-table-actions">
<a>
<EditFilled
className="openingStock-edit-icon"
onClick={() => {
handleEditEntry(index);
setActiveAccordionKeys(['1']);
}}
/>
</a>
<a
onClick={(e) => {
e.stopPropagation();
}}
>
<DeleteFilled
className="openingStock-delete-icon"
onClick={() => handleDeleteEntry(index)}
/>
</a>
</div>
),
},
]}
/>
</div>
)}
<div className="submitButton">
<Buttons
buttonText="SUBMIT"
color="901D77"
icon={<ArrowRightOutlined />}
/>
</div>
</div>
</Form>
</>
}
handleCancel={handleAdditionalInfoClose}
buttonText="Submit"
/>
<DefaultModal
open={eliminateModal}
title="Ignore Products"
footer={false}
children={
<div>
<div className="openingStock-modal-section">
<label className="openingStock-modal-label">
Select Products to Ignore:
</label>
<Select
mode="multiple"
placeholder="Choose products to ignore"
className="openingStock-select-full-width"
value={[]}
onChange={(selectedIds) => {
const newEliminated = [
...eliminatedProducts,
...selectedIds,
];
setEliminatedProducts(newEliminated);
setFilteredProductStockData(
ProductStockData.filter(
(item) => !newEliminated.includes(item.ProdId)
)
);
}}
options={ProductStockData.filter(
(product) => !eliminatedProducts.includes(product.ProdId)
).map((product) => ({
value: product.ProdId,
label: `${product.ProdName} (${product.ProdVariantName})`,
}))}
showSearch
filterOption={(input, option) =>
option.label.toLowerCase().includes(input.toLowerCase())
}
maxTagCount={3}
maxTagTextLength={30}
/>
</div>
{eliminatedProducts.length > 0 && (
<div className="openingStock-ignored-products-section">
<h4>Ignored Products ({eliminatedProducts.length}):</h4>
<div className="openingStock-ignored-products-container">
{eliminatedProducts.map((prodId, index) => {
const product = ProductStockData.find(
(p) => p.ProdId === prodId
);
return (
<div
key={index}
className="openingStock-ignored-product-tag"
>
<span className="openingStock-ignored-product-name">
{product?.ProdName}
</span>
<span
onClick={() => {
const updatedEliminated =
eliminatedProducts.filter(
(id) => id !== prodId
);
setEliminatedProducts(updatedEliminated);
setFilteredProductStockData(
ProductStockData.filter(
(item) =>
!updatedEliminated.includes(item.ProdId)
)
);
}}
className="openingStock-ignored-product-remove"
>
×
</span>
</div>
);
})}
</div>
</div>
)}
<div className="openingStock-modal-footer">
<button
onClick={() => setEliminateModal(false)}
className="openingStock-close-btn"
>
Close
</button>
</div>
</div>
}
handleCancel={() => setEliminateModal(false)}
/>
</div>
</div>
</div>
);
};
export default openingStockForm;