Merge pull request 'price-weight-calculate' (#112) from price-weight-calculate into main

Reviewed-on: Pozomind/pozo-retail-app#112
This commit is contained in:
karthikalakshmi 2026-02-09 16:54:14 +05:30
commit 3d4cb2f9af
4 changed files with 150 additions and 86 deletions

View File

@ -102,15 +102,33 @@ const BSBillingEditQuantity = (props) => {
const SettingDataSelector = useSelector(PreferenceData);
const OrderType = useSelector(GlobalOrderType);
const [BillOrderPre, setBillOrderPre] = useState(null);
const [RadioBtnSelection, setRadioBtnSelection] = useState(
props?.shortKeyMethod == 'price'
? 'Price'
: ItemData?.ScaleType !== 'weight'
? 'Quantity'
: PriceChangeaccess
? 'Price'
: 'Parcel'
);
const SHORTKEY_TO_RADIO = {
price: 'Price',
quantity: 'qty',
Parcel: 'Parcel',
weightAmount: 'weightAmount'
};
const [RadioBtnSelection, setRadioBtnSelection] = useState(() => {
if (props?.shortKeyMethod && SHORTKEY_TO_RADIO[props.shortKeyMethod]) {
return SHORTKEY_TO_RADIO[props.shortKeyMethod];
}
if (ItemData?.ScaleType !== 'weight') {
return 'Quantity';
}
if (PriceChangeaccess) {
return 'Price';
}
return 'Parcel';
});
// const [RadioBtnSelection, setRadioBtnSelection] = useState(
// props?.shortKeyMethod == 'price'
// ? 'Price'
// : ItemData?.ScaleType !== 'weight'
// ? 'Quantity'
// : PriceChangeaccess
// ? 'Price'
// : 'Parcel'
// );
const [PercentageSelection, setPercentageSelection] = useState('Fixed');
const [RadioDetails, setRadioDetails] = useState(false);
const [editedPrice, setEditedPrice] = useState(0);
@ -3552,13 +3570,13 @@ const BSBillingEditQuantity = (props) => {
{isKg && (<button
type="button"
className={
RadioBtnSelection === 'AddWeight'
? 'SelecBtn AddWeight'
RadioBtnSelection === 'weightAmount'
? 'SelecBtn weightAmount'
: 'ChangeBtn'
}
onClick={() => onRadioBtnChange('AddWeight')}
onClick={() => onRadioBtnChange('weightAmount')}
>
Add Weight
Weight / Amount
</button>)}
</div>
@ -3766,7 +3784,7 @@ const BSBillingEditQuantity = (props) => {
/>
</>
)}
{RadioBtnSelection == 'AddWeight' && (
{RadioBtnSelection == 'weightAmount' && (
<>
<WeightCalculatePrice
CartOrderDetails={CartOrderDetails}

View File

@ -1,87 +1,105 @@
import { useState, useEffect, useRef } from 'react';
import { InputField } from '../../../../../Components/Forms/InputField.jsx';
import { Form } from 'antd';
import { Form, Radio } from 'antd';
import Buttons from '../../../../../Components/Forms/Buttons.jsx';
import { ArrowRightOutlined } from '@ant-design/icons';
import "./WeightCalculatePrice.scss"
const WeightCalculatePrice = ({ itemData, CartOrderDetails, onSubmit }) => {
const [enteredPrice, setEnteredPrice] = useState('');
const [enteredQty, setEnteredQty] = useState('');
const [calculatedQty, setCalculatedQty] = useState(0);
const [calcMode, setCalcMode] = useState('amt');
const priceInputRef = useRef(null);
const [form] = Form.useForm();
const basePrice = parseFloat(itemData?.OrderRate || itemData?.SellingPrice || 0);
const basePrice = parseFloat(
itemData?.OrderRate || itemData?.SellingPrice || 0
);
// Auto focus input
useEffect(() => {
setTimeout(() => {
const inputElement = priceInputRef.current?.querySelector('input');
if (inputElement) {
inputElement.focus();
}
const input = priceInputRef.current?.querySelector('input');
if (input) input.focus();
}, 100);
}, []);
}, [calcMode]);
// Calculate quantity based on entered price
// AMT calculate QTY
const handlePriceChange = (e) => {
const value = e.target.value;
setEnteredPrice(value);
if (value && basePrice > 0) {
const price = parseFloat(value);
const qty = price / basePrice;
const qty = parseFloat(value) / basePrice;
setCalculatedQty(qty);
} else {
setCalculatedQty(0);
}
};
// KGS calculate AMT
const handleQtyChange = (e) => {
const value = e.target.value;
setEnteredQty(value);
if (value && basePrice > 0) {
const qty = parseFloat(value);
const price = qty * basePrice;
setEnteredPrice(price.toFixed(2));
setCalculatedQty(qty);
} else {
setEnteredPrice('');
setCalculatedQty(0);
}
};
const handleSubmit = (e) => {
if (e && e.preventDefault) {
e.preventDefault();
}
if (e && e.preventDefault) e.preventDefault();
if (enteredPrice && calculatedQty > 0) {
console.log('Submitting weight calculation:', {
if (calculatedQty > 0 && enteredPrice > 0) {
onSubmit?.({
price: parseFloat(enteredPrice),
quantity: calculatedQty,
quantity: parseFloat(calculatedQty),
});
// Pass the calculated values back to parent component
if (onSubmit) {
onSubmit({
price: parseFloat(enteredPrice),
quantity: calculatedQty,
});
}
}
};
return (
<div className="weight-calculate-price">
<Form
form={form}
onFinish={handleSubmit}
onSubmitCapture={(e) => e.preventDefault()}
>
<Form form={form} onFinish={handleSubmit}>
{/* MODE SELECTION */}
<div className="weight-info">
<div className="product-details">
<p><strong>Product:</strong> {itemData?.ProdName}</p>
<p><strong>Variant:</strong> {itemData?.ProdVariantName}</p>
<p><strong>Base Price:</strong> {basePrice.toFixed(2)} per {itemData?.UomName || 'unit'}</p>
<div className="productils">
<Radio.Group
value={calcMode}
onChange={(e) => {
setCalcMode(e.target.value);
setEnteredPrice('');
setEnteredQty('');
setCalculatedQty(0);
form.resetFields();
}}
>
<Radio.Button value="amt">AMT</Radio.Button>
<Radio.Button value="kgs">KGS</Radio.Button>
</Radio.Group>
<p>
<strong>Base Price:</strong> {basePrice.toFixed(2)} per{' '}
{itemData?.UomName || 'unit'}
</p>
</div>
</div>
{/* AMOUNT INPUT */}
{calcMode === 'amt' && (
<Form.Item
name="enteredPrice"
rules={[
{
required: true,
message: 'Please enter the price',
},
{
pattern: /^[1-9]\d*(\.\d+)?$/,
message: 'Please enter a valid price',
},
{ required: true, message: 'Please enter amount' },
{ pattern: /^[1-9]\d*(\.\d+)?$/, message: 'Invalid amount' },
]}
>
<InputField
@ -89,35 +107,52 @@ const WeightCalculatePrice = ({ itemData, CartOrderDetails, onSubmit }) => {
label="Enter Amount (₹)"
value={enteredPrice}
onChange={handlePriceChange}
autocomplete="off"
inputMode="decimal"
placeholder="Enter price amount"
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;
e.target.value = e.target.value.replace(/[^0-9.]/g, '');
}}
/>
</Form.Item>
)}
{/* QUANTITY INPUT */}
{calcMode === 'kgs' && (
<Form.Item
name="enteredQty"
rules={[
{ required: true, message: 'Please enter quantity' },
{ pattern: /^\d*(\.\d+)?$/, message: 'Invalid quantity' },
]}
>
<InputField
ref={priceInputRef}
label={`Enter Quantity (${itemData?.UomName || 'KGS'})`}
value={enteredQty}
onChange={handleQtyChange}
inputMode="decimal"
onInput={(e) => {
e.target.value = e.target.value.replace(/[^0-9.]/g, '');
}}
/>
</Form.Item>
)}
<div className="calculated-quantity-display">
<div className="quantity-row">
<label className="quantity-label">Calculated Quantity:</label>
<span className="quantity-value">
{calculatedQty > 0 ? calculatedQty.toFixed(3) : '0.000'} {itemData?.UomName || 'units'}
<label>Calculated Quantity : </label>
<span>
{calculatedQty > 0 ? calculatedQty.toFixed(3) : '0.000'}{' '}
{itemData?.UomName || 'units'}
</span>
</div>
{calculatedQty > 0 && (
{enteredPrice > 0 && (
<div className="total-display">
<label>Total Amount:</label>
<span>{parseFloat(enteredPrice || 0).toFixed(2)}</span>
<span>{parseFloat(enteredPrice).toFixed(2)}</span>
</div>
)}
</div>
<div className="submit-button-container">
<div className="weightCalBTN">
<Buttons
buttonText="Apply"
color="901D77"

View File

@ -0,0 +1,9 @@
.productils {
margin: 10px 0;
}
.weightCalBTN {
width: 100%;
display: flex;
justify-content: flex-end;
}

View File

@ -15,8 +15,10 @@ const ShortcutKeyHelper = ({ }) => {
{ key: 'F4', description: 'Quick Pay' },
{ key: 'Alt + W', description: 'Hold and Recall' },
{ key: 'Ctrl + Q', description: 'Qty Change' },
{ key: 'Alt + P', description: 'Change Total Amount' },
{ key: 'Ctrl + E', description: 'Price Change' },
{ key: 'Ctrl + Y', description: 'Weight / Amount' },
{ key: 'Ctrl + B', description: 'Packing' },
{ key: 'Alt + P', description: 'Change Total Amount' },
{ key: 'Ctrl + I', description: 'Customer Rate History' },
];