2026-01-27 18:27:29 +05:30
|
|
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
import { useDispatch } from 'react-redux';
|
2026-03-09 10:43:17 +05:30
|
|
|
import { ImWarning } from 'react-icons/im';
|
|
|
|
|
import {
|
|
|
|
|
Form,
|
|
|
|
|
Table,
|
|
|
|
|
Input,
|
|
|
|
|
Select,
|
|
|
|
|
AutoComplete,
|
|
|
|
|
Button,
|
|
|
|
|
Tooltip,
|
|
|
|
|
} from 'antd';
|
|
|
|
|
import { BsUpcScan } from 'react-icons/bs';
|
|
|
|
|
import { FaLink } from 'react-icons/fa';
|
2026-01-27 18:27:29 +05:30
|
|
|
import {
|
|
|
|
|
DeleteFilled,
|
|
|
|
|
ArrowRightOutlined,
|
|
|
|
|
SearchOutlined,
|
|
|
|
|
} from '@ant-design/icons';
|
|
|
|
|
import { Messages } from '../../Components/Notifications/Messages.jsx';
|
|
|
|
|
import { InputField } from '../../Components/Forms/InputField.jsx';
|
|
|
|
|
import Buttons from '../../Components/Forms/Buttons.jsx';
|
2026-03-09 10:43:17 +05:30
|
|
|
import {
|
|
|
|
|
getSession,
|
|
|
|
|
pdfDiv,
|
|
|
|
|
printDiv,
|
|
|
|
|
validateSafeInput,
|
|
|
|
|
} from '../../Services/Others';
|
2026-01-27 18:27:29 +05:30
|
|
|
import FormHeader from '../PageComponents/FormHeader.jsx';
|
|
|
|
|
import { DropDowns } from '../../Components/Forms/DropDown.jsx';
|
|
|
|
|
import { CiBarcode } from 'react-icons/ci';
|
|
|
|
|
import {
|
|
|
|
|
AdminUserData,
|
|
|
|
|
Emailsend,
|
|
|
|
|
getProdQuoaVariantdata,
|
|
|
|
|
getPurProductData,
|
|
|
|
|
postPurcQuotation,
|
|
|
|
|
} from '../../Features/PurchaseQuotation/PurchaseQuotation.js';
|
|
|
|
|
import '../../Styles/PurchaseQuotation/PurchaseQuotation.scss';
|
|
|
|
|
import PurchaseQuotationPrint from './PurchaseQuotationPrint.jsx';
|
|
|
|
|
import { getPurchaseTaxTypeData } from '../../Features/StockMaster/StockMaster.js';
|
|
|
|
|
import {
|
|
|
|
|
changeBreadCrumb,
|
|
|
|
|
getEmpAccess,
|
|
|
|
|
} from '../../Features/AppPage/CenterPage.js';
|
|
|
|
|
import { useAuth } from '../../AuthContext.jsx';
|
2026-03-09 10:43:17 +05:30
|
|
|
import {
|
|
|
|
|
getAllCustomer,
|
|
|
|
|
getPreferenceData,
|
|
|
|
|
} from '../../Features/BookingScreen/BookingData/BookingData.js';
|
2026-01-27 18:27:29 +05:30
|
|
|
const subDirectory = import.meta.env.BASE_URL;
|
|
|
|
|
import TooltipWrapper from '../../Components/Tooltip/Tooltip';
|
|
|
|
|
import { FaEye, FaPrint } from 'react-icons/fa';
|
|
|
|
|
import { MdOutlineMail } from 'react-icons/md';
|
|
|
|
|
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
|
|
|
|
|
import FloatLabel from '../../Components/Forms/FloatLabel/index.jsx';
|
2026-03-09 10:43:17 +05:30
|
|
|
import { debounce } from 'lodash';
|
2026-01-27 18:27:29 +05:30
|
|
|
import { getPrintSelectionComponentData } from '../../Features/ThemeChange/ThemeChange.js';
|
|
|
|
|
import { PrintStyleFunction } from '../paymentpdfPage/PrintStyleFunction.js';
|
|
|
|
|
import { isMobile } from 'react-device-detect';
|
|
|
|
|
import { PurchaseQtMobilePrint } from './PurchaseQtMobilePrint.js';
|
2026-03-11 14:19:41 +05:30
|
|
|
import BarCodeScan from '../../Services/BarCodeScan.jsx';
|
2026-01-27 18:27:29 +05:30
|
|
|
const SalesQuotationForm = () => {
|
|
|
|
|
const { SadminuserAccess } = useAuth();
|
|
|
|
|
let SAAccessCommonMaster = SadminuserAccess?.find(
|
|
|
|
|
(e) => e?.MenuName === 'Sales Quotation'
|
|
|
|
|
);
|
|
|
|
|
const formRef = useRef(null);
|
|
|
|
|
|
|
|
|
|
const [form] = Form.useForm();
|
|
|
|
|
const [emailform] = Form.useForm();
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const CompId = getSession('CompId');
|
|
|
|
|
const BranchId = getSession('BranchId');
|
|
|
|
|
const AppId = getSession('AppId');
|
|
|
|
|
const UserId = getSession('UserId');
|
|
|
|
|
const UserType = getSession('UserType');
|
|
|
|
|
const [messageType, setMessageType] = useState(null);
|
|
|
|
|
const [messageData, setMessageData] = useState(null);
|
|
|
|
|
const [AdminUser, setAdminUser] = useState([]);
|
|
|
|
|
const [SelecAdminUser, setSelecAdminUser] = useState(null);
|
|
|
|
|
const [SelTaxType, setSelTaxType] = useState(null);
|
|
|
|
|
const [SelTaxTypeName, setSelTaxTypeName] = useState(null);
|
|
|
|
|
const [ProductData, setProductData] = useState([]);
|
|
|
|
|
const [AllCustomer, setAllCustomer] = useState(null);
|
|
|
|
|
|
|
|
|
|
const [SelProduct, setSelProduct] = useState(null);
|
|
|
|
|
const [selectedProductName, setSelectedProductName] = useState(null);
|
2026-03-09 10:43:17 +05:30
|
|
|
const [productSearchText, setProductSearchText] = useState('');
|
2026-01-27 18:27:29 +05:30
|
|
|
const [scanner, setScanner] = useState(false);
|
|
|
|
|
|
|
|
|
|
console.log(SelTaxTypeName, 'SelTaxTypeName');
|
|
|
|
|
const [selectedProductVariantData, setselectedProductVariantData] =
|
|
|
|
|
useState(null);
|
|
|
|
|
const [Variants, setVariants] = useState();
|
|
|
|
|
const [TableData, setTableData] = useState([]);
|
|
|
|
|
const [editingKey, setEditingKey] = useState('');
|
|
|
|
|
const [index, setindex] = useState();
|
|
|
|
|
const [Delete, setDelete] = useState(false);
|
|
|
|
|
const [allowDecimal, setAllowDecimal] = useState(false);
|
|
|
|
|
const [TotalBillAmount, setTotalBillAmount] = useState(null);
|
|
|
|
|
const [TotalCgst, setTotalCgst] = useState(null);
|
|
|
|
|
const [TotalSgst, setTotalSgst] = useState(null);
|
|
|
|
|
const [TotalIgst, setTotalIgst] = useState(null);
|
|
|
|
|
const [TotalAmount, setTotalAmount] = useState(null);
|
|
|
|
|
const [PurcTaxTypeData, setPurcTaxTypeData] = useState(null);
|
|
|
|
|
const [PrintData, setPrintData] = useState([]);
|
|
|
|
|
const isEditing = (record, index) => index === editingKey;
|
|
|
|
|
const [empData, setEmpData] = useState();
|
|
|
|
|
const [addnewAccess, setaddnewAccess] = useState(true);
|
|
|
|
|
const [isbarcode, setisbarcode] = useState(false);
|
|
|
|
|
const [isSubmitted, setIsSubmitted] = useState(false);
|
2026-03-09 10:43:17 +05:30
|
|
|
const [usrMailDataModel, setusrMailDataModel] = useState(false);
|
2026-01-27 18:27:29 +05:30
|
|
|
const [EnteredMailId, setEnteredMailId] = useState(null);
|
|
|
|
|
const [PrintTempData, setPrintTempData] = useState([]);
|
|
|
|
|
console.log(TableData, 'TableData');
|
2026-03-09 10:43:17 +05:30
|
|
|
const items = [
|
|
|
|
|
{
|
|
|
|
|
name: 'Home',
|
|
|
|
|
link: `${subDirectory}app-page/home`,
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
name: 'Sales Quotation',
|
|
|
|
|
link: `${subDirectory}setting/sales-quotation`,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
// const QuotationStylepdf = `<style>
|
|
|
|
|
// * {
|
|
|
|
|
// box-sizing: border-box;
|
|
|
|
|
// font-family: 'Poppins', sans-serif;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// body {
|
|
|
|
|
// margin: 0;
|
|
|
|
|
// padding: 0;
|
|
|
|
|
// font-size: 12px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Body {
|
|
|
|
|
// padding: 20px;
|
|
|
|
|
// width: 100%;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Content {
|
|
|
|
|
// border: 1px solid #aaa;
|
|
|
|
|
// padding: 16px;
|
|
|
|
|
// margin-bottom: 24px;
|
|
|
|
|
// page-break-after: always;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-print-Logo {
|
|
|
|
|
// width: 50px;
|
|
|
|
|
// height: 50px;
|
|
|
|
|
// margin: 10px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Header {
|
|
|
|
|
// display: flex;
|
|
|
|
|
// justify-content: space-between;
|
|
|
|
|
// align-items: flex-start;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Company, .Quo-Print-Qno {
|
|
|
|
|
// font-size: 12px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Cname {
|
|
|
|
|
// font-size: 16px;
|
|
|
|
|
// font-weight: bold;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-address {
|
|
|
|
|
// font-size: 12px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Horizondal-line {
|
|
|
|
|
// border-bottom: 1px solid #aaa;
|
|
|
|
|
// margin: 8px 0;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Customer {
|
|
|
|
|
// font-size: 12px;
|
|
|
|
|
// margin-top: 8px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Table {
|
|
|
|
|
// margin-top: 12px;
|
|
|
|
|
// overflow-x: auto;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-ProTable {
|
|
|
|
|
// width: 100%;
|
|
|
|
|
// border-collapse: collapse;
|
|
|
|
|
// font-size: 11px;
|
|
|
|
|
// table-layout: fixed;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-ProTable th,
|
|
|
|
|
// .Quo-Print-ProTable td {
|
|
|
|
|
// border: 1px solid #aaa;
|
|
|
|
|
// padding: 6px;
|
|
|
|
|
// word-wrap: break-word;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-headingData {
|
|
|
|
|
// background-color: #f2f2f2;
|
|
|
|
|
// font-weight: bold;
|
|
|
|
|
// text-align: center;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-TableDataSno,
|
|
|
|
|
// .Quo-Print-TableDataName,
|
|
|
|
|
// .Quo-Print-TableData,
|
|
|
|
|
// .Quo-Print-TableDataAmt {
|
|
|
|
|
// text-align: left;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-TableDataAmt {
|
|
|
|
|
// text-align: right;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Summary {
|
|
|
|
|
// margin-top: 16px;
|
|
|
|
|
// display: flex;
|
|
|
|
|
// justify-content: flex-end;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Total {
|
|
|
|
|
// width: 280px;
|
|
|
|
|
// border: 1px solid #000;
|
|
|
|
|
// padding: 8px;
|
|
|
|
|
// font-size: 12px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Total table {
|
|
|
|
|
// width: 100%;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-SummTableData {
|
|
|
|
|
// text-align: right;
|
|
|
|
|
// padding: 4px 6px;
|
|
|
|
|
// }
|
|
|
|
|
// </style>`;
|
|
|
|
|
// const QuotationStyle = `<style>
|
|
|
|
|
// .Quo-Print-Body{
|
|
|
|
|
// height: 100%;
|
|
|
|
|
// margin: 0vw 0vh;
|
|
|
|
|
// }
|
|
|
|
|
// .page {
|
|
|
|
|
|
|
|
|
|
// page-break-after: always;
|
|
|
|
|
// page-break-inside: avoid;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Content{
|
2026-03-09 10:43:17 +05:30
|
|
|
// display:flex;
|
2026-01-27 18:27:29 +05:30
|
|
|
// flex-direction:column;
|
|
|
|
|
// height:95vh;
|
|
|
|
|
// width:93vw;
|
|
|
|
|
// border:0.5px solid rgb(170, 164, 164);
|
2026-03-09 10:43:17 +05:30
|
|
|
// margin:2rem 1rem 1rem 1rem;
|
2026-01-27 18:27:29 +05:30
|
|
|
// gap:1.5rem;
|
|
|
|
|
// page-break-after: always;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-print-Logo{
|
|
|
|
|
// width: 50px ;
|
|
|
|
|
// height: 50px;
|
|
|
|
|
// margin:10px 0 0 10px;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-ComCus{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:column;
|
|
|
|
|
// height:18vh;
|
|
|
|
|
// justify-content:space-between;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Tabsum{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:column;
|
2026-03-09 10:43:17 +05:30
|
|
|
// justify-content:space-between;
|
2026-01-27 18:27:29 +05:30
|
|
|
// gap:1rem;
|
|
|
|
|
// height:60vh;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Header{
|
|
|
|
|
// display: flex;
|
|
|
|
|
// flex-direction: row;
|
|
|
|
|
// justify-content: space-between;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-Company{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:column;
|
|
|
|
|
// padding:10px;
|
|
|
|
|
// gap:0.1rem;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Cname{
|
|
|
|
|
// font-size:25px;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-address{
|
|
|
|
|
// font-size:22px;
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-wrap:wrap;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Qno{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:column;
|
|
|
|
|
// padding:10px;
|
|
|
|
|
// gap:0.1rem;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Customer{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:Column;
|
|
|
|
|
// padding-left:10px;
|
|
|
|
|
// gap:0.1rem;
|
|
|
|
|
// }
|
|
|
|
|
// .Horizondal-line{
|
|
|
|
|
// border-bottom: 0.5px solid rgb(170, 164, 164);
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Table{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-ProTable{
|
|
|
|
|
// width:100%;
|
|
|
|
|
// border-collapse: collapse;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-DataRow{
|
|
|
|
|
// line-height:2rem;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-tableheader{
|
|
|
|
|
// border-top:0.5px solid rgb(170, 164, 164);
|
|
|
|
|
// border-bottom: 0.5px solid rgb(170, 164, 164);
|
|
|
|
|
// line-height:4rem;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-TableData{
|
|
|
|
|
// text-align:right;
|
|
|
|
|
// padding:1px;
|
|
|
|
|
// font-size:22px;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-TableDataSno{
|
|
|
|
|
// text-align:center;
|
|
|
|
|
// padding:1px;
|
|
|
|
|
// font-size:20px;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// .Quo-Print-TableDataName{
|
|
|
|
|
// text-align:left;
|
|
|
|
|
// padding-left:1px;
|
|
|
|
|
// font-size:20px;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-headingData{
|
|
|
|
|
// text-align:center;
|
|
|
|
|
// padding:1px;
|
|
|
|
|
// font-size:22px;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-TableDataAmt{
|
|
|
|
|
// text-align:right;
|
|
|
|
|
// padding-right:5px;
|
|
|
|
|
// font-size:20px;
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Summary{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// flex-direction:row;
|
|
|
|
|
// justify-content: flex-end;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-SummTableData{
|
|
|
|
|
// text-align:right;
|
|
|
|
|
// padding:1px;
|
|
|
|
|
// font-size:22px;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
// .Quo-Print-Total{
|
|
|
|
|
// display:flex;
|
|
|
|
|
// justify-content:flex-end;
|
|
|
|
|
// border:0.5px solid black;
|
|
|
|
|
// width:300px;
|
|
|
|
|
// margin-right: 10px;
|
|
|
|
|
// font-size:20px;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// </style>`;
|
|
|
|
|
|
|
|
|
|
const PurchaseOrderStyle = `<style>
|
|
|
|
|
@media print {
|
|
|
|
|
@page {
|
|
|
|
|
size: A4;
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-Body {
|
|
|
|
|
width: 195mm;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
// padding: 10mm;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-Body {
|
|
|
|
|
margin: 0;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
background: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-Content {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-width: 200mm;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
border: 1px solid rgb(170, 164, 164);
|
|
|
|
|
padding: 10px;
|
|
|
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.Quo-print-Logo{
|
|
|
|
|
width: 50px ;
|
|
|
|
|
height: 50px;
|
|
|
|
|
margin:5px 0 0 5;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-ComCus{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:column;
|
|
|
|
|
height:18vh;
|
|
|
|
|
justify-content:space-between;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Tabsum{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:column;
|
|
|
|
|
justify-content:space-between;
|
|
|
|
|
gap:1rem;
|
|
|
|
|
height:60vh;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Header{
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-Company{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:column;
|
|
|
|
|
padding:10px;
|
|
|
|
|
gap:0.1rem;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Cname{
|
|
|
|
|
font-size:25px;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-address{
|
|
|
|
|
font-size:22px;
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-wrap:wrap;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Qno{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:column;
|
|
|
|
|
padding:10px;
|
|
|
|
|
gap:0.1rem;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Customer{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:Column;
|
|
|
|
|
padding-left:10px;
|
|
|
|
|
gap:0.1rem;
|
|
|
|
|
}
|
|
|
|
|
.Horizondal-line{
|
|
|
|
|
border-bottom: 0.5px solid rgb(170, 164, 164);
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Table{
|
|
|
|
|
display:flex;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-ProTable {
|
|
|
|
|
width: 100%;
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
margin-top: 15px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-DataRow {
|
|
|
|
|
// line-height: 2.5rem;
|
|
|
|
|
border-bottom: 1px solid #eee;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-tableheader {
|
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
border-top: 1px solid rgb(170, 164, 164);
|
|
|
|
|
border-bottom: 1px solid rgb(170, 164, 164);
|
|
|
|
|
line-height: 3rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-TableData {
|
|
|
|
|
text-align: right;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-TableDataSno {
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
width: 60px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-TableDataName {
|
|
|
|
|
text-align: left;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.Quo-Print-headingData {
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 8px;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-TableDataAmt{
|
|
|
|
|
text-align:right;
|
|
|
|
|
padding-right:5px;
|
|
|
|
|
font-size:25px;
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Summary{
|
|
|
|
|
display:flex;
|
|
|
|
|
flex-direction:row;
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-SummTableData{
|
|
|
|
|
text-align:right;
|
|
|
|
|
padding:1px;
|
|
|
|
|
font-size:22px;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.Quo-Print-Total{
|
|
|
|
|
display:flex;
|
|
|
|
|
justify-content:flex-end;
|
|
|
|
|
border:0.5px solid black;
|
|
|
|
|
width:300px;
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
font-size:20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</style>`;
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
dispatch(changeBreadCrumb({ items: items }));
|
|
|
|
|
getAdminUserdata();
|
|
|
|
|
getProduct();
|
|
|
|
|
getPurchaseTaxType();
|
|
|
|
|
fetchdata();
|
|
|
|
|
getPreference();
|
|
|
|
|
// if (UserType === "Employee") {
|
|
|
|
|
// fetchApi()
|
|
|
|
|
// }
|
|
|
|
|
}, []);
|
|
|
|
|
// console.log(TableData, "TableDataTableData")
|
|
|
|
|
const debouncedScannerSearch = useCallback(
|
|
|
|
|
debounce((value) => {
|
|
|
|
|
const qr = value?.trim();
|
|
|
|
|
|
|
|
|
|
const matchedProduct = ProductData.find(
|
|
|
|
|
(p) => p.QRCode?.toLowerCase() === qr?.toLowerCase()
|
|
|
|
|
);
|
|
|
|
|
if (matchedProduct) {
|
|
|
|
|
let productName = {};
|
2026-03-09 10:43:17 +05:30
|
|
|
productName.label = `${matchedProduct?.ProdName} (${matchedProduct.Size} ${matchedProduct.UomName})${matchedProduct?.BrandName ? ` - ${matchedProduct?.BrandName}` : ''}`;
|
2026-01-27 18:27:29 +05:30
|
|
|
ProductDropDownChange(matchedProduct.ProdId, productName);
|
|
|
|
|
if (matchedProduct?.ProdVariantPriceDetails?.length < 2) {
|
2026-03-09 10:43:17 +05:30
|
|
|
setSelectedProductName('');
|
|
|
|
|
setSelProduct(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
} else {
|
2026-03-09 10:43:17 +05:30
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('The Scanned Product not Available in Product List');
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
}, 300),
|
|
|
|
|
[ProductData]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const getPreference = async () => {
|
|
|
|
|
const data = { AppId: AppId, CompId: CompId, BranchId: BranchId };
|
2026-03-09 10:43:17 +05:30
|
|
|
const { data: res } = await dispatch(getPreferenceData(data)).unwrap();
|
|
|
|
|
const decimalSetting = res?.data?.[0]?.SettingDtlDetails?.find(
|
|
|
|
|
(setting) =>
|
|
|
|
|
setting?.SettingIdName?.toLowerCase() === 'decimal' &&
|
|
|
|
|
setting?.SettingValue === 'Y'
|
|
|
|
|
);
|
2026-01-27 18:27:29 +05:30
|
|
|
if (decimalSetting) {
|
2026-03-09 10:43:17 +05:30
|
|
|
setAllowDecimal(true);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
2026-03-09 10:43:17 +05:30
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
const changebarcode = useCallback(() => {
|
|
|
|
|
setisbarcode((prev) => !prev);
|
|
|
|
|
}, []);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (UserType === 'Employee') {
|
|
|
|
|
fetchApi();
|
|
|
|
|
}
|
|
|
|
|
}, [UserType]);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
let hasAccess = false;
|
|
|
|
|
|
|
|
|
|
if (UserType === 'Admin' || UserType === 'Super Admin') {
|
|
|
|
|
hasAccess = true;
|
|
|
|
|
} else if (UserType === 'Employee') {
|
|
|
|
|
hasAccess = empData?.AddAccess === 'Y';
|
|
|
|
|
} else if (UserType === 'Super Admin User') {
|
|
|
|
|
hasAccess = SAAccessCommonMaster?.AddAccess === 'Y';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setaddnewAccess(!hasAccess);
|
|
|
|
|
}, [empData, SAAccessCommonMaster, UserType]);
|
|
|
|
|
|
|
|
|
|
const fetchApi = async () => {
|
|
|
|
|
let data = {
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
EmpId: UserId,
|
|
|
|
|
};
|
|
|
|
|
let response = await dispatch(getEmpAccess(data)).unwrap();
|
|
|
|
|
let datas = response?.data?.data?.[0]?.EmpAccessDetails?.filter(
|
2026-01-28 19:31:14 +05:30
|
|
|
(item) => item.ConfigName === 'Sales Quotation'
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
setEmpData(datas?.[0]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// Print();
|
|
|
|
|
// }, [PrintData]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
let total = TableData?.reduce((accumulator, currentValue) => {
|
|
|
|
|
return accumulator + currentValue.NetAmt;
|
|
|
|
|
}, 0);
|
|
|
|
|
setTotalAmount(total);
|
|
|
|
|
let cgst = TableData?.filter(
|
|
|
|
|
(item) => item.TaxName?.toLowerCase() === 'cgst,sgst'
|
|
|
|
|
);
|
|
|
|
|
let totalgst = cgst?.reduce((accumulator, currentValue) => {
|
|
|
|
|
return accumulator + currentValue.TaxAmt;
|
|
|
|
|
}, 0);
|
|
|
|
|
setTotalCgst(totalgst / 2);
|
|
|
|
|
setTotalSgst(totalgst / 2);
|
|
|
|
|
let igst = TableData?.filter(
|
|
|
|
|
(item) => item.TaxName?.toLowerCase() === 'igst'
|
|
|
|
|
);
|
|
|
|
|
let totaligst = igst?.reduce((accumulator, currentValue) => {
|
|
|
|
|
return accumulator + currentValue.TaxAmt;
|
|
|
|
|
}, 0);
|
|
|
|
|
setTotalIgst(totaligst);
|
|
|
|
|
let billtotal = TableData?.reduce((accumulator, currentValue) => {
|
|
|
|
|
return accumulator + currentValue.BillAmount;
|
|
|
|
|
}, 0);
|
|
|
|
|
setTotalBillAmount(billtotal);
|
|
|
|
|
}, [TableData]);
|
2026-03-09 10:43:17 +05:30
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
const getProduct = async () => {
|
|
|
|
|
let Product = await dispatch(
|
|
|
|
|
getPurProductData({
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
ActiveStatus: 'A',
|
|
|
|
|
})
|
|
|
|
|
).unwrap();
|
|
|
|
|
if (Product?.data?.statusCode === 1) {
|
|
|
|
|
let Productonlydata = Product?.data?.data?.filter(
|
2026-03-09 10:43:17 +05:30
|
|
|
(item) =>
|
|
|
|
|
item?.ProdTypeName === 'Product' &&
|
|
|
|
|
(item?.StockAvailable === 'Y' ? item?.BalanceQty > 0 : true)
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setProductData(Productonlydata);
|
|
|
|
|
} else {
|
|
|
|
|
setProductData([]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const getAdminUserdata = async () => {
|
|
|
|
|
let adminuser = await dispatch(AdminUserData()).unwrap();
|
|
|
|
|
if (adminuser?.data?.statusCode === 1) {
|
|
|
|
|
setAdminUser(adminuser?.data?.data);
|
|
|
|
|
console.log(adminuser?.data?.data, 'adminuser');
|
|
|
|
|
} else {
|
|
|
|
|
setAdminUser([]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const fetchdata = async () => {
|
|
|
|
|
let res = await dispatch(
|
|
|
|
|
getAllCustomer({ CompId: CompId, AppId: AppId, branchId: BranchId })
|
|
|
|
|
).unwrap();
|
|
|
|
|
await setAllCustomer(res?.data?.data);
|
|
|
|
|
|
|
|
|
|
const Data = { AppId, CompId, BranchId };
|
|
|
|
|
|
2026-03-09 10:43:17 +05:30
|
|
|
const printtemp = await dispatch(
|
|
|
|
|
getPrintSelectionComponentData(Data)
|
|
|
|
|
).unwrap();
|
2026-01-27 18:27:29 +05:30
|
|
|
const printTypeName = printtemp?.data?.data
|
2026-03-09 10:43:17 +05:30
|
|
|
?.flatMap((template) => template.ComponentDetails || [])
|
2026-01-27 18:27:29 +05:30
|
|
|
?.find(
|
2026-03-09 10:43:17 +05:30
|
|
|
(comp) =>
|
|
|
|
|
comp.SetasDefault === 'Y' && comp.PrintTypeName === 'Sales Quotation'
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
setPrintTempData(printTypeName);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getPurchaseTaxType = async () => {
|
|
|
|
|
let res = await dispatch(getPurchaseTaxTypeData()).unwrap();
|
|
|
|
|
if (res?.data?.statusCode === 1) {
|
|
|
|
|
setPurcTaxTypeData(res?.data?.data);
|
|
|
|
|
let tempniltax = res?.data?.data?.find(
|
|
|
|
|
(item) => item?.ConfigName?.toLowerCase() === 'withtax'
|
|
|
|
|
);
|
|
|
|
|
setSelTaxType(tempniltax?.ConfigId);
|
|
|
|
|
setSelTaxTypeName(tempniltax?.ConfigName);
|
|
|
|
|
formRef.current?.setFieldsValue({ TaxType: tempniltax?.ConfigId });
|
|
|
|
|
} else {
|
|
|
|
|
setPurcTaxTypeData(null);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// const Print = async () => {
|
|
|
|
|
// if (PrintData?.length > 0) {
|
|
|
|
|
// await printDiv(`Pur-Quot-Print`, QuotationStyle);
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
const handleAdminUserDropDownChange = (UserId) => {
|
|
|
|
|
setSelecAdminUser(UserId);
|
|
|
|
|
formRef.current?.setFieldsValue({ CustId: UserId });
|
|
|
|
|
setIsSubmitted();
|
|
|
|
|
};
|
|
|
|
|
const handleQuoTaxTypeChange = (taxtype) => {
|
|
|
|
|
setSelTaxType(taxtype);
|
|
|
|
|
formRef.current?.setFieldsValue({ TaxType: taxtype });
|
|
|
|
|
let taxname = PurcTaxTypeData?.find((item) => item.ConfigId === taxtype);
|
|
|
|
|
setSelTaxTypeName(taxname?.ConfigName);
|
|
|
|
|
let taxchange = TableData?.map((item) => {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
TaxAmt:
|
|
|
|
|
taxname?.ConfigName?.toLowerCase() === 'withtax'
|
|
|
|
|
? (item?.NetAmt * parseInt(item?.TaxPercentage)) /
|
2026-03-09 10:43:17 +05:30
|
|
|
(100 + parseInt(item?.TaxPercentage))?.toFixed(2)
|
2026-01-27 18:27:29 +05:30
|
|
|
: 0,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setTableData(taxchange);
|
|
|
|
|
};
|
|
|
|
|
const handleScanSearch = () => {
|
|
|
|
|
if (scanner === false) {
|
2026-03-09 10:43:17 +05:30
|
|
|
setMessageType('success');
|
|
|
|
|
setMessageData('Search by QrCode/BarCode Enabled');
|
2026-01-27 18:27:29 +05:30
|
|
|
} else {
|
2026-03-09 10:43:17 +05:30
|
|
|
setMessageType('success');
|
|
|
|
|
setMessageData('Search by QrCode/BarCode Disabled');
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
2026-03-09 10:43:17 +05:30
|
|
|
setScanner((prev) => !prev);
|
2026-01-27 18:27:29 +05:30
|
|
|
setSelectedProductName(null);
|
|
|
|
|
setselectedProductVariantData(null);
|
2026-03-09 10:43:17 +05:30
|
|
|
setVariants(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
formRef?.current?.setFieldsValue({
|
|
|
|
|
ProdId: null,
|
2026-03-09 10:43:17 +05:30
|
|
|
VarProdId: null,
|
2026-01-27 18:27:29 +05:30
|
|
|
});
|
2026-03-09 10:43:17 +05:30
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
const handleProductSearch = (value) => {
|
|
|
|
|
if (scanner) {
|
|
|
|
|
debouncedScannerSearch(value);
|
|
|
|
|
}
|
2026-03-09 10:43:17 +05:30
|
|
|
setProductSearchText(value);
|
2026-01-27 18:27:29 +05:30
|
|
|
setSelectedProductName(value);
|
|
|
|
|
setselectedProductVariantData([]);
|
2026-03-09 10:43:17 +05:30
|
|
|
setVariants([]);
|
2026-01-27 18:27:29 +05:30
|
|
|
};
|
|
|
|
|
const ProductDropDownChange = async (ProdId, option) => {
|
2026-03-09 10:43:17 +05:30
|
|
|
setProductSearchText('');
|
|
|
|
|
setSelectedProductName(option?.label ? option?.label : '');
|
2026-01-27 18:27:29 +05:30
|
|
|
formRef?.current?.resetFields(['VarProdId']);
|
|
|
|
|
|
|
|
|
|
console.log(ProductData, 'ProdIdProdId');
|
|
|
|
|
setSelProduct(ProdId);
|
|
|
|
|
|
|
|
|
|
formRef.current?.setFieldsValue({ ProdId: ProdId });
|
|
|
|
|
|
|
|
|
|
let x = ProductData?.find((e) => e.ProdId === ProdId)?.ProdName;
|
|
|
|
|
|
|
|
|
|
let variantValues1 = await dispatch(
|
|
|
|
|
getProdQuoaVariantdata({
|
|
|
|
|
CompId: CompId,
|
|
|
|
|
AppId: AppId,
|
|
|
|
|
BranchId: BranchId,
|
|
|
|
|
prodName: x,
|
|
|
|
|
})
|
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
|
|
let variants1 = variantValues1?.data?.data;
|
|
|
|
|
|
|
|
|
|
// let cc = variants1?.[0]?.ProductDetail;
|
|
|
|
|
let cc = variants1?.filter((item) => item?.ProdName == x)?.[0]
|
|
|
|
|
?.ProductDetail;
|
|
|
|
|
|
|
|
|
|
setVariants(
|
|
|
|
|
cc?.[0]?.ProdVariantDetails?.map((detail) => ({
|
|
|
|
|
...detail,
|
|
|
|
|
ProdIdProdName: `${detail.ProdVariantName} ${detail.ProdId}`,
|
|
|
|
|
}))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (cc?.[0]?.ProdVariantDetails?.length < 2) {
|
|
|
|
|
if (TableData?.some((e) => e.ProdId == ProdId)) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
|
|
|
|
|
setMessageData('Already Product Exists');
|
|
|
|
|
} else {
|
|
|
|
|
let ProductData1 = ProductData?.find((e) => e.ProdId === ProdId);
|
|
|
|
|
console.log(ProductData1, 'ProductData1ProductData1');
|
|
|
|
|
let ProduData2 = {
|
|
|
|
|
ProdId: ProductData1?.ProdId,
|
|
|
|
|
ProdName: ProductData1?.ProdName,
|
|
|
|
|
UomName: ProductData1?.UomName,
|
|
|
|
|
Price: ProductData1?.SellPrice,
|
|
|
|
|
TaxName: ProductData1?.TaxName,
|
|
|
|
|
HSNCode: ProductData1?.HSNCode,
|
|
|
|
|
Size: ProductData1?.Size,
|
|
|
|
|
// OnePcsAvailable:ProductData1?.OnePcsAvailable,
|
|
|
|
|
// NumberofPieceinside: ProductData1?.NoOfPcs,
|
|
|
|
|
// AmountPerPiece: ProductData1?.OnePcsPrice,
|
|
|
|
|
TaxId: ProductData1?.TaxId,
|
|
|
|
|
TaxPercentage: ProductData1?.TaxPercentage,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let tempPurData = {
|
|
|
|
|
...ProduData2,
|
|
|
|
|
Qty: 0,
|
|
|
|
|
// 'InwardPrice': 0,
|
|
|
|
|
PurcDisc: 0,
|
|
|
|
|
NetAmt: 0,
|
|
|
|
|
BillAmount: 0,
|
|
|
|
|
DiscType: 'P',
|
|
|
|
|
// 'WhSalePrice': 0,
|
|
|
|
|
// 'ReceivedQty': 0,
|
|
|
|
|
// 'AcceptedQty': 0,
|
|
|
|
|
// 'RejectedQty': 0,
|
|
|
|
|
// "OfferPrice": 0,
|
|
|
|
|
// "SpecialPrice": 0,
|
|
|
|
|
ProdVariantName: 'Variant 1',
|
|
|
|
|
// "FreeItem": 0,
|
|
|
|
|
// 'TaxPerc': PurcselectedTax ? PurcselectedTax : 0,
|
|
|
|
|
TaxAmt: 0,
|
|
|
|
|
// 'TaxType': SelectedPurcTaxType ? SelectedPurcTaxType : 0,
|
|
|
|
|
};
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
[`BalanceQty${TableData.length + 1}`]: undefined,
|
|
|
|
|
// [`ReceivedQty${index}`]: undefined,
|
|
|
|
|
// [`AcceptedQty${index}`]: undefined,
|
|
|
|
|
// [`RejectedQty${index}`]: undefined,
|
|
|
|
|
[`Amount${TableData.length + 1}`]: ProductData1?.SellPrice,
|
|
|
|
|
// [`FreeQty${index}`]: undefined,
|
|
|
|
|
// [`InwardPrice${index}`]: undefined,
|
|
|
|
|
// [`MRP${index}`]: undefined,
|
|
|
|
|
[`PurcDisc${TableData.length + 1}`]: 0,
|
|
|
|
|
[`SellPrice${TableData.length + 1}`]: ProductData1?.SellPrice,
|
|
|
|
|
// [`WhSalePrice${index}`]: undefined,
|
|
|
|
|
// [`offerSalePrice${index}`]: undefined,
|
|
|
|
|
// [`splSalePrice${index}`]: undefined
|
|
|
|
|
});
|
|
|
|
|
setTableData([...TableData, tempPurData]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const ProductVariantDropDownChange = (value) => {
|
|
|
|
|
const ProdName2 = Variants?.filter(
|
|
|
|
|
(item) => item.ProdIdProdName === value
|
|
|
|
|
)?.[0]?.ProdVariantName;
|
|
|
|
|
|
|
|
|
|
const ProdName1 = TableData?.some(
|
2026-03-09 10:43:17 +05:30
|
|
|
(e) => e.ProdId == SelProduct && e.ProdVariantName === ProdName2
|
2026-01-27 18:27:29 +05:30
|
|
|
);
|
|
|
|
|
if (ProdName1) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Already variant Exists');
|
|
|
|
|
} else {
|
|
|
|
|
const ProdName = Variants?.filter(
|
|
|
|
|
(item) => item.ProdIdProdName === value
|
|
|
|
|
)?.[0]?.ProdVariantName;
|
|
|
|
|
const OnePcsAvailable = Variants?.filter(
|
|
|
|
|
(item) => item.ProdIdProdName === value
|
|
|
|
|
)?.[0]?.OnePcsAvailable;
|
|
|
|
|
formRef?.current?.setFieldsValue({ VarProdId: value });
|
|
|
|
|
setselectedProductVariantData(ProdName);
|
|
|
|
|
|
|
|
|
|
// let x = VariantData1?.filter((e) => e.InwardDtlId == value);
|
|
|
|
|
// let u = ProductData?.find((e) => e.ProdId == selectedProductData);
|
|
|
|
|
// console.log(first)
|
2026-03-09 10:43:17 +05:30
|
|
|
let ProductData1 = ProductData?.find((e) => e.ProdId == SelProduct);
|
2026-01-27 18:27:29 +05:30
|
|
|
console.log(ProductData1, 'ProductData1ProductData1');
|
|
|
|
|
let mrp;
|
|
|
|
|
let sellprice;
|
|
|
|
|
if (ProdName == 'Variant 1') {
|
|
|
|
|
mrp = ProductData1?.MRP;
|
|
|
|
|
sellprice = ProductData1?.SellPrice;
|
|
|
|
|
} else {
|
|
|
|
|
mrp = ProductData1?.ProdVariantPriceDetails?.find(
|
|
|
|
|
(item) => item.ProdVariantName == ProdName
|
|
|
|
|
)?.MRP;
|
|
|
|
|
sellprice = ProductData1?.ProdVariantPriceDetails?.find(
|
|
|
|
|
(item) => item.ProdVariantName == ProdName
|
|
|
|
|
)?.SellPrice;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let ProduData2 = {
|
|
|
|
|
ProdId: ProductData1?.ProdId,
|
|
|
|
|
// MRP: mrp,
|
|
|
|
|
ProdName: ProductData1?.ProdName,
|
|
|
|
|
UomName: ProductData1?.UomName,
|
|
|
|
|
Price: sellprice,
|
|
|
|
|
TaxName: ProductData1?.TaxName,
|
|
|
|
|
HSNCode: ProductData1?.HSNCode,
|
|
|
|
|
// StockAvailable: ProductData1?.StockAvailable,
|
|
|
|
|
// OnePcsAvailable:ProductData1?.OnePcsAvailable,
|
|
|
|
|
// NumberofPieceinside: ProductData1?.NoOfPcs,
|
|
|
|
|
// AmountPerPiece: ProductData1?.OnePcsPrice,
|
|
|
|
|
Size: ProductData1?.Size,
|
|
|
|
|
TaxId: ProductData1?.TaxId,
|
|
|
|
|
TaxPercentage: ProductData1?.TaxPercentage,
|
|
|
|
|
};
|
|
|
|
|
// ProduData2["StockAvailable"]="Y"
|
|
|
|
|
|
|
|
|
|
let tempPurData = {
|
|
|
|
|
...ProduData2,
|
|
|
|
|
Qty: 0,
|
|
|
|
|
PurcDisc: 0,
|
|
|
|
|
NetAmt: 0,
|
|
|
|
|
BillAmount: 0,
|
|
|
|
|
DiscType: 'P',
|
|
|
|
|
ProdVariantName: ProdName,
|
|
|
|
|
TaxAmt: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setTableData([...TableData, tempPurData]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const onComplete = useCallback(() => {
|
|
|
|
|
setMessageData(null);
|
|
|
|
|
setMessageType(null);
|
|
|
|
|
}, []);
|
|
|
|
|
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 = [...TableData];
|
|
|
|
|
// const index = newData.findIndex((item) => recordKey === item.InwardDtlId);
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
const item = newData[index];
|
|
|
|
|
newData.splice(index, 1, { ...item, ...modifiedObject });
|
|
|
|
|
setTableData(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 getColumns = (data, seltax) => {
|
|
|
|
|
const hasDiscount = data?.some((record) => record.PurcDisc > 0);
|
|
|
|
|
|
|
|
|
|
const baseColumns = [
|
|
|
|
|
{
|
|
|
|
|
title: 'Sl.No',
|
|
|
|
|
align: 'center',
|
|
|
|
|
key: 'sno',
|
|
|
|
|
render: (text, object, index) => (
|
|
|
|
|
<a style={{ color: 'black' }}>{index + 1}</a>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Product Name',
|
|
|
|
|
dataIndex: 'ProdName',
|
|
|
|
|
key: 'ProdName',
|
2026-03-09 10:43:17 +05:30
|
|
|
width: '230px',
|
2026-01-27 18:27:29 +05:30
|
|
|
align: 'right',
|
|
|
|
|
render: (text, record, index) => (
|
|
|
|
|
<a style={{ color: 'black' }}>
|
|
|
|
|
{record?.ProdName +
|
|
|
|
|
'(' +
|
|
|
|
|
record?.Size +
|
|
|
|
|
'-' +
|
|
|
|
|
record?.UomName +
|
|
|
|
|
')' +
|
|
|
|
|
'(' +
|
|
|
|
|
record?.ProdVariantName +
|
|
|
|
|
')'}
|
|
|
|
|
</a>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Qty',
|
|
|
|
|
dataIndex: 'Qty',
|
|
|
|
|
key: 'Qty',
|
|
|
|
|
editable: true,
|
|
|
|
|
// with: '100px',
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
return isEditing(record, index) ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={'Qty' + index}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
pattern: /^[1-9]\d*(\.\d+)?$/,
|
|
|
|
|
message: 'Please enter quantity',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
onPressEnter={(e) => handleKeyPress(e, record, index)}
|
|
|
|
|
onBlur={(e) => handleQtyChange(e, record)}
|
|
|
|
|
onChange={(e) => handleQtyChange(e, record, index)}
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
|
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, ''); // Remove invalid characters
|
|
|
|
|
const parts = cleanedValue.split('.');
|
|
|
|
|
|
|
|
|
|
if (cleanedValue.startsWith('.')) {
|
|
|
|
|
cleanedValue = '0' + cleanedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
|
|
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
text
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
// {
|
|
|
|
|
// title: 'Hsn Code',
|
|
|
|
|
// dataIndex: 'HSNCode',
|
|
|
|
|
// key: 'HSNCode',
|
|
|
|
|
// },
|
|
|
|
|
{
|
|
|
|
|
title: 'Uom',
|
|
|
|
|
dataIndex: 'UomName',
|
|
|
|
|
key: 'UOMName',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Rate',
|
|
|
|
|
dataIndex: 'Price',
|
|
|
|
|
key: 'Price',
|
|
|
|
|
editable: true,
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
return isEditing(record, index) ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={'Price' + index}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
pattern: /^[1-9]\d*(\.\d+)?$/,
|
|
|
|
|
message: 'Please enter Sales Rate',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
onPressEnter={(e) => handleKeyPress(e, record, index)}
|
|
|
|
|
onChange={(e) => handlePurrateChange(e, record, index)}
|
|
|
|
|
onBlur={(e) => handlePurrateChange(e, record, index)}
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
|
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, ''); // Remove invalid characters
|
|
|
|
|
const parts = cleanedValue.split('.');
|
|
|
|
|
|
|
|
|
|
if (cleanedValue.startsWith('.')) {
|
|
|
|
|
cleanedValue = '0' + cleanedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
|
|
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
text
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: 'Discount',
|
|
|
|
|
dataIndex: 'PurcDisc',
|
|
|
|
|
key: 'PurcDisc',
|
|
|
|
|
editable: true,
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
return isEditing(record, index) ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={'PurcDisc' + index}
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
const PurcDiscType = form.getFieldValue([
|
|
|
|
|
`DiscType${index}`,
|
|
|
|
|
]);
|
|
|
|
|
console.log(PurcDiscType, 'PurcDiscType');
|
|
|
|
|
if (value === undefined || value === '')
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
|
|
|
|
if (PurcDiscType === 'P') {
|
|
|
|
|
console.log(PurcDiscType, 'PurcDiscType');
|
|
|
|
|
if (
|
|
|
|
|
!/^(100(\.0{1,2})?|[0-9]{1,2}(\.\d{1,2})?)$/.test(value)
|
|
|
|
|
) {
|
|
|
|
|
return Promise.reject(
|
|
|
|
|
'Please enter a valid discount (0-100%)'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Input
|
|
|
|
|
onPressEnter={(e) => handleKeyPress(e, record, index)}
|
|
|
|
|
onChange={(e) => handlePurdiscChange(e, record, index)}
|
|
|
|
|
onBlur={(e) => handlePurdiscChange(e, record)}
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
inputMode="decimal"
|
|
|
|
|
onInput={(e) => {
|
|
|
|
|
let cleanedValue = e.target.value.replace(/[^0-9.]/g, ''); // Remove invalid characters
|
|
|
|
|
const parts = cleanedValue.split('.');
|
|
|
|
|
|
|
|
|
|
if (cleanedValue.startsWith('.')) {
|
|
|
|
|
cleanedValue = '0' + cleanedValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.target.value =
|
|
|
|
|
parts.length > 2
|
|
|
|
|
? `${parts[0]}.${parts.slice(1).join('')}`
|
|
|
|
|
: cleanedValue;
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
text
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
title: 'Amount',
|
|
|
|
|
dataIndex: 'NetAmt',
|
|
|
|
|
key: 'NetAmt',
|
|
|
|
|
editable: true,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Conditionally add the Discount Type column if there's a discount
|
|
|
|
|
if (hasDiscount) {
|
|
|
|
|
baseColumns.splice(6, 0, {
|
|
|
|
|
title: 'Discount Type',
|
|
|
|
|
dataIndex: 'DiscType',
|
|
|
|
|
key: 'DiscType',
|
|
|
|
|
editable: true,
|
|
|
|
|
render: (text, record, index) => {
|
|
|
|
|
const purchaseDiscount = record.PurcDisc || 0; // Ensure a valid number
|
|
|
|
|
return isEditing(record, index) && purchaseDiscount > 0 ? (
|
|
|
|
|
<Form.Item
|
|
|
|
|
name={'DiscType' + index}
|
|
|
|
|
initialValue={record.DiscountType}
|
|
|
|
|
rules={[
|
|
|
|
|
{ required: true, message: 'Please select a Discount Type' },
|
|
|
|
|
{
|
|
|
|
|
validator: async (_, value) => {
|
|
|
|
|
const PurcDisc = form.getFieldValue([`PurcDisc${index}`]);
|
|
|
|
|
const PurcDiscType = form.getFieldValue([
|
|
|
|
|
`DiscType${index}`,
|
|
|
|
|
]);
|
|
|
|
|
if (value === undefined || value === '')
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
|
|
|
|
|
if (PurcDisc > 99 && PurcDiscType == 'P') {
|
|
|
|
|
console.log(
|
|
|
|
|
PurcDiscType,
|
|
|
|
|
PurcDisc,
|
|
|
|
|
'record.DiscountType'
|
|
|
|
|
);
|
|
|
|
|
const newData = TableData.map((item, index1) => {
|
|
|
|
|
if (index1 === index) {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
PurcDisc: 0,
|
|
|
|
|
NetAmt: item.Price * item.Qty,
|
|
|
|
|
// TaxAmt: taxamount,
|
|
|
|
|
BillAmount: item.Price * item.Qty - item.taxamount,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
...form.getFieldsValue(),
|
|
|
|
|
[`PurcDisc${index}`]: 0,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// if (
|
|
|
|
|
// !/^(100(\.0{1,2})?|[0-9]{1,2}(\.\d{1,2})?)$/.test(value)
|
|
|
|
|
// ) {
|
|
|
|
|
// return Promise.reject('enter a valid discount (0-100%)');
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<Select
|
|
|
|
|
onChange={(value) =>
|
|
|
|
|
handleDiscountTypeChange(value, record, index)
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Option value="P">%</Option>
|
|
|
|
|
<Option value="A">Amt</Option>
|
|
|
|
|
</Select>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
) : (
|
|
|
|
|
text
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (seltax !== 'WOT') {
|
|
|
|
|
baseColumns.splice(8, 0, {
|
|
|
|
|
title: 'Tax %',
|
|
|
|
|
dataIndex: 'TaxPercentage',
|
|
|
|
|
key: 'TaxPercentage',
|
|
|
|
|
editable: true,
|
|
|
|
|
});
|
|
|
|
|
baseColumns.splice(9, 0, {
|
|
|
|
|
title: 'Tax Name',
|
|
|
|
|
dataIndex: 'TaxName',
|
|
|
|
|
key: 'TaxName',
|
|
|
|
|
editable: true,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
baseColumns.push({
|
|
|
|
|
title: 'Action',
|
|
|
|
|
dataIndex: 'Action',
|
|
|
|
|
key: 'Action',
|
|
|
|
|
align: 'center',
|
|
|
|
|
editable: false,
|
|
|
|
|
render: (_, record, index) => (
|
|
|
|
|
<a>
|
|
|
|
|
<DeleteFilled
|
|
|
|
|
style={{ color: '#FF4D4F' }}
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation(); // Stop event from bubbling up to row
|
|
|
|
|
statusFormatters(record, index);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</a>
|
|
|
|
|
),
|
|
|
|
|
});
|
|
|
|
|
return baseColumns;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const columns = getColumns(TableData, SelTaxType);
|
|
|
|
|
|
|
|
|
|
const edit = (record, index) => {
|
|
|
|
|
form.setFieldsValue({ ...record });
|
|
|
|
|
setEditingKey(index);
|
|
|
|
|
setindex(index);
|
|
|
|
|
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
[`Qty${index}`]: record?.Qty,
|
|
|
|
|
[`NetAmt${index}`]: !isNaN(record?.NetAmt) ? record?.NetAmt : 0,
|
|
|
|
|
[`PurcDisc${index}`]: record?.PurcDisc,
|
|
|
|
|
[`Price${index}`]: record?.Price,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
const statusFormatters = (record, index) => {
|
|
|
|
|
// Remove the row from table data
|
|
|
|
|
const newData = TableData.filter((_, i) => i !== index);
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
setDelete(true);
|
|
|
|
|
setEditingKey('');
|
|
|
|
|
// Get all current form values
|
|
|
|
|
const currentFormValues = form.getFieldsValue();
|
|
|
|
|
|
|
|
|
|
// Clear all form fields first
|
|
|
|
|
const allFieldsToClear = [];
|
|
|
|
|
for (let i = 0; i < TableData.length; i++) {
|
|
|
|
|
allFieldsToClear.push(
|
|
|
|
|
`BalanceQty${i}`,
|
|
|
|
|
`Amount${i}`,
|
|
|
|
|
`PurcDisc${i}`,
|
|
|
|
|
`SellPrice${i}`,
|
|
|
|
|
`Qty${i}`,
|
|
|
|
|
`NetAmt${i}`,
|
|
|
|
|
`Price${i}`,
|
|
|
|
|
`DiscType${i}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const clearAllValues = {};
|
|
|
|
|
allFieldsToClear.forEach((field) => {
|
|
|
|
|
clearAllValues[field] = undefined;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Set new form values with correct indices
|
|
|
|
|
const newFormValues = {};
|
|
|
|
|
newData.forEach((item, newIndex) => {
|
|
|
|
|
newFormValues[`Qty${newIndex}`] = item.Qty;
|
|
|
|
|
newFormValues[`NetAmt${newIndex}`] = item.NetAmt;
|
|
|
|
|
newFormValues[`PurcDisc${newIndex}`] = item.PurcDisc;
|
|
|
|
|
newFormValues[`Price${newIndex}`] = item.Price;
|
|
|
|
|
newFormValues[`DiscType${newIndex}`] = item.DiscType;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Apply the new form values
|
|
|
|
|
form.setFieldsValue({ ...clearAllValues, ...newFormValues });
|
|
|
|
|
console.log(form.getFieldsValue(), 'jjij');
|
|
|
|
|
};
|
|
|
|
|
const handleQtyChange = (e, record, index) => {
|
|
|
|
|
const qty = e.target.value;
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(qty)) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Only numeric values are allowed');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const sellprice = parseInt(record.Price);
|
|
|
|
|
const Amount = !isNaN(sellprice * parseInt(qty))
|
|
|
|
|
? sellprice * parseInt(qty)
|
|
|
|
|
: 0;
|
|
|
|
|
|
2026-03-09 10:43:17 +05:30
|
|
|
const taxamt =
|
|
|
|
|
SelTaxTypeName?.toLowerCase() === 'withtax'
|
|
|
|
|
? (Amount * parseInt(record?.TaxPercentage)) /
|
|
|
|
|
(100 + parseInt(record?.TaxPercentage))
|
|
|
|
|
: 0;
|
2026-01-27 18:27:29 +05:30
|
|
|
const newData = TableData.map((item, index1) => {
|
|
|
|
|
if (index1 === index) {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
Qty: qty,
|
|
|
|
|
NetAmt: Amount,
|
|
|
|
|
TaxAmt: taxamt,
|
|
|
|
|
BillAmount: Amount - taxamt,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
...form.getFieldsValue(),
|
|
|
|
|
|
|
|
|
|
[`Qty${index}`]: qty,
|
|
|
|
|
[`NetAmt${index}`]: Amount,
|
2026-03-09 10:43:17 +05:30
|
|
|
|
2026-01-27 18:27:29 +05:30
|
|
|
[`PurcDisc${index}`]: 0,
|
|
|
|
|
[`DiscType${index}`]: 'P',
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
const handleDiscountTypeChange = (value, record, index) => {
|
|
|
|
|
const tempamt = record.Qty * record.Price;
|
|
|
|
|
const DisType = value;
|
|
|
|
|
const amount =
|
|
|
|
|
value === 'A'
|
|
|
|
|
? tempamt - record.PurcDisc
|
|
|
|
|
: tempamt - tempamt * (record.PurcDisc / 100);
|
|
|
|
|
const taxamt =
|
|
|
|
|
SelTaxTypeName?.toLowerCase() === 'withtax'
|
|
|
|
|
? (amount * parseInt(record?.TaxPercentage)) /
|
2026-03-09 10:43:17 +05:30
|
|
|
(100 + parseInt(record?.TaxPercentage))?.toFixed(2)
|
2026-01-27 18:27:29 +05:30
|
|
|
: 0;
|
|
|
|
|
// You can calculate acceptedQty based on your requirement
|
|
|
|
|
const newData = TableData.map((item, index1) => {
|
|
|
|
|
if (index1 === index) {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
|
|
|
|
|
NetAmt: amount,
|
|
|
|
|
TaxAmt: taxamt,
|
|
|
|
|
BillAmount: amount - taxamt,
|
|
|
|
|
DiscType: DisType,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePurrateChange = (e, record, index) => {
|
|
|
|
|
const inputValue = e.target.value;
|
|
|
|
|
|
|
|
|
|
// Validate if inputValue is numeric
|
|
|
|
|
if (!/^\d*\.?\d*$/.test(inputValue)) {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Only numeric values are allowed');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PurcRate = inputValue;
|
|
|
|
|
// const PurcRate = e.target.value
|
|
|
|
|
const tempamt = !isNaN(parseInt(PurcRate) * parseInt(record?.Qty))
|
|
|
|
|
? parseInt(PurcRate) * parseInt(record?.Qty)
|
|
|
|
|
: 0;
|
|
|
|
|
const amount =
|
|
|
|
|
record?.PurcDisc === 0
|
|
|
|
|
? tempamt
|
|
|
|
|
: record?.DiscType === 'A'
|
|
|
|
|
? tempamt - record.PurcDisc
|
|
|
|
|
: tempamt - tempamt * (record.PurcDisc / 100);
|
|
|
|
|
const taxamt =
|
|
|
|
|
SelTaxTypeName?.toLowerCase() === 'withtax'
|
|
|
|
|
? (amount * parseInt(record?.TaxPercentage)) /
|
2026-03-09 10:43:17 +05:30
|
|
|
(100 + parseInt(record?.TaxPercentage))?.toFixed(2)
|
2026-01-27 18:27:29 +05:30
|
|
|
: 0;
|
|
|
|
|
// You can calculate acceptedQty based on your requirement
|
|
|
|
|
const newData = TableData.map((item, index1) => {
|
|
|
|
|
if (index1 === index) {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
Price: PurcRate,
|
|
|
|
|
NetAmt: amount,
|
|
|
|
|
TaxAmt: taxamt,
|
|
|
|
|
BillAmount: amount - taxamt,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
...form.getFieldsValue(),
|
|
|
|
|
[`Price${index}`]: PurcRate,
|
|
|
|
|
[`NetAmt${index}`]: amount,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
const handlePurdiscChange = (e, record, index) => {
|
|
|
|
|
console.log(e.target.value, record, 'discountdiscount');
|
|
|
|
|
const PurcDisc = e.target.value;
|
|
|
|
|
const PurcRate = record?.Price;
|
|
|
|
|
const tempamt = parseInt(record?.Price) * record?.Qty;
|
|
|
|
|
const amount =
|
|
|
|
|
record.DiscType === 'A'
|
|
|
|
|
? tempamt - PurcDisc
|
|
|
|
|
: tempamt - tempamt * (parseFloat(PurcDisc) / 100);
|
|
|
|
|
const taxamount =
|
|
|
|
|
SelTaxTypeName?.toLowerCase() === 'withtax'
|
|
|
|
|
? (amount * parseInt(record?.TaxPercentage)) /
|
2026-03-09 10:43:17 +05:30
|
|
|
(100 + parseInt(record?.TaxPercentage))?.toFixed(2)
|
2026-01-27 18:27:29 +05:30
|
|
|
: 0;
|
|
|
|
|
form.setFields([{ name: [`PurcDisc${index}`], errors: [] }]);
|
|
|
|
|
|
|
|
|
|
// Check if PurcDisc is a valid number
|
|
|
|
|
if (!isNaN(parseFloat(PurcDisc)) && isFinite(PurcDisc)) {
|
|
|
|
|
if (record?.Qty > 0) {
|
|
|
|
|
const newData = TableData.map((item, index1) => {
|
|
|
|
|
if (index1 === index) {
|
|
|
|
|
return {
|
|
|
|
|
...item,
|
|
|
|
|
PurcDisc: PurcDisc,
|
|
|
|
|
NetAmt: amount,
|
|
|
|
|
TaxAmt: taxamount,
|
|
|
|
|
BillAmount: amount - taxamount,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
setTableData(newData);
|
|
|
|
|
form.setFieldsValue({
|
|
|
|
|
...form.getFieldsValue(),
|
|
|
|
|
[`PurcDisc${index}`]: PurcDisc,
|
|
|
|
|
[`NetAmt${index}`]: amount,
|
|
|
|
|
// [`DiscType${index}`]: 'P',
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
form.setFields([
|
|
|
|
|
{
|
|
|
|
|
name: [`PurcDisc${index}`],
|
|
|
|
|
errors: [' Please Enter Purchase Quantity'],
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Set error if PurcDisc is not a valid number
|
|
|
|
|
form.setFields([
|
|
|
|
|
{ name: [`PurcDisc${index}`], errors: [' Discount must be a number'] },
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const PrintQuotation = async () => {
|
|
|
|
|
// await printDiv(`Pur-Quot-Print`, QuotationStyle)
|
|
|
|
|
if (
|
|
|
|
|
TableData?.length > 0 &&
|
|
|
|
|
TableData?.every((item) => item.Qty !== 0 && item.Amount !== 0)
|
|
|
|
|
) {
|
|
|
|
|
let PostData = formRef.current?.getFieldsValue();
|
|
|
|
|
PostData['ProductDetails'] = TableData;
|
|
|
|
|
PostData['BillAmount'] = parseFloat(TotalBillAmount?.toFixed(2));
|
|
|
|
|
PostData['NetAmount'] = parseFloat(TotalAmount?.toFixed(2));
|
|
|
|
|
PostData['TaxAmount'] = parseFloat(
|
|
|
|
|
(TotalCgst + TotalSgst + TotalIgst)?.toFixed(2)
|
|
|
|
|
);
|
2026-03-09 10:43:17 +05:30
|
|
|
((PostData['CompId'] = CompId),
|
2026-01-27 18:27:29 +05:30
|
|
|
(PostData['BranchId'] = BranchId),
|
2026-03-09 10:43:17 +05:30
|
|
|
(PostData['AppId'] = AppId));
|
2026-01-27 18:27:29 +05:30
|
|
|
let res = await dispatch(postPurcQuotation(PostData)).unwrap();
|
|
|
|
|
if (res?.data?.statusCode === 1) {
|
|
|
|
|
setMessageType('success');
|
|
|
|
|
setMessageData(res?.data?.response);
|
|
|
|
|
const custId = formRef.current?.getFieldValue('CustId');
|
2026-03-09 10:43:17 +05:30
|
|
|
const customer = AllCustomer?.find((c) => c.UserId === custId);
|
|
|
|
|
console.log(customer, 'customertrt');
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
setPrintData(res?.data?.data);
|
|
|
|
|
setIsSubmitted(true);
|
|
|
|
|
formRef?.current?.resetFields([
|
|
|
|
|
'CustId',
|
|
|
|
|
'ProdId',
|
|
|
|
|
'QRCode',
|
|
|
|
|
'VarProdId',
|
|
|
|
|
'TaxType',
|
|
|
|
|
]);
|
|
|
|
|
setTableData([]);
|
|
|
|
|
setSelProduct(null);
|
|
|
|
|
setSelectedProductName(null);
|
|
|
|
|
setSelecAdminUser(null);
|
|
|
|
|
setSelTaxType(null);
|
|
|
|
|
setSelTaxTypeName(null);
|
|
|
|
|
setVariants(null);
|
|
|
|
|
setselectedProductVariantData(null);
|
|
|
|
|
|
|
|
|
|
// Reset totals
|
|
|
|
|
setTotalBillAmount(null);
|
|
|
|
|
setTotalCgst(null);
|
|
|
|
|
setTotalSgst(null);
|
|
|
|
|
setTotalIgst(null);
|
|
|
|
|
setTotalAmount(null);
|
|
|
|
|
|
|
|
|
|
// Reset editing state
|
|
|
|
|
setEditingKey('');
|
|
|
|
|
setindex(null);
|
|
|
|
|
|
|
|
|
|
// Clear form values for all table rows
|
|
|
|
|
const clearFields = {};
|
|
|
|
|
TableData.forEach((_, index) => {
|
|
|
|
|
clearFields[`Qty${index}`] = undefined;
|
|
|
|
|
clearFields[`Price${index}`] = undefined;
|
|
|
|
|
clearFields[`PurcDisc${index}`] = undefined;
|
|
|
|
|
clearFields[`NetAmt${index}`] = undefined;
|
|
|
|
|
clearFields[`DiscType${index}`] = undefined;
|
|
|
|
|
});
|
|
|
|
|
form.setFieldsValue(clearFields);
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData(res?.data?.response);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
setMessageData('Please give Product Quantity for all Product ');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onChangeprodFunction = (e) => {
|
|
|
|
|
console.log(e, 'yyyyyyyyyyyyyy');
|
|
|
|
|
|
|
|
|
|
if (isbarcode) {
|
|
|
|
|
// When in barcode mode, search by QRCode
|
|
|
|
|
const productByQR = ProductData.find(
|
|
|
|
|
(p) => p.QRCode && p.QRCode?.toLowerCase() === e?.toLowerCase()
|
|
|
|
|
);
|
|
|
|
|
if (productByQR) {
|
|
|
|
|
const productValue =
|
|
|
|
|
productByQR.ProdName +
|
|
|
|
|
' ' +
|
|
|
|
|
'(' +
|
|
|
|
|
productByQR.Size +
|
|
|
|
|
productByQR.UomName +
|
|
|
|
|
')';
|
|
|
|
|
form.setFieldsValue({ ProdId: productValue });
|
|
|
|
|
setSelProduct(productValue);
|
|
|
|
|
ProductDropDownChange({ value: productValue });
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Normal mode - search by product name
|
|
|
|
|
form.setFieldsValue({ ProdId: e });
|
|
|
|
|
setSelProduct(e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handlePrint = async () => {
|
|
|
|
|
const style = await PrintStyleFunction(
|
2026-03-09 10:43:17 +05:30
|
|
|
PrintTempData?.StyleName == undefined
|
|
|
|
|
? 'Style 13'
|
|
|
|
|
: PrintTempData?.StyleName,
|
2026-01-27 18:27:29 +05:30
|
|
|
'Quotation'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const stylesMap = {
|
|
|
|
|
'Style 1': 'SQPrintStyle1',
|
|
|
|
|
'Style 2': 'SQPrintStyle2',
|
|
|
|
|
'Style 3': 'SQPrintStyle3',
|
|
|
|
|
'Style 4': 'SQPrintStyle4',
|
|
|
|
|
'Style 5': 'SQPrintStyle5',
|
|
|
|
|
'Style 6': 'SQPrintStyle6',
|
|
|
|
|
'Style 7': 'SQPrintStyle7',
|
|
|
|
|
'Style 8': 'SQPrintStyle8',
|
|
|
|
|
'Style 9': 'SQPrintStyle9',
|
|
|
|
|
'Style 10': 'SQPrintStyle10',
|
|
|
|
|
'Style 11': 'SQPrintStyle11',
|
|
|
|
|
'Style 12': 'SQPrintStyle12',
|
|
|
|
|
'Style 13': 'Pur-Quot-Print',
|
|
|
|
|
A4: 'SQPrintStyleA4',
|
|
|
|
|
A5: 'SQPrintStyleA5',
|
|
|
|
|
A4Standard: 'SQA4Standard',
|
|
|
|
|
TaxInvoice: 'TaxInvoice',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const selectedStyle =
|
|
|
|
|
stylesMap[
|
2026-03-09 10:43:17 +05:30
|
|
|
PrintTempData?.StyleName == undefined
|
|
|
|
|
? 'Style 13'
|
|
|
|
|
: PrintTempData?.StyleName
|
2026-01-27 18:27:29 +05:30
|
|
|
];
|
2026-03-09 10:43:17 +05:30
|
|
|
|
|
|
|
|
if (isMobile) {
|
|
|
|
|
PurchaseQtMobilePrint({
|
|
|
|
|
PrintTempData: PrintTempData,
|
|
|
|
|
PrintOrderDetails: PrintData,
|
|
|
|
|
UserId: UserId,
|
|
|
|
|
dispatch,
|
|
|
|
|
});
|
|
|
|
|
} else if (selectedStyle) {
|
|
|
|
|
await printDiv(`${selectedStyle}`, style);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleEmailClick = async (mail, data) => {
|
2026-03-09 10:43:17 +05:30
|
|
|
let record = mail == 'mail' ? data : PrintData?.[0];
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
if (record?.Email) {
|
|
|
|
|
setTimeout(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const blob = await pdfDiv('Pur-Quot-Print', PurchaseOrderStyle);
|
|
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
|
fileBlob: blob,
|
|
|
|
|
toEmail: record?.Email,
|
|
|
|
|
type: 'Quotation',
|
|
|
|
|
messageTemplatesList: [],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const res = await dispatch(Emailsend(payload)).unwrap();
|
|
|
|
|
if (res?.data?.status === 1) {
|
|
|
|
|
setMessageData(res?.data?.response);
|
|
|
|
|
setMessageType('success');
|
2026-03-09 10:43:17 +05:30
|
|
|
} else {
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageData(res?.data?.response);
|
|
|
|
|
setMessageType('error');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setMessageData("Email sent successfully");
|
|
|
|
|
// setMessageType('success');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('❌ Email send failed:', error);
|
|
|
|
|
// alert('❌ Email failed to send');
|
2026-03-09 10:43:17 +05:30
|
|
|
setMessageData('Email failed to send');
|
2026-01-27 18:27:29 +05:30
|
|
|
setMessageType('error');
|
|
|
|
|
}
|
|
|
|
|
}, 300);
|
2026-03-09 10:43:17 +05:30
|
|
|
} else {
|
|
|
|
|
setusrMailDataModel(true);
|
2026-01-27 18:27:29 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleUserMailmodalCancel = () => {
|
2026-03-09 10:43:17 +05:30
|
|
|
setusrMailDataModel(false);
|
|
|
|
|
setEnteredMailId(null);
|
2026-01-27 18:27:29 +05:30
|
|
|
emailform.resetFields();
|
|
|
|
|
// setQuotationProductdata([])
|
2026-03-09 10:43:17 +05:30
|
|
|
};
|
2026-01-27 18:27:29 +05:30
|
|
|
|
|
|
|
|
const emailSubmit = (values) => {
|
2026-03-09 10:43:17 +05:30
|
|
|
let data = {
|
|
|
|
|
...PrintData?.[0],
|
|
|
|
|
...{ CustMail: values.email },
|
|
|
|
|
...{ Email: values.email },
|
|
|
|
|
};
|
|
|
|
|
handleEmailClick('mail', data);
|
2026-01-27 18:27:29 +05:30
|
|
|
setEnteredMailId(null);
|
|
|
|
|
emailform.resetFields();
|
|
|
|
|
emailform.setFieldsValue({ email: '' });
|
|
|
|
|
setusrMailDataModel(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="pageOverAll">
|
|
|
|
|
<div className="userPage">
|
|
|
|
|
<div className="userPageContent">
|
|
|
|
|
<Messages
|
|
|
|
|
messageType={messageType}
|
|
|
|
|
messageData={messageData}
|
|
|
|
|
onComplete={onComplete}
|
|
|
|
|
/>
|
2026-03-09 10:43:17 +05:30
|
|
|
<div
|
|
|
|
|
className="formName"
|
|
|
|
|
style={{
|
|
|
|
|
display: 'flex',
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
marginTop: '5px',
|
|
|
|
|
}}
|
|
|
|
|
>
|
2026-01-27 18:27:29 +05:30
|
|
|
<FormHeader title={'Sales Quotation'} />
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
display: 'flex',
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
gap: '7px',
|
|
|
|
|
padding: '6px 12px',
|
|
|
|
|
backgroundColor: '#059645',
|
|
|
|
|
borderRadius: '8px',
|
|
|
|
|
color: 'white',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
fontFamily: 'Poppins',
|
|
|
|
|
fontWeight: '400',
|
2026-03-09 10:43:17 +05:30
|
|
|
whiteSpace: 'nowrap',
|
|
|
|
|
fontSize: '15px',
|
2026-01-27 18:27:29 +05:30
|
|
|
}}
|
2026-03-09 10:43:17 +05:30
|
|
|
onClick={() =>
|
|
|
|
|
navigate(`${subDirectory}setting/sales-quotation/list`)
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
>
|
|
|
|
|
<FaEye /> <span>View Quotation</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="Quo-formDiv">
|
|
|
|
|
<Form
|
|
|
|
|
ref={formRef}
|
|
|
|
|
className="formDivAnt"
|
|
|
|
|
onFinish={PrintQuotation}
|
|
|
|
|
>
|
|
|
|
|
<div className="formDivS">
|
|
|
|
|
<div className="inputForm">
|
|
|
|
|
<div className="purchaseQuoaDetails">
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="CustId"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: 'Please Select Customer',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<DropDowns
|
|
|
|
|
options={AllCustomer?.map((option) => ({
|
|
|
|
|
value: option.CustId,
|
|
|
|
|
label:
|
|
|
|
|
option.CustName ||
|
|
|
|
|
option.CustShortName ||
|
|
|
|
|
option.CustMobile,
|
|
|
|
|
}))}
|
|
|
|
|
label={<label class="required">Customer</label>}
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
onChangeFunction={handleAdminUserDropDownChange}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Form.Item
|
|
|
|
|
name="TaxType"
|
|
|
|
|
rules={[
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: 'Please Select Purchase Tax Type',
|
|
|
|
|
},
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<DropDowns
|
|
|
|
|
options={PurcTaxTypeData?.map((option) => ({
|
|
|
|
|
value: option.ConfigId,
|
|
|
|
|
label: option.ConfigName,
|
|
|
|
|
}))}
|
|
|
|
|
label={
|
|
|
|
|
<label class="required">Purchase Tax Type</label>
|
|
|
|
|
}
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
onChangeFunction={(e) => handleQuoTaxTypeChange(e)}
|
|
|
|
|
valueData={SelTaxType}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
<div className="ProductDropDownChange-Quotation">
|
2026-03-09 10:43:17 +05:30
|
|
|
<Form.Item name="ProdId">
|
2026-01-27 18:27:29 +05:30
|
|
|
<div className="product-scan sales-quotation">
|
2026-03-09 10:43:17 +05:30
|
|
|
<FloatLabel
|
|
|
|
|
label={'Product Name'}
|
|
|
|
|
value={selectedProductName}
|
|
|
|
|
>
|
2026-01-27 18:27:29 +05:30
|
|
|
<AutoComplete
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
value={selectedProductName}
|
|
|
|
|
filterOption={(input, option) => {
|
2026-03-09 10:43:17 +05:30
|
|
|
const product = ProductData.find(
|
|
|
|
|
(p) => p.ProdId === option.value
|
|
|
|
|
);
|
|
|
|
|
const nameMatch = option.label
|
|
|
|
|
?.toLowerCase()
|
|
|
|
|
?.includes(productSearchText?.toLowerCase());
|
|
|
|
|
const qrMatch =
|
|
|
|
|
product?.QRCode?.toLowerCase() ==
|
|
|
|
|
productSearchText?.toLowerCase();
|
2026-01-27 18:27:29 +05:30
|
|
|
return nameMatch || qrMatch;
|
|
|
|
|
}}
|
2026-03-09 10:43:17 +05:30
|
|
|
options={
|
|
|
|
|
!scanner
|
|
|
|
|
? ProductData?.map((option) => ({
|
|
|
|
|
value: option.ProdId,
|
|
|
|
|
label: `${option.ProdName} (${option.Size} ${option.UomName})${option?.BrandName ? ` - ${option?.BrandName}` : ''}`,
|
|
|
|
|
}))
|
|
|
|
|
: []
|
|
|
|
|
}
|
2026-01-27 18:27:29 +05:30
|
|
|
onSelect={ProductDropDownChange}
|
|
|
|
|
onChange={handleProductSearch}
|
|
|
|
|
onKeyDown={(e) => {
|
2026-03-09 10:43:17 +05:30
|
|
|
if (scanner && e.key === 'Enter') {
|
2026-01-27 18:27:29 +05:30
|
|
|
e.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
disabled={ProductData?.length === 0}
|
2026-03-09 10:43:17 +05:30
|
|
|
></AutoComplete>
|
2026-01-27 18:27:29 +05:30
|
|
|
</FloatLabel>
|
2026-03-09 10:43:17 +05:30
|
|
|
<Tooltip title={'BarCode/QrCode'} placement={'top'}>
|
|
|
|
|
<div className="BsUpcScanSQ">
|
2026-03-11 14:19:41 +05:30
|
|
|
{!isMobile ? <BsUpcScan
|
2026-03-09 10:43:17 +05:30
|
|
|
strokeWidth={0.5}
|
|
|
|
|
color="#000"
|
|
|
|
|
style={{
|
|
|
|
|
fontSize: '16px',
|
|
|
|
|
color: scanner ? '#52c41a' : '#888',
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
}}
|
|
|
|
|
className="product-scan-Icon"
|
|
|
|
|
onClick={handleScanSearch}
|
|
|
|
|
/>
|
2026-03-11 14:19:41 +05:30
|
|
|
: <BarCodeScan
|
|
|
|
|
onScan={(value) => {
|
|
|
|
|
debouncedScannerSearch(value);
|
|
|
|
|
}}
|
|
|
|
|
/>}
|
2026-03-09 10:43:17 +05:30
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
</Tooltip>
|
2026-03-09 10:43:17 +05:30
|
|
|
{ProductData?.length === 0 && (
|
|
|
|
|
<p style={{ color: 'red' }}>
|
|
|
|
|
<ImWarning /> All Products have no Stock
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
{Variants?.length > 1 && (
|
|
|
|
|
<Form.Item name="VarProdId">
|
|
|
|
|
<DropDowns
|
|
|
|
|
options={Variants?.map((option) => ({
|
|
|
|
|
value: option.ProdIdProdName,
|
|
|
|
|
label: option.ProdVariantName,
|
|
|
|
|
}))}
|
|
|
|
|
label={'Variant Name'}
|
|
|
|
|
className="field-DropDown"
|
|
|
|
|
onChangeFunction={(e) =>
|
|
|
|
|
ProductVariantDropDownChange(e)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</Form.Item>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<div
|
|
|
|
|
className="Quotation-table"
|
|
|
|
|
style={{
|
|
|
|
|
maxwidth: '500px',
|
|
|
|
|
overflow: TableData?.length > 0 ? 'auto' : 'hidden',
|
|
|
|
|
// overflowX: TableData?.length > 0 ? "auto" : "hidden",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Form form={form} component={false}>
|
|
|
|
|
<Table
|
|
|
|
|
bordered
|
|
|
|
|
dataSource={TableData}
|
|
|
|
|
columns={columns}
|
|
|
|
|
rowClassName="editable-row"
|
|
|
|
|
onRow={(record, index) => ({
|
|
|
|
|
onClick: () => {
|
|
|
|
|
edit(record, index);
|
|
|
|
|
},
|
|
|
|
|
})}
|
|
|
|
|
pagination={false}
|
|
|
|
|
/>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-09 10:43:17 +05:30
|
|
|
<div
|
|
|
|
|
className="QuosubmitButton"
|
|
|
|
|
style={{ display: 'flex', gap: '1rem' }}
|
|
|
|
|
>
|
2026-01-27 18:27:29 +05:30
|
|
|
<Buttons
|
|
|
|
|
buttonText="SUBMIT"
|
|
|
|
|
color="901D77"
|
|
|
|
|
disabled={addnewAccess}
|
|
|
|
|
icon={<ArrowRightOutlined />}
|
|
|
|
|
htmlType={true}
|
|
|
|
|
/>
|
|
|
|
|
{isSubmitted && PrintData?.length > 0 && (
|
|
|
|
|
<>
|
|
|
|
|
<div>
|
|
|
|
|
<MdOutlineMail
|
|
|
|
|
size={39}
|
|
|
|
|
color="#25D366"
|
|
|
|
|
style={{ cursor: 'pointer' }}
|
|
|
|
|
onClick={handleEmailClick}
|
|
|
|
|
title="Share by Email"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<FaPrint
|
|
|
|
|
size={32}
|
|
|
|
|
color="#1292EE"
|
|
|
|
|
style={{ cursor: 'pointer' }}
|
|
|
|
|
onClick={handlePrint}
|
|
|
|
|
title="Print"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
|
|
|
|
{TableData?.length > 0 && (
|
|
|
|
|
<div className="Quo-Summary-Quotation">
|
2026-03-09 10:43:17 +05:30
|
|
|
<div className="Quotation-summary">
|
|
|
|
|
{' '}
|
|
|
|
|
Gross Total:{' '}
|
|
|
|
|
{allowDecimal ? TotalBillAmount?.toFixed(2) : TotalBillAmount}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="Quotation-summary">
|
|
|
|
|
{' '}
|
|
|
|
|
Total GST:{' '}
|
|
|
|
|
{allowDecimal
|
|
|
|
|
? (TotalCgst + TotalSgst + TotalIgst)?.toFixed(2)
|
|
|
|
|
: TotalCgst + TotalSgst + TotalIgst}
|
|
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
{/* <div> Total SGST: {TotalSgst?.toFixed(2)}</div>
|
|
|
|
|
<div> Total IGST: {TotalIgst?.toFixed(2)}</div> */}
|
2026-03-09 10:43:17 +05:30
|
|
|
<div className="Quotation-summary">
|
|
|
|
|
{' '}
|
|
|
|
|
Total Amount:{' '}
|
|
|
|
|
{allowDecimal
|
|
|
|
|
? Math.round(TotalAmount)?.toFixed(2)
|
|
|
|
|
: Math.round(TotalAmount)}
|
|
|
|
|
</div>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
<DefaultModal
|
|
|
|
|
width={400}
|
|
|
|
|
open={usrMailDataModel}
|
|
|
|
|
title="User Mail"
|
|
|
|
|
handleCancel={handleUserMailmodalCancel}
|
|
|
|
|
footer={false}
|
|
|
|
|
children={
|
|
|
|
|
<div>
|
|
|
|
|
<Form form={emailform} layout="vertical" onFinish={emailSubmit}>
|
|
|
|
|
<Form.Item
|
|
|
|
|
label="Mail ID"
|
|
|
|
|
name="email"
|
|
|
|
|
rules={[
|
2026-03-09 10:43:17 +05:30
|
|
|
{ required: true, message: 'Email is required' },
|
|
|
|
|
{ type: 'email', message: 'Enter a valid email address' },
|
2026-01-27 18:27:29 +05:30
|
|
|
]}
|
|
|
|
|
>
|
2026-03-09 10:43:17 +05:30
|
|
|
<Input autoComplete="off" placeholder="Enter your email" />
|
2026-01-27 18:27:29 +05:30
|
|
|
</Form.Item>
|
|
|
|
|
|
|
|
|
|
<Button type="primary" htmlType="submit">
|
|
|
|
|
Submit
|
|
|
|
|
</Button>
|
|
|
|
|
</Form>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div style={{ display: 'none' }}>
|
2026-03-09 10:43:17 +05:30
|
|
|
<PurchaseQuotationPrint
|
|
|
|
|
PrintingData={PrintData}
|
|
|
|
|
PrintTempData={PrintTempData}
|
|
|
|
|
/>
|
2026-01-27 18:27:29 +05:30
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
2026-03-09 10:43:17 +05:30
|
|
|
export default SalesQuotationForm;
|