Merge pull request 'combo-table-qty-price-edit' (#129) from combo-table-qty-price-edit into main

Reviewed-on: Pozomind/pozo-retail-app#129
This commit is contained in:
karthikalakshmi 2026-02-11 15:55:12 +05:30
commit 509b2aae37
5 changed files with 111 additions and 37 deletions

View File

@ -82,16 +82,16 @@ export const ReprintDetails = createAsyncThunk(
const { AppId, CompId, BranchId, OrderFromDate, OrderToDate, OrderId } = data || {}; const { AppId, CompId, BranchId, OrderFromDate, OrderToDate, OrderId } = data || {};
if (OrderId && !OrderFromDate && !OrderToDate) { if (OrderId && !OrderFromDate && !OrderToDate) {
return await axiosRetailInstanceData.get( return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&OrderId=${OrderId}&pageNumber=${data.PageNumber}` `/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&OrderId=${OrderId}&pageNumber=${data.PageNumber}&Type=${data.Type}`
); );
} }
if (OrderFromDate && OrderToDate) { if (OrderFromDate && OrderToDate) {
return await axiosRetailInstanceData.get( return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&orderFromDate=${OrderFromDate}&orderToDate=${OrderToDate} &pageNumber=${data.PageNumber}` `/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&orderFromDate=${OrderFromDate}&orderToDate=${OrderToDate} &pageNumber=${data.PageNumber}&Type=${data.Type}`
); );
} else { } else {
return await axiosRetailInstanceData.get( return await axiosRetailInstanceData.get(
`/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&pageNumber=${data.PageNumber}` `/reprint?CompId=${CompId}&BranchId=${BranchId}&AppId=${AppId}&pageNumber=${data.PageNumber}&Type=${data.Type}`
); );
} }
} }

View File

