diff --git a/src/Features/ProductPage/ProductPage.js b/src/Features/ProductPage/ProductPage.js index 0fa2118..eb13b85 100644 --- a/src/Features/ProductPage/ProductPage.js +++ b/src/Features/ProductPage/ProductPage.js @@ -4,6 +4,7 @@ import { axiosCommonInstanceData, axiosRetailOcrData, } from '../AuthenicationToken/AuthenticationToken'; +import { data } from 'jquery'; // export const getUserGuideLines = createAsyncThunk('product/getBranchData', async ({ formType, userId }) => { // if (formType !=null && formType !=undefined && userId !=null && userId !=undefined) { @@ -60,7 +61,7 @@ export const getTopSellingProduct = createAsyncThunk( } ); export const PostPedalOCR = createAsyncThunk( - 'Stock/PostPedalOCR', + 'Stock/PostPedalOCR', async (fileOrFormData) => { let formdata; if (fileOrFormData instanceof FormData) { @@ -244,6 +245,22 @@ export const getProductDataPageNo = createAsyncThunk( } ); +export const getDirectSaleProducts = createAsyncThunk( + 'product/getDirectSaleProducts', + async (data) => { + const { CompId, BranchId, AppId, page } = data + if ( + CompId != null && CompId != undefined && + BranchId != null && BranchId != undefined && + AppId != null && AppId != undefined + ) { + return await axiosRetailInstanceData.get( + `/product?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&SalesType=DS&PageNumber=${page}` + ); + } + } +); + export const getAllprodIds = createAsyncThunk( 'product/getAllprodIds', async (ProdData) => { @@ -273,6 +290,13 @@ export const getAllprodIds = createAsyncThunk( } ); +export const getAllProductShortCodes = createAsyncThunk('product/getAllProductShortCodes', async (data) => { + const { AppId, CompId, BranchId } = data; + if (AppId != null && AppId && BranchId != null && BranchId && AppId && AppId != null) { + return await axiosRetailInstanceData.get(`/Product/ProdShortCodes?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}`); + } +}); + export const getProductDataSearch = createAsyncThunk( 'product/getProductDataSearch', async (ProdData) => { @@ -291,6 +315,22 @@ export const getProductDataSearch = createAsyncThunk( } ); +export const getDirectSaleSearchedProduct = createAsyncThunk( + 'product/getDirectSaleSearchedProduct', + async (data) => { + const { CompId, BranchId, AppId, prodName } = data; + if ( + CompId != null && CompId != undefined && + BranchId != null && BranchId != undefined && + AppId != undefined && AppId != null + ) { + return await axiosRetailInstanceData.get( + `/ProductMasterSearch?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&prodName=${prodName}&SalesType=DS` + ); + } + } +); + export const getBrandData = createAsyncThunk( 'product/getBrandData', async ({ ConfigId }) => { @@ -571,24 +611,24 @@ export const postRackData = createAsyncThunk( async (postData) => { return await axiosRetailInstanceData.post(`/RackMaster`, postData); } -); +); export const putRackData = createAsyncThunk( 'putRackData/RackMaster', async (postData) => { return await axiosRetailInstanceData.put(`/RackMaster`, postData); } -); +); export const getRackData = createAsyncThunk( 'getRackData/RackMaster', - async ({ AppId, CompId, BranchId}) => { + async ({ AppId, CompId, BranchId }) => { if ( AppId != null && AppId != undefined && CompId != null && CompId != undefined && BranchId != null && - BranchId != undefined + BranchId != undefined ) { return await axiosRetailInstanceData.get( `/RackMaster?AppId=${AppId}&CompId=${CompId}&BranchId=${BranchId}` @@ -599,12 +639,12 @@ export const getRackData = createAsyncThunk( export const deleteRackData = createAsyncThunk( 'deleteRackData/RackMaster', - async ({ activeStatus, updatedBy, rackId}) => { + async ({ activeStatus, updatedBy, rackId }) => { if ( updatedBy != null && updatedBy != undefined && activeStatus != null && - activeStatus != undefined + activeStatus != undefined ) { return await axiosRetailInstanceData.delete( `/RackMaster?activeStatus=${activeStatus}&updatedBy=${updatedBy}&rackId=${rackId}` diff --git a/src/Features/StockMaster/StockMaster.js b/src/Features/StockMaster/StockMaster.js index 574f245..b6a75b9 100644 --- a/src/Features/StockMaster/StockMaster.js +++ b/src/Features/StockMaster/StockMaster.js @@ -26,21 +26,29 @@ export const getProductData = createAsyncThunk( export const getInvoiceImageData = createAsyncThunk( 'Stock/getInvoiceImageData', - async (file) => { + async ({ file, AppId, CompId, BranchId }) => { if (!file) return; const formData = new FormData(); - formData.append('file', file); // 👈 actual file here + formData.append('file', file); // file + formData.append('AppId', AppId); // 👈 add AppId + formData.append('CompId', CompId); // 👈 add CompId + formData.append('BranchId', BranchId); // 👈 add BranchId - const response = await axiosRetailOcrData.post('/invoice', formData, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }); + const response = await axiosRetailOcrData.post( + '/invoice', + formData, + { + headers: { + 'Content-Type': 'multipart/form-data', + }, + } + ); return response.data; } ); + export const getPurchaseTypeData = createAsyncThunk( 'product/getPurchaseTypeData', async () => { diff --git a/src/Pages/BookingScreen/Components/BSBillingTables/StandardTable/StandardTablePayment.jsx b/src/Pages/BookingScreen/Components/BSBillingTables/StandardTable/StandardTablePayment.jsx index 1c3f736..b2806c9 100644 --- a/src/Pages/BookingScreen/Components/BSBillingTables/StandardTable/StandardTablePayment.jsx +++ b/src/Pages/BookingScreen/Components/BSBillingTables/StandardTable/StandardTablePayment.jsx @@ -358,6 +358,7 @@ const StandardTablePayment = () => { const [creditCustomerOpen, setcreditCustomerOpen] = useState(false); const [Splitpayment, setSplitpayment] = useState(false); const [customerPreviesOrders, setCustomerPreviesOrders] = useState(false); + const paymentGatewayRef = React.useRef(null); const [PrintOrderDetails, setPrintOrderDetails] = useState([]); const [PaymentUpiOptions, setPaymentUpiOptions] = useState([]); const [PaymentDeviceCard, setPaymentDeviceCard] = useState([]); @@ -4125,6 +4126,7 @@ const StandardTablePayment = () => { children={ <> { open={showCancelConfirm} title="Cancel Payment" onOk={() => { + paymentGatewayRef.current?.clearPolling(); setBusinessUPI(false); setShowCancelConfirm(false); ClearAllGlobalStateDatas(); diff --git a/src/Pages/BookingScreen/Components/BookingFunctionality/FeaturesFunctionalities.jsx b/src/Pages/BookingScreen/Components/BookingFunctionality/FeaturesFunctionalities.jsx index ce5e6ca..2deb79f 100644 --- a/src/Pages/BookingScreen/Components/BookingFunctionality/FeaturesFunctionalities.jsx +++ b/src/Pages/BookingScreen/Components/BookingFunctionality/FeaturesFunctionalities.jsx @@ -18,6 +18,7 @@ import { Switch, Tooltip, Popconfirm, + Tabs, } from 'antd'; import { TiDelete } from 'react-icons/ti'; import { CiCalculator1 } from 'react-icons/ci'; @@ -171,6 +172,7 @@ const FeaturesFunctionalities = (props) => { const [WeightScale, setWeightScale] = useState(props.WeightScale); const [WeightScale2, setWeightScale2] = useState(true); + const [activeTab, setActiveTab] = useState('quickAdd'); const [CusDetails, setCusDetails] = useState(false); const [zipCodeData, setZipCodeData] = useState(false); const [messageType, setMessageType] = useState(null); @@ -3904,17 +3906,27 @@ const FeaturesFunctionalities = (props) => {
+ <> + + + } handleCancel={props.handleQuickAddCancel} /> diff --git a/src/Pages/BookingScreen/Components/OtherConponents/Reprint/BSReprint.jsx b/src/Pages/BookingScreen/Components/OtherConponents/Reprint/BSReprint.jsx index a1086e2..b2989ea 100644 --- a/src/Pages/BookingScreen/Components/OtherConponents/Reprint/BSReprint.jsx +++ b/src/Pages/BookingScreen/Components/OtherConponents/Reprint/BSReprint.jsx @@ -1269,6 +1269,7 @@ function BSReprint({ setOpenModel = () => { } }) { OverallDisc, OrderPaymentDtl, } = orderDtls; + const updated = productDetails?.map((item) => ({ ...item, Offer: item?.OfferAmt, diff --git a/src/Pages/BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx b/src/Pages/BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx index aeba81e..a72f095 100644 --- a/src/Pages/BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx +++ b/src/Pages/BookingScreen/Components/UtillComponents/PaymentGatewayEmbedded.jsx @@ -1,8 +1,8 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState, useImperativeHandle, forwardRef } from 'react'; import { useDispatch } from 'react-redux'; import { getPaymentStatusForBusinessUPI } from '../../../../Features/BookingScreen/BookingData/BookingData'; -const PaymentGatewayEmbedded = ({ +const PaymentGatewayEmbedded = forwardRef(({ orderId, businessUPILink, setBusinessUPI, @@ -12,12 +12,21 @@ const PaymentGatewayEmbedded = ({ ClearAllGlobalStateDatas = () => {}, CustomerDisplay = () => {}, Type=null -}) => { +}, ref) => { const dispatch = useDispatch(); const intervalRef = useRef(null); const [timedOut, setTimedOut] = useState(false); const [showTimeout, setShowTimeout] = useState(false); + useImperativeHandle(ref, () => ({ + clearPolling: () => { + if (intervalRef.current) { + clearInterval(intervalRef.current); + intervalRef.current = null; + } + } + })); + useEffect(() => { if (paymentSucess || timedOut) return; @@ -174,6 +183,6 @@ const PaymentGatewayEmbedded = ({ )} ); -}; +}); export default PaymentGatewayEmbedded; diff --git a/src/Pages/BookingScreen/Forms/QuickAdd/DirectSale.jsx b/src/Pages/BookingScreen/Forms/QuickAdd/DirectSale.jsx new file mode 100644 index 0000000..782e2e6 --- /dev/null +++ b/src/Pages/BookingScreen/Forms/QuickAdd/DirectSale.jsx @@ -0,0 +1,901 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { Table, Input, Select, Button } from 'antd'; +import { PlusOutlined, DeleteOutlined, SaveOutlined, PrinterOutlined } from '@ant-design/icons'; +import { Tables } from '../../../../Components/Tables/Table'; +import { useDispatch } from 'react-redux'; +import { postProductData, getDirectSaleProducts, getAllProductShortCodes, deleteProductData, getDirectSaleSearchedProduct } from '../../../../Features/ProductPage/ProductPage.js'; +import { getSession, printDiv } from '../../../../Services/Others'; +import { Messages } from '../../../../Components/Notifications/Messages.jsx'; +import { FaStarOfLife } from "react-icons/fa6"; +import { IoMdRefresh } from "react-icons/io"; +import StickerPrintModel from '../../../Product/StickerPrintModal.jsx'; +import { getPageStyle, style } from '../../../Product/Printstyles.js'; +import { getBarcodeSessionsIDs, getBarcodeTemplate } from '../../../../Features/Barcode/Barcode.js'; +import { generateBarcode, generateQRCode, generateQRCodeCopy } from '../../../../Services/utils.js'; +import StickerPrintTemplates from '../../../Product/StickerTemplates.jsx'; +import useBarcodeGenerator from './useBarcodeQRGenerator.js'; + +const DirectSale = ({ UomData = [], TaxData = [], ProductTypeData = [], ProdCatData = [], ProdSubCatData = [], SupplierData = [], activeTab = null }) => { + + const formRef = useRef(); + const tableRef = useRef(); + const searchInputRef = useRef(); + const dispatch = useDispatch(); + const [messageType, setMessageType] = useState(null); + const [messageData, setMessageData] = useState(null); + const [currentPage, setCurrentPage] = useState(1); + + const CompId = getSession('CompId'); + const BranchId = getSession('BranchId'); + const AppId = getSession('AppId'); + const UserId = getSession('UserId'); + + const [dataSource, setDataSource] = useState([]); + const [editingKey, setEditingKey] = useState(null); + + const [copies, setCopies] = useState(null); + const [dropdownValue, setDropdownValue] = useState(null); + const [multiProduct, setMultiProduct] = useState(false); + const [printReady, setPrintReady] = useState(false); + const [printProductName, setPrintProductName] = useState(false); + const [productShortCodes, setAllProductShortCodes] = useState([]); + const [searchText, setSearchText] = useState(''); + console.log(searchText, "searchText") + const [stickerPrintModalOpen, setStickerPrintModalOpen] = useState(false); + const [barcodeTemplateDetails, setBarcodeTemplateDetails] = useState([]); + const [filteredProducts, setFilteredProducts] = useState([]); + const [labelPrintData, setLabelPrintData] = useState(null); + const [prodId, setProdId] = useState(null); + const [nickName, setNickName] = useState(null); + const [crossData, setCrossData] = useState(null); + const [triggerState, setTriggerState] = useState(1); + const [templateOptions, setTemplateOptions] = useState({ + mrp: false, + barcode: false, + color: false, + eDate: false, + mDate: false, + sellingPrice: false, + productName: false, + value: '', + secondValue: '', + qrcode: false, + codeType: '', + }); + + console.log((searchText != null && searchText != ''), "filteredProducts") + + const { qrBase64, barcodeBase64 } = useBarcodeGenerator(prodId); + + const handleAdd = () => { + setDataSource([{ + key: dataSource.length + 1, + productName: '', + shortCode: '', + sellingPrice: '', + uom: null, + tax: null, + prodId: null, + size: null, + uomName: null, + activeStatus: 'A' + }, ...dataSource]); + }; + + const handleDelete = async (record) => { + if (record?.prodId) { + const deleteData = { + ProdId: record.prodId, + ActiveStatus: record.activeStatus === 'A' ? 'D' : 'A', + UpdatedBy: UserId, + }; + const response = await dispatch(deleteProductData(deleteData))?.unwrap(); + if (response?.data?.statusCode === 1) { + setMessageData(record.activeStatus === 'A' ? 'Product De-Activated Successfully' : 'Product Activated Successfully'); + setMessageType('success'); + await fetchDirectSaleProducts(); + } else { + setMessageData(response?.data?.response || 'Failed to update status'); + setMessageType('error'); + } + return; + } else { + // const { key } = record; + // setDataSource(dataSource.filter(item => item.key !== key)); + setMessageData('Atleast one empty row should be in table.'); + setMessageType('warning'); + } + + }; + + const handleChange = useCallback((key, field, value) => { + if (searchText) { + setFilteredProducts(prev => + prev.map(item => + item.key === key ? { ...item, [field]: value } : item + ) + ); + } else { + setDataSource(prev => + prev.map(item => + item.key === key ? { ...item, [field]: value } : item + ) + ); + } + }, [searchText]); + + const handleSave = async (record) => { + + if (!record.productName || !record.sellingPrice || !record.uom || !record.tax || !record?.shortCode) { + setMessageData('Please fill all the required fields!'); + setMessageType('warning'); + return; + } + + const exists = isShortCodeDuplicate(record?.shortCode, record?.prodId); + + if (exists) { + setMessageData('Short code already exists for another product'); + setMessageType('error'); + return; + } + + const postData = { + ProdName: record.productName, + Size: '1', + UOM: record.uom, + MRP: record.sellingPrice, + SellPrice: record.sellingPrice, + TaxId: record.tax, + CompId: CompId, + BranchId: BranchId, + AppId: AppId, + ProdType: ProductTypeData?.find(item => item.ConfigName === 'Product')?.ConfigId, + ProdCat: ProdCatData?.find(item => item.ConfigName === 'General')?.ConfigId, + ProdSubCat: ProdSubCatData?.find(item => item.ConfigName === 'General')?.ConfigId, + QtyBasedPrice: 'N', + ProdQtywisePriceDetails: [], + StockAvailable: 'N', + TokenAvailable: 'N', + InwardDate: new Date().toJSON(), + SuppId: SupplierData?.find(item => item.SuppName?.toLowerCase() === 'self')?.SuppId, + AutoGenerateQr: 'N', + QRCode: null, + CreatedBy: UserId, + ProdLogo: '', + Cess: 0, + ProdShortCode: record?.shortCode + }; + + try { + if (record?.prodId) { + console.log('Updating Product') + } else { + const response = await dispatch(postProductData(postData)).unwrap(); + if (response?.data?.statusCode === 1) { + const prodId = response?.data?.ProductDetails?.[0]?.ProdId; + const size = response?.data?.ProductDetails?.[0]?.Size; + const uomName = response?.data?.ProductDetails?.[0]?.UomName; + const totalProducts = response?.data?.ProductDetails?.[0]?.TotalCount; + setSearchText(currentSearchText => { + if (currentSearchText != null && currentSearchText !== '') { + setCurrentPage(1); + setTriggerState(prev => prev + 1); + if (searchInputRef.current) { + searchInputRef.current.value = ''; + } + return ''; + } else { + setDataSource(prev => prev.map(item => + item.key === record.key ? { ...item, prodId, size, uomName, totalProducts } : { ...item, totalProducts } + )); + } + return currentSearchText; + }); + setMessageData('Product saved successfully!'); + setMessageType('success'); + return; + } + } + + } catch (error) { + console.error('Error saving product:', error); + } + }; + + const handlePrint = async (record) => { + const exists = isShortCodeDuplicate(record?.shortCode, record?.prodId); + if (exists) { + setMessageData('Short code already exists for another product. Cannot print.'); + setMessageType('error'); + return; + } + setStickerPrintModalOpen(true); + setLabelPrintData({ ...record, MRP: record?.sellingPrice || 0, SellPrice: record?.sellingPrice || 0 }); + setProdId(record?.shortCode + '' + record?.sellingPrice) + } + + const columns = useMemo(() => [ + { + title: 'SL.No', + width: 50, + align: 'center', + render: (_, __, index) => (currentPage - 1) * 10 + index + 1 + }, + { + title: () =>
Product Name + + + +
, + dataIndex: 'productName', + width: 150, + render: (text, record) => ( + record.prodId && editingKey !== record.key ? +
{text}
: + handleChange(record.key, 'productName', e.target.value)} + placeholder="Enter product name" + /> + ) + }, + { + title: () =>
Short Code + + + +
, + dataIndex: 'shortCode', + width: 100, + render: (text, record) => ( + record.prodId && editingKey !== record.key ? +
{text}
: + { + const originalValue = e.target.value; + const hasNonAlpha = /[^a-zA-Z]/.test(originalValue); + if (hasNonAlpha) { + setMessageData('Enter Alphabet Characters only'); + setMessageType('warning'); + } + }} + onChange={(e) => { + const value = e.target.value.replace(/[^a-zA-Z]/g, '').toUpperCase(); + const exists = isShortCodeDuplicate(value, record?.prodId); + if (exists && value) { + setMessageData('Short code already exists for another product'); + setMessageType('error'); + } + handleChange(record.key, 'shortCode', value); + }} + placeholder="Short Code" + /> + ) + }, + { + title: () =>
Selling Price + + + +
, + dataIndex: 'sellingPrice', + width: 120, + render: (text, record) => ( + record.prodId && editingKey !== record.key ? +
{text}
: + { + const value = e.target.value.replace(/[^0-9.]/g, ''); + const parts = value.split('.'); + const formatted = parts.length > 2 ? `${parts[0]}.${parts.slice(1).join('')}` : value; + handleChange(record.key, 'sellingPrice', formatted); + }} + placeholder="0.00" + /> + ) + }, + { + title: () =>
UOM + + + +
, + dataIndex: 'uom', + width: 60, + render: (text, record) => ( + record.prodId && editingKey !== record.key ? +
{UomData?.find(item => item.ConfigId === text)?.ConfigName || '-'}
: + handleChange(record.key, 'tax', value)} + placeholder="Tax" + style={{ width: '100%' }} + options={TaxData?.map(item => ({ + value: item.TaxId, + label: `${item.TaxIdName} - ${item.TaxPercentage}%` + }))} + /> + ); + } + }, + { + title: 'Save / Print', + width: 90, + align: 'center', + render: (_, record) => { + const existingProduct = record?.prodId; + + return ( +
+ {!existingProduct && } + {existingProduct && } +
+ ); + } + }, + { + title: 'Action', + width: 60, + align: "center", + render: (_, record) => { + if (record?.activeStatus === 'A') { + return handleDelete(record)} + style={{ color: 'red', cursor: 'pointer', fontSize: '18px' }} + /> + } else { + return handleDelete(record)} + /> + } + + } + } + ], [ + searchText, + editingKey, + productShortCodes, + UomData, + TaxData + ]); + + useEffect(() => { + if (activeTab === 'directSale' && AppId && CompId && BranchId) { + fetchDirectSaleProducts(); + fetchAllProductShortCodes(); + } + }, [activeTab, AppId, BranchId, CompId, currentPage, triggerState]); + + useEffect(() => { + if (dataSource.every(row => row.prodId)) { + handleAdd(); + } + }, [dataSource]); + + useEffect(() => { + const timer = setTimeout(() => { + if (searchText) { + fetchSearchedProducts(); + } else { + setFilteredProducts([{ + key: 1, + productName: '', + shortCode: '', + sellingPrice: '', + uom: null, + tax: null, + prodId: null, + size: null, + uomName: null, + activeStatus: 'A' + }]); + } + }, 500); + + return () => clearTimeout(timer); + }, [searchText, AppId, BranchId, CompId]); + + useEffect(() => { + const handleClickOutside = (event) => { + if (tableRef.current && !tableRef.current.contains(event.target) && !event.target.closest('.ant-select-dropdown')) { + setEditingKey(null); + } + }; + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + + useEffect(() => { + if (activeTab === 'directSale' && AppId && CompId && BranchId && stickerPrintModalOpen) { + getBarcodeSessionData(); + fetchBarcodeTemplateDetails(); + } + }, [activeTab, AppId, BranchId, CompId, stickerPrintModalOpen]); + + const fetchSearchedProducts = async () => { + try { + const data = { + AppId: AppId, + CompId: CompId, + BranchId: BranchId, + prodName: searchText + } + const response = await dispatch(getDirectSaleSearchedProduct(data))?.unwrap(); + if (response?.data?.data?.length > 0 && response?.data?.statusCode === 1) { + const products = response?.data?.data?.map((item, index) => ({ + key: index + 1, + productName: item.ProdName, + shortCode: item.ProdShortCode, + sellingPrice: item.SellPrice, + uom: item.UOM, + tax: item.TaxId, + prodId: item.ProdId, + activeStatus: item?.ActiveStatus, + size: item.Size || 1, + uomName: item.UomName || 'PCS', + totalProducts: item?.TotalCount + })) + setFilteredProducts([{ + key: products.length + 1, + productName: '', + shortCode: '', + sellingPrice: '', + uom: null, + tax: null, + prodId: null, + size: null, + uomName: null, + activeStatus: 'A' + }, ...products]); + } else { + setFilteredProducts([{ + key: 1, + productName: '', + shortCode: '', + sellingPrice: '', + uom: null, + tax: null, + prodId: null, + size: null, + uomName: null, + activeStatus: 'A' + }]); + } + } catch (error) { + console.error(error?.message) + } + + } + + const isShortCodeDuplicate = useCallback((code, prodId) => { + return productShortCodes.some( + item => + item.ProdShortCode.toUpperCase() === code.toUpperCase() && + item.ProdId !== prodId + ); + }, [productShortCodes]); + + const fetchBarcodeTemplateDetails = async () => { + const response = await dispatch( + getBarcodeTemplate({ compId: CompId, appId: AppId, branchId: BranchId }) + ).unwrap(); + if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) { + const { TemplateDetails } = response?.data?.data?.[0]; + setBarcodeTemplateDetails(TemplateDetails); + } else { + setBarcodeTemplateDetails([]); + } + }; + + const getBarcodeSessionData = async () => { + try { + let response = await dispatch(getBarcodeSessionsIDs()).unwrap(); + if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) { + setCrossData( + response?.data?.data?.filter( + (item) => !item.ConfigName?.includes('100X13 (55MM Printable Gold)') + ) || [] + ); + } else { + setCrossData([]); + } + } catch (error) { + console.error('Error fetching barcode session data:', error); + } + }; + + const fetchDirectSaleProducts = async () => { + try { + const data = { + AppId: AppId, + CompId: CompId, + BranchId: BranchId, + page: currentPage + } + + const response = await dispatch(getDirectSaleProducts(data))?.unwrap(); + if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) { + const products = response?.data?.data?.map((item, index) => ({ + key: index + 1, + productName: item.ProdName, + shortCode: item.ProdShortCode, + sellingPrice: item.SellPrice, + uom: item.UOM, + tax: item.TaxId, + prodId: item.ProdId, + activeStatus: item?.ActiveStatus, + size: item.Size || 1, + uomName: item.UomName || 'PCS', + totalProducts: item?.TotalCount + })); + setDataSource([{ + key: products.length + 1, + productName: '', + shortCode: '', + sellingPrice: '', + uom: null, + tax: null, + prodId: null, + size: null, + uomName: null, + activeStatus: 'A' + }, ...products]); + } else { + setDataSource([]) + } + + } catch (error) { + console.error('Error fetching direct sale products:', error); + } + } + + const fetchAllProductShortCodes = async () => { + try { + const data = { + AppId: AppId, + CompId: CompId, + BranchId: BranchId, + } + + const response = await dispatch(getAllProductShortCodes(data))?.unwrap(); + if (response?.data?.statusCode === 1 && response?.data?.data?.length > 0) { + setAllProductShortCodes(response?.data?.data); + } else { + setAllProductShortCodes([]); + } + + console.log(response); + + } catch (error) { + console.error('Error fetching product short codes:', error); + } + } + + const handlePageChange = (current) => { + setCurrentPage(current); + }; + + const onFinish = async () => { + const template = barcodeTemplateDetails?.find( + (find) => find.SessionName === dropdownValue + ); + const templateAvailable = template === undefined ? false : true; + + if (templateAvailable) { + const checkComponent = (name) => + template?.OptionDetails?.some((some) => some.OptionName === name); + const mrp = checkComponent('MRP'); + const barcode = checkComponent('Barcode'); + const color = checkComponent('Color'); + const eDate = checkComponent('E Date'); + const mDate = checkComponent('M Date'); + const sellingPrice = checkComponent('Selling Price'); + const productName = checkComponent('Product Name'); + const qrcode = checkComponent('Qrcode'); + const position = template.Position !== '' ? template.Position : ''; + const positionString = + template.PositionString !== '' ? template.PositionString : ''; + + setTemplateOptions({ + mrp: mrp, + barcode: barcode, + color: color, + eDate: eDate, + mDate: mDate, + sellingPrice: sellingPrice, + productName: productName, + value: position, + secondValue: positionString, + qrcode: qrcode, + codeType: template?.CodeType, + }); + } + + setPrintReady(true); + + setTimeout(async () => { + switch (dropdownValue) { + case '15X15 6cross': // COMPLETE + await printDiv( + templateAvailable ? 'label-15X156cross' : 'StickerPrints0', + style + getPageStyle(92) + ); + handleModalClose(); + break; + case '22X35 3cross': // Need to check + await printDiv( + templateAvailable ? '22X353cross' : 'StickerPrints1', + style + getPageStyle(105) + ); + handleModalClose(); + break; + case '25X25 4cross': // COMPLETE + await printDiv( + templateAvailable ? '25X254cross' : 'StickerPrints2', + style + getPageStyle(100) + ); + handleModalClose(); + break; + case '25X50 2cross': //Need to check + await printDiv( + templateAvailable ? '25X502cross' : 'StickerPrints3', + style + getPageStyle(100) + ); + handleModalClose(); + break; + case '50X30 Single': // COMPLETE + await printDiv( + templateAvailable ? '50X30Single' : 'StickerPrints4', + style + ); + handleModalClose(); + break; + case '50X25 Single': // COMPLETE + await printDiv( + templateAvailable ? '50X25Single' : 'StickerPrints5', + style + ); + handleModalClose(); + break; + case '100X13 (55MM Printable)': //Need to check + await printDiv( + templateAvailable ? '100X13(55MMPrintable)' : 'StickerPrints6', + style + ); + handleModalClose(); + break; + case '100X15 (70MM Printable)': // COMPLETE + await printDiv( + templateAvailable ? '100X15(70MMPrintable)' : 'StickerPrints7', + style + ); + handleModalClose(); + break; + case '100X150': // COMPLETE + await printDiv( + templateAvailable ? '100X150' : 'StickerPrints8', + style + ); + handleModalClose(); + setPrintReady(false); + break; + default: + alert('! Select correct cross '); + setPrintReady(false); + } + }, 100); + }; + + const CoresOnChange = (params) => { + setDropdownValue(params); + formRef.current?.setFieldsValue({ Cross: params }); + const template = barcodeTemplateDetails?.find( + (find) => find.SessionName === params + ); + const checkComponent = (name) => + template?.OptionDetails?.some((some) => some.OptionName === name); + const productName = checkComponent('Product Name'); + setPrintProductName(productName); + }; + + const CopiesOnChange = (params) => { + setCopies(params); + formRef.current?.setFieldsValue({ Copies: params }); + }; + + const handleModalClose = () => { + setCopies(null) + setDropdownValue('') + setStickerPrintModalOpen(false); + setLabelPrintData(null); + setNickName(null); + setProdId(null) + setMultiProduct(false); + formRef?.current?.resetFields(); + setPrintReady(false); + }; + + const imageTagBarcodeAndQR = useCallback( + (w = 'auto', fs = '6px', codeData = null) => { + const currentCode = codeData || prodId; + return ( + (templateOptions.barcode || templateOptions.qrcode) && ( + <> + Barcode + {templateOptions.codeType !== 'B' && ( +

+ {currentCode} +

+ )} + + ) + ); + }, + [templateOptions, multiProduct, barcodeBase64, qrBase64, prodId] + ); + + const onComplete = useCallback(() => { + setMessageType(null); + setMessageData(null); + }, []); + + return ( +
+ +
+ setSearchText(e.target.value)} + /> +
+
+ Note: Click on a row to modify the product details +
+
+ ({ + onClick: () => record.prodId && setEditingKey(record.key) + })} + ownPagination={true} + pagination={{ + current: currentPage, + onChange: handlePageChange, + total: (searchText != null && searchText != '') ? filteredProducts?.length : ((dataSource[dataSource.length - 1]?.totalProducts || 0) + 1), + pageSize: 11, + showSizeChanger: false, + hideOnSinglePage: true, + }} + bordered + /> +
+ + {stickerPrintModalOpen && { }} + selectedRecords={null} + coresdata={crossData} + dropdownValue={dropdownValue} + CoresOnChange={CoresOnChange} + barcodeTemplateDetails={barcodeTemplateDetails} + detail={labelPrintData} + proName={labelPrintData?.productName} + nickName={nickName} + ProdId={labelPrintData?.shortCode + '' + labelPrintData?.sellingPrice} + size={labelPrintData?.size} + // valueStyleColumn={valueStyleColumn} + // secondValueStyle={secondValueStyle} + // valueStyleRow={valueStyleRow} + CopiesOnChange={CopiesOnChange} + printProductName={printProductName} + totalCopies={null} + setstockWiseQrcode={null} + setProductWiseQrcode={null} + setNickName={setNickName} + templateOptions={templateOptions} + />} + + {printReady && ( + + generateQRCodeCopy(null, code) + } + generateCodeImage={(code, codeType = 'Q') => generateCodeImage(code, codeType, null)} + imageTagBarcodeAndQR={imageTagBarcodeAndQR} + dropdownValue={dropdownValue} + barcodeTemplateDetails={barcodeTemplateDetails} + /> + )} +
+ ); +}; + +export default DirectSale; \ No newline at end of file diff --git a/src/Pages/BookingScreen/Forms/QuickAdd/QuickAdd.jsx b/src/Pages/BookingScreen/Forms/QuickAdd/QuickAdd.jsx index 244dfd7..b20947e 100644 --- a/src/Pages/BookingScreen/Forms/QuickAdd/QuickAdd.jsx +++ b/src/Pages/BookingScreen/Forms/QuickAdd/QuickAdd.jsx @@ -1,6 +1,7 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { Form, Tooltip } from 'antd'; +import { Form, Tooltip, Tabs } from 'antd'; +import DirectSale from './DirectSale.jsx'; import { ArrowRightOutlined, PlusCircleOutlined, @@ -13,7 +14,7 @@ import { Messages } from '../../../../Components/Notifications/Messages'; import { DropDowns } from '../../../../Components/Forms/DropDown.jsx'; import { DatePic } from '../../../../Components/Forms/DatePicker.jsx'; import { DefaultModal } from '../../../../Components/Modal/DefaultModal.jsx'; -import FormHeader from '../../../PageComponents/FormHeader.jsx'; + import { getSession, validateSafeInput } from '../../../../Services/Others'; import { getAdmin, @@ -61,6 +62,7 @@ const ProductForm = ({ ProductSearch, ProductSearchType, cardData, + activeTab = null }) => { const dispatch = useDispatch(); const formRef = useRef(null); @@ -116,6 +118,7 @@ const ProductForm = ({ const [tempSelectedColumns, setTempSelectedColumns] = useState([]); const [tableFieldPreferences, setTableFieldPreferences] = useState([]); const [selectedFields, setSelectedFields] = useState([]); + console.log(selectedAdditionalColumn, "selectedAdditionalColumn") console.log(tempSelectedColumns, "tempSelectedColumns") const CompId = getSession('CompId'); @@ -515,367 +518,286 @@ const ProductForm = ({ messageData={messageData} onComplete={onComplete} /> -
- -
-
-
{ - setTempSelectedColumns([...selectedAdditionalColumn]); - setShowColumnModal(true); - }}> - - {/* Additional Fields */} - { - setTempSelectedColumns([...selectedAdditionalColumn]); - setShowColumnModal(true); - }} - style={{ cursor: 'pointer', fontSize: '20px' }} - /> - -
+ {activeTab === 'directSale' ? ( + + ) : ( +
-
-
-
-
- {ProductSearch &&
Qrcode : {ProductSearchValue}
} +
{ + setTempSelectedColumns([...selectedAdditionalColumn]); + setShowColumnModal(true); + }}> + + {/* Additional Fields */} + { + setTempSelectedColumns([...selectedAdditionalColumn]); + setShowColumnModal(true); + }} + style={{ cursor: 'pointer', fontSize: '20px' }} + /> + +
-
- { - await validateSafeInput(value); + +
+
+
+ {ProductSearch &&
Qrcode : {ProductSearchValue}
} - if (value && value.length > 50) { - return Promise.reject( - 'Product Name should not exceed 50 characters' - ); - } - - return Promise.resolve(); - }, - }, - ]} - > - Product Name} - isOnChange={cardData?.length === 1} - /> - - { - await validateSafeInput(value); - if (value && value.length > 10) { - return Promise.reject( - 'No.of.Units should not exceed 10 characters' - ); - } - - return Promise.resolve(); - }, - }, - ]} - > - No.of.Units} - // inputMode="decimal" - isOnChange={cardData?.length === 1} - // onInput={(e) => { - // const cleanedValue = e.target.value.replace( - // /[^0-9.]/g, - // "" - // ); - // const parts = cleanedValue.split("."); - // e.target.value = - // parts.length > 2 - // ? `${parts[0]}.${parts.slice(1).join("")}` - // : cleanedValue; - // }} - suffix={ - -
Enter No.of.Units as:
-
- - Single number (5) -
-
- - Decimal (1.500 or 1.5) -
-
- - Width x Height (10x10) -
- - } - > - -
- } - /> -
- - ({ - value: option.ConfigId, - label: option.ConfigName, - }))} - label={} - className="field-DropDown" - isOnchanges={SelectedUom ? true : false} - onChangeFunction={handleUomDropDownChange} - valueData={SelectedUom} - disabled={formType == 'edit' ? true : false} - /> - - { - await validateSafeInput(value); - - if (value && value.length > 10) { - return Promise.reject( - 'MRP should not exceed 10 characters' - ); - } - - return Promise.resolve(); - }, - }, - ]} - > - MRP} - inputMode="decimal" - onInput={(e) => { - const cleanedValue = e.target.value?.replace( - /[^0-9.]/g, - '' - ); - const parts = cleanedValue.split('.'); - e.target.value = - parts.length > 2 - ? `${parts[0]}.${parts.slice(1).join('')}` - : cleanedValue; - }} - /> - - - Sales Price} - inputMode="decimal" - onInput={(e) => { - const cleanedValue = e.target.value?.replace( - /[^0-9.]/g, - '' - ); - const parts = cleanedValue.split('.'); - e.target.value = - parts.length > 2 - ? `${parts[0]}.${parts.slice(1).join('')}` - : cleanedValue; - }} - /> - - {cardData?.length === 1 && ( +
{ await validateSafeInput(value); + + if (value && value.length > 50) { + return Promise.reject( + 'Product Name should not exceed 50 characters' + ); + } + + return Promise.resolve(); }, }, ]} > Product Name} isOnChange={cardData?.length === 1} - label={} /> - )} - {cardData?.length === 1 && ( -
-

Upload Icon

-

- -
- )} + { + await validateSafeInput(value); + if (value && value.length > 10) { + return Promise.reject( + 'No.of.Units should not exceed 10 characters' + ); + } - {true && ( - <> - {(taxField && selectedAdditionalColumn?.includes('Tax')) && - - ({ - value: option.TaxId, - label: getOptionLabel( - option, - SelectedTaxId === option.TaxId - ), - // label: option.TaxIdName + ' - ' + option.TaxPercentage + ' % ', - }))} - label="Tax" - className="field-DropDown" - isOnchanges={SelectedTaxId ? true : false} - onChangeFunction={handleTaxDropDownChange} - valueData={SelectedTaxId} - /> - - } - {(taxField && selectedAdditionalColumn?.includes('Tax')) && - - - + return Promise.resolve(); + }, + }, + ]} + > + No.of.Units} + // inputMode="decimal" + isOnChange={cardData?.length === 1} + // onInput={(e) => { + // const cleanedValue = e.target.value.replace( + // /[^0-9.]/g, + // "" + // ); + // const parts = cleanedValue.split("."); + // e.target.value = + // parts.length > 2 + // ? `${parts[0]}.${parts.slice(1).join("")}` + // : cleanedValue; + // }} + suffix={ + +
Enter No.of.Units as:
+
+ - Single number (5) +
+
+ - Decimal (1.500 or 1.5) +
+
+ - Width x Height (10x10) +
+ + } + > +
-
} + } + /> +
+ + ({ + value: option.ConfigId, + label: option.ConfigName, + }))} + label={} + className="field-DropDown" + isOnchanges={SelectedUom ? true : false} + onChangeFunction={handleUomDropDownChange} + valueData={SelectedUom} + disabled={formType == 'edit' ? true : false} + /> + + { + await validateSafeInput(value); - {(cessField && selectedAdditionalColumn?.includes('Cess')) && 10) { + return Promise.reject( + 'MRP should not exceed 10 characters' + ); + } + + return Promise.resolve(); + }, + }, + ]} + > + MRP} + inputMode="decimal" + onInput={(e) => { + const cleanedValue = e.target.value?.replace( + /[^0-9.]/g, + '' + ); + const parts = cleanedValue.split('.'); + e.target.value = + parts.length > 2 + ? `${parts[0]}.${parts.slice(1).join('')}` + : cleanedValue; + }} + /> + + + Sales Price} + inputMode="decimal" + onInput={(e) => { + const cleanedValue = e.target.value?.replace( + /[^0-9.]/g, + '' + ); + const parts = cleanedValue.split('.'); + e.target.value = + parts.length > 2 + ? `${parts[0]}.${parts.slice(1).join('')}` + : cleanedValue; + }} + /> + + {cardData?.length === 1 && ( + { - await validateSafeInput(value); // To block HTML tags & SQL keywords - return Promise.resolve(); + await validateSafeInput(value); }, }, ]} > - - } + Brand} + /> + + )} + {cardData?.length === 1 && ( +
+

Upload Icon

+

+ +
+ )} - {(hsnField && selectedAdditionalColumn?.includes('Hsn Code')) && - + {(taxField && selectedAdditionalColumn?.includes('Tax')) && + + ({ + value: option.TaxId, + label: getOptionLabel( + option, + SelectedTaxId === option.TaxId + ), + // label: option.TaxIdName + ' - ' + option.TaxPercentage + ' % ', + }))} + label="Tax" + className="field-DropDown" + isOnchanges={SelectedTaxId ? true : false} + onChangeFunction={handleTaxDropDownChange} + valueData={SelectedTaxId} + /> + + } + {(taxField && selectedAdditionalColumn?.includes('Tax')) && + + + + + } + + {(cessField && selectedAdditionalColumn?.includes('Cess')) && - HSN Code} - id="HSNCode" - value={selectedHsn} - type="text" - list="hsnList" - maxLength={100} - autoComplete="off" - isOnChange={selectedHsn ? true : false} - onChange={(e) => { - const value = e?.target?.value || ""; - setSelectedHsn(value); - if (value.length >= 1) { - formRef.current?.setFieldsValue({ - HSNCode: value, - }); - handleHsnData(value); - } - }} - - suffix={ - selectedHsn?.length >= 1 ? ( - setSelectedHsn("")} /> - ) : ( -
- ) - } - /> - {HsnDetails?.length > 0 && ( - - {HsnDetails - .filter((item) => { - const search = selectedHsn?.toLowerCase() || ""; - return ( - item.HSN_CD?.toLowerCase()?.includes(search) || - item.Description?.toLowerCase()?.includes(search) - ); - }) - .map((item, index) => ( - - )} - - - - } - - - {selectedAdditionalColumn?.includes('WholeSale') && - { @@ -885,161 +807,252 @@ const ProductForm = ({ }, ]} > - WholeSale} - /> - - } - - )} -
- {/*
+ + } + + {(hsnField && selectedAdditionalColumn?.includes('Hsn Code')) && + + HSN Code} + id="HSNCode" + value={selectedHsn} + type="text" + list="hsnList" + maxLength={100} + autoComplete="off" + isOnChange={selectedHsn ? true : false} + onChange={(e) => { + const value = e?.target?.value || ""; + setSelectedHsn(value); + if (value.length >= 1) { + formRef.current?.setFieldsValue({ + HSNCode: value, + }); + handleHsnData(value); + } + }} + + suffix={ + selectedHsn?.length >= 1 ? ( + setSelectedHsn("")} /> + ) : ( +
+ ) + } + /> + {HsnDetails?.length > 0 && ( + + {HsnDetails + .filter((item) => { + const search = selectedHsn?.toLowerCase() || ""; + return ( + item.HSN_CD?.toLowerCase()?.includes(search) || + item.Description?.toLowerCase()?.includes(search) + ); + }) + .map((item, index) => ( + + )} + + + + } + + + {selectedAdditionalColumn?.includes('WholeSale') && + { + await validateSafeInput(value); // To block HTML tags & SQL keywords + return Promise.resolve(); + }, + }, + ]} + > + WholeSale} + /> + + } + + )} +
+ {/*
Additional Details
*/} +
+
+
+ } + htmlType={true} + />
-
- } - htmlType={true} - /> -
-
- - - -
- - ({ - value: option.ConfigId, - label: option.ConfigName, - }))} - label="Tax Name" - className="field-DropDown" - onChangeFunction={handleTaxNameDropDownChange} - valueData={SelectedTaxNameId} - /> - - { - await validateSafeInput(value); // To block HTML tags & SQL keywords - return Promise.resolve(); - }, - }, - ]} - > - - - - { - await validateSafeInput(value); // To block HTML tags & SQL keywords - return Promise.resolve(); - }, - }, - ]} - > - - -
- + + +
+ + ({ + value: option.ConfigId, + label: option.ConfigName, + }))} + label="Tax Name" + className="field-DropDown" + onChangeFunction={handleTaxNameDropDownChange} + valueData={SelectedTaxNameId} + /> + { + await validateSafeInput(value); // To block HTML tags & SQL keywords + return Promise.resolve(); + }, }, ]} > - + + + { + await validateSafeInput(value); // To block HTML tags & SQL keywords + return Promise.resolve(); + }, + }, + ]} + > + + +
+ + + + + +
-
- - } - handleSubmit={submitTax} - handleCancel={handleTax} - > + + } + handleSubmit={submitTax} + handleCancel={handleTax} + > - { - setShowColumnModal(false); - setSelectedFields([...selectedAdditionalColumn.map(col => - tableFieldPreferences?.find(pref => pref.label === col)?.value - ).filter(Boolean)]); - setTempSelectedColumns([...selectedAdditionalColumn]); - }} - > -
- {tableFieldPreferences?.map((option) => ( -
- -
- ))} -
-
+ { + setShowColumnModal(false); + setSelectedFields([...selectedAdditionalColumn.map(col => + tableFieldPreferences?.find(pref => pref.label === col)?.value + ).filter(Boolean)]); + setTempSelectedColumns([...selectedAdditionalColumn]); + }} + > +
+ {tableFieldPreferences?.map((option) => ( +
+ +
+ ))} +
+
-
+
+ )}
); }; diff --git a/src/Pages/BookingScreen/Forms/QuickAdd/useBarcodeQRGenerator.js b/src/Pages/BookingScreen/Forms/QuickAdd/useBarcodeQRGenerator.js new file mode 100644 index 0000000..0fd53d5 --- /dev/null +++ b/src/Pages/BookingScreen/Forms/QuickAdd/useBarcodeQRGenerator.js @@ -0,0 +1,69 @@ +import { useEffect, useState } from 'react'; +import QRCode from 'qrcode'; +import JsBarcode from 'jsbarcode'; + +const useBarcodeGenerator = (code) => { + const [qrBase64, setQrBase64] = useState(null); + const [barcodeBase64, setBarcodeBase64] = useState(null); + + useEffect(() => { + if (!code) { + setQrBase64(null); + return; + } + + const generateQR = async () => { + try { + const url = await QRCode.toDataURL(code); + setQrBase64(url); + } catch (error) { + console.error('QR generation error:', error); + } + }; + + generateQR(); + }, [code]); + + useEffect(() => { + if (!code) { + setBarcodeBase64(null); + return; + } + + try { + const svg = document.createElementNS( + 'http://www.w3.org/2000/svg', + 'svg' + ); + + JsBarcode(svg, code, { + format: 'CODE128', + displayValue: true, + lineColor: '#000', + width: 2, + height: 50, + }); + + const svgData = new XMLSerializer().serializeToString(svg); + const svgBlob = new Blob([svgData], { + type: 'image/svg+xml;charset=utf-8', + }); + + const reader = new FileReader(); + reader.onloadend = () => { + setBarcodeBase64(reader.result); + }; + + reader.readAsDataURL(svgBlob); + } catch (error) { + console.error('Barcode generation error:', error); + } + }, [code]); + + return { + qrBase64, + barcodeBase64 + }; +}; + +export default useBarcodeGenerator; diff --git a/src/Pages/Product/StickerPrintModal.jsx b/src/Pages/Product/StickerPrintModal.jsx index b9fd032..970fae2 100644 --- a/src/Pages/Product/StickerPrintModal.jsx +++ b/src/Pages/Product/StickerPrintModal.jsx @@ -87,7 +87,7 @@ const StickerPrintModel = ({ if (coresdata?.length > 0 && open) { CoresOnChange(coresdata?.[0].ConfigName); } - }, [open]); + }, [open, coresdata]); return ( { }, }) => { + + const AppId = getSession('AppId'); + const CompId = getSession('CompId'); + const BranchId = getSession('BranchId'); + const extractedTableRef = useRef(null); const [form] = Form.useForm(); const [ocrLoading, setOcrLoading] = useState(false); @@ -503,7 +509,7 @@ const InvoiceImageExtractorModal = ({ const [productTableData, setProductTableData] = useState([]); const [TotalAmtData, SetTotalAmtData] = useState(0); const [SupplierData, setSupplierData] = useState([]); - console.log(form?.getFieldsValue(), 'SupplierData', SupplierData); + console.log(form?.getFieldsValue(), 'productTableData', productTableData); const [showPreviewModal, setShowPreviewModal] = useState(false); const [processedImages, setProcessedImages] = useState(new Set()); const [uploadMoreVisible, setUploadMoreVisible] = useState(false); @@ -716,8 +722,14 @@ const InvoiceImageExtractorModal = ({ setProcessingStep('Processing image…'); try { + const data = { + file: fileToProcess, + AppId, + CompId, + BranchId + } const response = await dispatch( - getInvoiceImageData(fileToProcess) + getInvoiceImageData(data) ).unwrap(); if (response?.data?.length > 0 && response?.statusCode === 1) { console.log('OCR API Response:', response); @@ -762,19 +774,38 @@ const InvoiceImageExtractorModal = ({ if (data.products?.length) { const mergedProducts = [...productTableData]; + data.products.forEach((p) => { const exists = mergedProducts.some( (x) => x.description === p.description && x.rate === p.rate ); if (!exists) mergedProducts.push(p); }); - setProductTableData( - mergedProducts?.map((item, index) => ({ + + // Sort Y first, then N + const sortedData = [...mergedProducts] + .sort((a, b) => { + if (a?.type === b?.type) return 0; + return a?.type === 'N' ? -1 : 1; + }) + .map((item, index) => ({ ...item, srNo: index + 1, - image: item?.image ? item?.image : (uploadImgData?.data?.status ? uploadImgData?.data?.image : null), - })) - ); + image: item?.image + ? item?.image + : uploadImgData?.data?.status + ? uploadImgData?.data?.image + : null, + })); + + setProductTableData(sortedData); + // setProductTableData( + // mergedProducts?.map((item, index) => ({ + // ...item, + // srNo: index + 1, + // image: item?.image ? item?.image : (uploadImgData?.data?.status ? uploadImgData?.data?.image : null), + // })) + // ); SetTotalAmtData( mergedProducts.reduce( (sum, item) => @@ -1012,6 +1043,7 @@ const InvoiceImageExtractorModal = ({ cursor: 'pointer', color: '#1292ee', marginBottom: '10px', + fontFamily: 'Poppins' }} onClick={() => setIsEditMode(true)} > @@ -1151,9 +1183,21 @@ const InvoiceImageExtractorModal = ({
Note: Click on a row to edit the data
+
+
+ + Product exists in list +
+ +
+ + Product not found in list +
+
+
`product-extractor-table ${record.type === 'N' ? 'not-added' : 'added'}`} columns={columns} data={productTableData} onRow={(record) => ({ diff --git a/src/Pages/StockMaster/StockForm.jsx b/src/Pages/StockMaster/StockForm.jsx index 2e85a1b..131f352 100644 --- a/src/Pages/StockMaster/StockForm.jsx +++ b/src/Pages/StockMaster/StockForm.jsx @@ -628,6 +628,7 @@ const StockForm = ({ formType }) => { const unmatchedProducts = matchedProducts.filter( (item) => !item.matchFound ); + if (unmatchedProducts?.length > 0) { setLoadingText('Mapping unmatched products...'); const response = await dispatch( @@ -704,7 +705,7 @@ const StockForm = ({ formType }) => { })); const bulkResponse = await dispatch( - bulkpostdata({ ProdDetails: newProductsData }) + bulkpostdata({ UploadType: 'Purchase', ProdDetails: newProductsData }) ).unwrap(); if (bulkResponse?.data?.statusCode === 1) { diff --git a/src/Styles/Product/Product.scss b/src/Styles/Product/Product.scss index 5384537..9b8beb3 100644 --- a/src/Styles/Product/Product.scss +++ b/src/Styles/Product/Product.scss @@ -1,16 +1,9 @@ .cropUploadFieldSmall { - :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper - .ant-upload-list.ant-upload-list-picture-card - .ant-upload-list-item-container, - :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper - .ant-upload-list.ant-upload-list-picture-card - .ant-upload-list-item-container, - :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper - .ant-upload-list.ant-upload-list-picture-circle - .ant-upload-list-item-container, - :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper - .ant-upload-list.ant-upload-list-picture-circle - .ant-upload-list-item-container { + + :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container, + :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container, + :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container, + :where(.css-dev-only-do-not-override-1v5z42l).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container { width: 65px; height: 65px; } @@ -326,14 +319,14 @@ } .viewerExcelupload .ant-table-wrapper, -.viewerExcelupload .ant-table-tbody > tr.ant-table-row > td { +.viewerExcelupload .ant-table-tbody>tr.ant-table-row>td { padding: 4px; font-size: 14px; font-weight: 600; } .viewerExcelupload .ant-table-wrapper, -.viewerExcelupload .ant-table-thead > tr > th { +.viewerExcelupload .ant-table-thead>tr>th { padding: 1px 8px !important; } @@ -388,7 +381,7 @@ } .productinputForm { - .ant-input-affix-wrapper > input.ant-input { + .ant-input-affix-wrapper>input.ant-input { padding-top: 1.5rem; } } @@ -442,7 +435,7 @@ } .product-Add-HSN { - .ant-input-affix-wrapper > input.ant-input { + .ant-input-affix-wrapper>input.ant-input { padding: 12px 0 0 0 !important; } } @@ -480,6 +473,7 @@ .ant-form-item { margin-bottom: 0; } + .ant-input { padding: 4px 14px 6px 11px !important; text-decoration: underline; @@ -504,9 +498,110 @@ width: 100%; display: flex; justify-content: flex-end; + @media (max-width: 500px) { position: fixed; right: 10px; bottom: 8px; } } + +.direct-sale-container { + .uom-select { + width: 90px !important; + } + + .tax-select { + width: 120px !important; + } + + .tax-select, + .uom-select { + + .ant-select-selection-placeholder, + .ant-select-selection-item { + padding-inline-end: 0 !important; + padding-top: 0 !important; + margin-top: 0 !important; + } + } + + .ant-select-arrow { + top: 60% !important; + } + + .ant-input { + padding: 6px 14px 6px 11px !important; + } + + .ant-select-single:not(.ant-select-customize-input) .ant-select-selector { + height: 36.5px !important; + } + +} + +.directsaleBTN { + + .ant-btn { + width: max-content !important; + height: 36px !important; + z-index: 0; + } + + .ant-btn:disabled, + .ant-btn[disabled] { + background-color: #f5f5f5; + color: rgba(0, 0, 0, 0.25); + } + + .ant-btn:not(:disabled) { + background-color: #10b981; + color: #fff; + font-size: 14px; + height: 36px !important; + border-radius: 6px; + font-family: "Poppins"; + + &:hover { + + background: #ffffff !important; + background-color: #ffffff !important; + color: #10b981; + border-color: #10b981; + } + } + + .save-btn { + background-color: #0088ff !important; + + &:hover { + color: #0088ff !important; + border-color: #0088ff !important; + } + } + + .ant-btn:not(:disabled):nth-child(2) { + background-color: #1292ee; + color: #fff; + font-size: 14px; + height: 36px !important; + border-radius: 6px; + + } + +} + + +.DirectSaleTable { + height: 70vh; + overflow: auto; + scrollbar-width: thin; +} + +.requiredIcons { + width: 12px; + border-radius: 6px; + height: 12px; + background-color: #fff; + padding: 2px; +} \ No newline at end of file diff --git a/src/Styles/Stock/StockMaster.scss b/src/Styles/Stock/StockMaster.scss index 6c7b0a5..4aebeef 100644 --- a/src/Styles/Stock/StockMaster.scss +++ b/src/Styles/Stock/StockMaster.scss @@ -133,6 +133,11 @@ .extractor-table { overflow: auto; scrollbar-width: thin; + +} + +.extractor-table-red .ant-table-thead { + background-color: #ef4444; } .product-extractor-table { @@ -160,6 +165,48 @@ text-align: center; } } + + &.not-added { + background-color: #ff4d4f; + + &:hover { + background-color: #ff4d4f !important; + + } + } + + &.added { + background-color: #52c41a; + } + +} + +.product-legend { + display: flex; + align-items: center; + gap: 10px; + font-family: 'Poppins'; + margin-bottom: 10px; + + .legend-item { + display: flex; + align-items: center; + gap: 10px; + } + + .legend-box { + width: 10px; + height: 10px; + border-radius: 2px; + + &.green { + background-color: #52c41a; + } + + &.red { + background-color: #ff4d4f; + } + } } // .supplierInfo .ant-select-selector @@ -839,8 +886,8 @@ font-size: 12px !important; } - .div-flex{ - padding-bottom: 18px !important; + .div-flex { + padding-bottom: 18px !important; } } @@ -863,6 +910,6 @@ .div-flex { flex-direction: column; align-items: flex-start; - padding-bottom: 8px !important; + padding-bottom: 8px !important; } } \ No newline at end of file