@ -87,6 +87,7 @@ import { v4 as uuidv4 } from 'uuid';
import { changeOrderOfferDetail } from '../../../../../Features/Offer/Offer.js'; import { changeOrderOfferDetail } from '../../../../../Features/Offer/Offer.js';
import { ChangeFullFreeProductList, changeFullOfferAppliedProducts, changeLoyaltyConsumedQuantities } from '../../../../../Features/Offer/Offernew/BookingOffernew.js'; import { ChangeFullFreeProductList, changeFullOfferAppliedProducts, changeLoyaltyConsumedQuantities } from '../../../../../Features/Offer/Offernew/BookingOffernew.js';
import { ChangeTotalAmount } from '../../../../../Features/ExteraCharges/ExtraCharges.js'; import { ChangeTotalAmount } from '../../../../../Features/ExteraCharges/ExtraCharges.js';
import { Radio } from 'antd';
const RetailApiurl = import.meta.env.ENV_API_URL; const RetailApiurl = import.meta.env.ENV_API_URL;
@ -127,12 +128,17 @@ function BSReprint({ setOpenModel = () => { } }) {
const SettingDataSelector = useSelector(PreferenceData); const SettingDataSelector = useSelector(PreferenceData);
const salesBillEdit = useSelector(GlobalSalesBillEdit); const salesBillEdit = useSelector(GlobalSalesBillEdit);
const custDisable = useSelector(GlobalSelectedCustDisable); const custDisable = useSelector(GlobalSelectedCustDisable);
console.log(SettingDataSelector, 'SettingDataSelector'); console.log(SettingDataSelector, 'SettingDataSelectoraa');
const MobileA4Print = SettingDataSelector?.[0]?.SettingDtlDetails?.find( const MobileA4Print = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
(setting) => (setting) =>
setting?.SettingIdName?.toLowerCase() === 'mobilea4' && setting?.SettingIdName?.toLowerCase() === 'mobilea4' &&
setting?.SettingValue === 'Y' setting?.SettingValue === 'Y'
); );
const preferenceEstimate =
SettingDataSelector?.[0]?.['SettingDtlDetails']?.find(
(item) => item.SettingIdName === 'Estimation'
)?.SettingValue === 'Y';
console.log(preferenceEstimate, 'preferenceEstimate');
const editBill = SettingDataSelector?.[0]?.SettingDtlDetails?.find( const editBill = SettingDataSelector?.[0]?.SettingDtlDetails?.find(
(setting) => (setting) =>
setting?.SettingIdName?.toLowerCase() === 'editbill' && setting?.SettingIdName?.toLowerCase() === 'editbill' &&
@ -160,10 +166,10 @@ function BSReprint({ setOpenModel = () => { } }) {
const AuthToken = sessionStorage.getItem('auth'); const AuthToken = sessionStorage.getItem('auth');
const SessionMobileNo = getSession('MobileNo'); const SessionMobileNo = getSession('MobileNo');
const [dateStrings, setDateStrings] = useState([]); const [dateStrings, setDateStrings] = useState([]);
const [type, setType] = useState("Sales");
// ---- 1. Fetch Function ---- // ---- 1. Fetch Function ----
const fetchData = async ({ queryKey }) => { const fetchData = async ({ queryKey }) => {
const [_, dates, page] = queryKey; const [_, dates, page,type] = queryKey;
const Response = await dispatch( const Response = await dispatch(
ReprintDetails({ ReprintDetails({
CompId, CompId,
@ -172,6 +178,7 @@ function BSReprint({ setOpenModel = () => { } }) {
OrderFromDate: dates?.[0] ?? '', OrderFromDate: dates?.[0] ?? '',
OrderToDate: dates?.[1] ?? '', OrderToDate: dates?.[1] ?? '',
PageNumber: page, PageNumber: page,
Type:type
}) })
).unwrap(); ).unwrap();
if (Response?.data?.statusCode === 1) { if (Response?.data?.statusCode === 1) {
@ -182,7 +189,7 @@ function BSReprint({ setOpenModel = () => { } }) {
}; };
const { data, isLoading, error } = useQuery({ const { data, isLoading, error } = useQuery({
queryKey: ['reprint', dateStrings, page], queryKey: ['reprint', dateStrings, page,type],
queryFn: fetchData, queryFn: fetchData,
enabled: true, enabled: true,
staleTime: 1000 * 60 * 5, staleTime: 1000 * 60 * 5,
@ -242,6 +249,8 @@ function BSReprint({ setOpenModel = () => { } }) {
} }
}; };
commonMasterApiCall(); commonMasterApiCall();
}, []);
useEffect(() => {
DefaultReprintReason(); DefaultReprintReason();
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -254,7 +263,9 @@ function BSReprint({ setOpenModel = () => { } }) {
dispatch(getPrinterMappingDetails(data)).unwrap(); dispatch(getPrinterMappingDetails(data)).unwrap();
const Data1 = { AppId, CompId, BranchId }; const Data1 = { AppId, CompId, BranchId };
dispatch(getPrintSelectionComponentData(Data1)).unwrap(); dispatch(getPrintSelectionComponentData(Data1)).unwrap();
}, []); }, []);
const handleDateChange = (dates, dateStrings) => { const handleDateChange = (dates, dateStrings) => {
// setDateRange(dateStrings); // setDateRange(dateStrings);
if (dateStrings[0] && dateStrings[1]) { if (dateStrings[0] && dateStrings[1]) {
@ -1394,6 +1405,15 @@ function BSReprint({ setOpenModel = () => { } }) {
} }
} }
const typeOptions = [
{ label: "Sales", value: "Sales" },
{ label: "Estimate", value: "Est" },
];
const typeChange = (e) => {
setType(e.target.value);
};
return ( return (
<> <>
<div> <div>
@ -1432,20 +1452,16 @@ function BSReprint({ setOpenModel = () => { } }) {
/> />
<div style={{ width: '100%' }}> <div style={{ width: '100%' }}>
<div className="bsreprintmodaltable-flex"> <div className="bsreprintmodaltable-flex">
{preferenceEstimate && <div>
<Radio.Group
options={typeOptions}
onChange={typeChange}
value={type}
optionType="button"
buttonStyle="solid" // optional
/>
</div>}
<div> <div>
{selectedRows.length > 0 && (
<div className="action-icons-reprint">
<FaDownload
onClick={() => mutiplePrint('download')}
className="icon-download"
/>
<MdEmail onClick={() => handleEmail()} className="icon-email" />
<FaWhatsapp
onClick={() => mutiplePrint('whatsapp')}
className="icon-whatsapp"
/>
</div>
)}
<RangePicker <RangePicker
placeholder={['Start Date', 'End Date']} placeholder={['Start Date', 'End Date']}
format="YYYY-MM-DD" format="YYYY-MM-DD"
@ -1473,6 +1489,22 @@ function BSReprint({ setOpenModel = () => { } }) {
Reprintformdata(); Reprintformdata();
}} }}
/> />
<div>
{selectedRows.length > 0 && (
<div className="action-icons-reprint">
<FaDownload
onClick={() => mutiplePrint('download')}
className="icon-download"
/>
<MdEmail onClick={() => handleEmail()} className="icon-email" />
<FaWhatsapp
onClick={() => mutiplePrint('whatsapp')}
className="icon-whatsapp"
/>
</div>
)}
</div>
</div> </div>
{/* <div className="Re-Print-table"> */} {/* <div className="Re-Print-table"> */}
<div className="bsreprintmodaltable"> <div className="bsreprintmodaltable">

View File

@ -1,5 +1,7 @@
import { Tooltip } from 'antd'; import { Tooltip, message } from 'antd';
import { useState, useEffect, useCallback } from 'react';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { Messages } from '../../Components/Notifications/Messages';
const AddAllProductsButton = ({ const AddAllProductsButton = ({
productData = [], productData = [],
@ -13,6 +15,9 @@ const AddAllProductsButton = ({
}) => { }) => {
// This function just returns a prepared product object, no state changes // This function just returns a prepared product object, no state changes
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const ProductDropDownChange = async ( const ProductDropDownChange = async (
VariantName, VariantName,
ProdId, ProdId,
@ -74,24 +79,34 @@ const AddAllProductsButton = ({
localId: uuidv4(), localId: uuidv4(),
}; };
}; };
const handleAddAll = async () => { const handleAddAll = async () => {
const existingProdIds = new Set(
purchaseData?.map((p) => `${p.ProdId}_${p.ProdVariantName}`)
);
const productsToAdd = productData?.filter(
(p) => !existingProdIds?.has(`${p.ProdId}_${p.ProdVariantName}`)
);
if (productsToAdd.length === 0) {
setMessageData('All products are already added');
setMessageType('warning');
return;
}
try { try {
setIsLoading(true); setIsLoading(true);
setLoadingText('Adding products...'); setLoadingText('Adding products...');
// allow UI paint
await new Promise((r) => requestAnimationFrame(r)); await new Promise((r) => requestAnimationFrame(r));
const allValidProducts = []; const allValidProducts = [];
const allFormValues = {}; const allFormValues = {};
for (let i = 0; i < productData.length; i += batchSize) { for (let i = 0; i < productsToAdd.length; i += batchSize) {
const batch = productData.slice(i, i + batchSize); const batch = productsToAdd.slice(i, i + batchSize);
setLoadingText( setLoadingText(
`Processing ${Math.min(i + batchSize, productData.length)} / ${ `Processing ${Math.min(i + batchSize, productsToAdd.length)} / ${productsToAdd.length
productData.length
}` }`
); );
@ -101,8 +116,7 @@ const AddAllProductsButton = ({
product.ProdVariantName, product.ProdVariantName,
product.ProdId, product.ProdId,
{ {
label: `${product.ProdName} (${product.Size} ${product.UomName})${ label: `${product.ProdName} (${product.Size} ${product.UomName})${product.BrandName ? ` - ${product.BrandName}` : ''
product.BrandName ? ` - ${product.BrandName}` : ''
}`, }`,
}, },
productData productData
@ -128,19 +142,25 @@ const AddAllProductsButton = ({
await new Promise((r) => setTimeout(r, 0)); await new Promise((r) => setTimeout(r, 0));
} }
// ONE state update
setPurchaseData((prev) => [...allValidProducts, ...prev]); setPurchaseData((prev) => [...allValidProducts, ...prev]);
// ONE form update
form?.setFieldsValue(allFormValues); form?.setFieldsValue(allFormValues);
} finally { } finally {
setIsLoading(false); setIsLoading(false);
setLoadingText(''); setLoadingText('');
} }
}; };
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
return ( return (
<Tooltip title="Add All Products" placement="top"> <Tooltip title="Add All Products" placement="top">
<Messages
messageType={messageType}
messageData={messageData}
onComplete={onComplete}
/>
<button type="button" className="addallProductTBN" onClick={handleAddAll}> <button type="button" className="addallProductTBN" onClick={handleAddAll}>
Add All Add All
</button> </button>

View File

@ -13,6 +13,7 @@ import {
getSupplaierIdBasedProducts getSupplaierIdBasedProducts
} from '../../Features/SupplierProductMapping/SupplierProductMapping.js'; } from '../../Features/SupplierProductMapping/SupplierProductMapping.js';
import { getsupplierBasedOnCmpId, getsupplierBasedOnCmpIdBrId } from '../../Features/SupplierMaster/SupplierMaster.js'; import { getsupplierBasedOnCmpId, getsupplierBasedOnCmpIdBrId } from '../../Features/SupplierMaster/SupplierMaster.js';
import "../../Pages/SupplierProductMapping/SupplierProductMapping.scss"
const SupplierProductMappingForm = ({ const SupplierProductMappingForm = ({
isModalOpen = false, isModalOpen = false,
@ -36,6 +37,8 @@ const SupplierProductMappingForm = ({
const [modalSelectedProduct, setModalSelectedProduct] = useState(null); const [modalSelectedProduct, setModalSelectedProduct] = useState(null);
const [tabledata, setTabledata] = useState([]); const [tabledata, setTabledata] = useState([]);
const [filteredTableData, setFilteredTableData] = useState([]); const [filteredTableData, setFilteredTableData] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(8);
const details = { const details = {
name: "tamil", name: "tamil",
address: { address: {
@ -199,7 +202,9 @@ const SupplierProductMappingForm = ({
key: "ProdId", key: "ProdId",
align: "center", align: "center",
width: "80px", width: "80px",
render: (text, object, index) => <span>{index + 1}</span>, render: (text, object, index) => (
<span>{(currentPage - 1) * pageSize + index + 1}</span>
),
}, },
{ {
title: "Product Name", title: "Product Name",
@ -274,7 +279,7 @@ const SupplierProductMappingForm = ({
isOnchanges={false} isOnchanges={false}
alphabetfilter="Yes" alphabetfilter="Yes"
/> />
<button style={{ padding: '10px 10px', margin: '0px 15px', borderRadius: '6px',fontFamily:'poppins', background: '#901D77', color: 'white', border: 'none', cursor: 'pointer' }} <button style={{ padding: '10px 10px', margin: '0px 15px', borderRadius: '6px', fontFamily: 'poppins', background: '#901D77', color: 'white', border: 'none', cursor: 'pointer' }}
onClick={allProductMap}>Add All</button> onClick={allProductMap}>Add All</button>
<div style={{ position: "absolute", left: "16rem", top: "1px" }}> <div style={{ position: "absolute", left: "16rem", top: "1px" }}>
@ -293,12 +298,22 @@ const SupplierProductMappingForm = ({
)} )}
</div> </div>
<div className="modal-table" style={{ marginTop: "1rem" }}> <div className="ProductMappingTable" style={{ marginTop: "1rem" }}>
<Tables <Tables
columns={tableColumns} columns={tableColumns}
data={modelTableData} data={modelTableData}
dataSource={modelTableData} dataSource={modelTableData}
pagination={false} pagination={{
current: currentPage,
pageSize: pageSize,
total: modelTableData.length,
showSizeChanger: false,
onChange: (page, size) => {
setCurrentPage(page);
setPageSize(size);
},
}}
ownPagination={true}
rowKey="ProdId" rowKey="ProdId"
/> />
</div> </div>

View File

@ -97,3 +97,10 @@
} }
} }
} }
.ProductMappingTable {
margin-top: 20px;
height: 300px;
overflow-y: auto;
border-radius: 6px;
}