added customer search based, Ledger Download Excel, Branch Login, Edit item-wise limit

This commit is contained in:
unknown 2026-03-05 19:11:12 +05:30
parent 0236fee8af
commit 14b857aa6d
19 changed files with 698 additions and 333 deletions

View File

@ -391,9 +391,27 @@ export const getAllCustomer = createAsyncThunk(
}
}
);
export const getSearchedCustomer = createAsyncThunk(
'product/getSearchedCustomer',
async ({ CompId, AppId, branchId, searchValue }) => {
if (
CompId !== null &&
CompId !== undefined &&
branchId !== null &&
branchId !== undefined &&
AppId !== null &&
AppId !== undefined
&& searchValue !== '' && searchValue !== null && searchValue !== undefined
) {
return await axiosRetailInstanceData.get(
`/Customer?compId=${CompId}&branchId=${branchId}&appId=${AppId}&custName=${encodeURIComponent(searchValue)}`
);
}
}
);
export const getCustomerForHold = createAsyncThunk(
'product/getAllCustomer',
'product/getCustomerForHold',
async ({ CompId, AppId, branchId, OrderId }) => {
if (
CompId != null &&

BIN
src/Images/xls-export.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -469,6 +469,14 @@ const BSBillingEditQuantity = (props) => {
setMessageType('warning');
return;
}
} else if (itemWiseLimitPreferenece) {
const exceptEditedItemCart = calculateOverAllQtyLimit(CartOrderDetails?.filter((_, index) => index !== editedProductIndex && _.ProdId === editedProduct?.ProdId && _.InwardDtlId === editedProduct?.InwardDtlId));
const totalQtyForItem = ((exceptEditedItemCart || 0) + (editedQty || 0));
if (totalQtyForItem > maxQtyLimit) {
setMessageData(`Item Quantity Limit Exceeds than ${maxQtyLimit}`);
setMessageType('warning');
return;
}
}
}

View File

@ -1146,6 +1146,8 @@ const BSBillingTable1 = () => {
e?.BookingTypeName != item?.BookingTypeName
);
if (tableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));

View File

@ -1062,6 +1062,8 @@ const BsBill2 = () => {
await dispatch(changeSelProdWiseEst([]));
await dispatch(ChangeTotalAmount([]));
dispatch(changeBillEditingMode(false));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
}
@ -1101,6 +1103,8 @@ const BsBill2 = () => {
await dispatch(changeSelProdWiseEst([]));
await dispatch(ChangeTotalAmount([]));
dispatch(changeBillEditingMode(false));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
}

View File

@ -1107,6 +1107,8 @@ const BSBillingTable3 = () => {
);
if (tableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));

View File

@ -1050,6 +1050,8 @@ const BSBillingTable4 = () => {
);
if (tableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));

View File

@ -870,6 +870,8 @@ const BsBill = () => {
);
if (TableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));
@ -2944,6 +2946,8 @@ const BsBill = () => {
// if the quantity of the item is 1, remove the item from the cart
if (TableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));
@ -2975,6 +2979,8 @@ const BsBill = () => {
// if the quantity of the item is 1, remove the item from the cart
if (TableData?.length <= 1) {
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changeReorderHoldDetails({}));
await dispatch(changeReorderProductDetails([]));
await dispatch(changeUnpaidData(false));
@ -3013,6 +3019,7 @@ const BsBill = () => {
await dispatch(ChangeOverAllDiscEstimate(null));
await dispatch(changeSelProdWiseEst([]));
await dispatch(ChangeTotalAmount([]));
}
}
}

View File

@ -1106,6 +1106,8 @@ const BSBillingTable6 = () => {
dispatch(changeBillEditingMode(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
}
if (item?.Offer > 0) {

View File

@ -40,6 +40,7 @@ import {
changeBillEditingMode,
changePreviousOrderPayment,
changePreviousOrderOfferDetail,
ChangeSelectedCustDisable,
} from '../../../../../Features/BookingScreen/BookingData/BookingData';
import {
ChangeFullFreeProductList,
@ -985,6 +986,8 @@ const BSBillingTable7 = () => {
dispatch(changeBillEditingMode(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
}
if (item?.Offer > 0) {
//check is Buyxgetx Or something
@ -2192,8 +2195,7 @@ const BSBillingTable7 = () => {
}
// onClick={editdelete === "Edit" ? () => handleEditQuantity(item) : editdelete === "Delete" ? () => removeFromCart(item) : ""}
className={`${
item?.SalesId && OrderType !== 'Hold'
className={`${item?.SalesId && OrderType !== 'Hold'
? 'BSBill-Table7-content-disabled'
: 'BSBill-Table7-content'
}
@ -2422,8 +2424,7 @@ const BSBillingTable7 = () => {
}
// onClick={editdelete === "Edit" ? () => handleEditQuantity(item) : editdelete === "Delete" ? () => removeFromCart(item) : ""}
className={`${
item?.SalesId
className={`${item?.SalesId
? 'BSBill-Table7-content-disabled'
: 'BSBill-Table7-content'
}
@ -2691,8 +2692,7 @@ const BSBillingTable7 = () => {
}
// onClick={editdelete === "Edit" ? () => handleEditQuantity(item) : editdelete === "Delete" ? () => removeFromCart(item) : ""}
className={`${
BookingType === 'Dine In' && item?.SalesId
className={`${BookingType === 'Dine In' && item?.SalesId
? 'BSBill-Table7-content-disabled'
: 'BSBill-Table7-content'
}
@ -2959,8 +2959,7 @@ const BSBillingTable7 = () => {
}
// onClick={editdelete === "Edit" ? () => handleEditQuantity(item) : editdelete === "Delete" ? () => removeFromCart(item) : ""}
className={`${
BookingType === 'Dine In' && item?.SalesId
className={`${BookingType === 'Dine In' && item?.SalesId
? 'BSBill-Table7-content-disabled'
: 'BSBill-Table7-content'
}

View File

@ -341,6 +341,16 @@ const ComboEditQtyAndRate = (props) => {
setQuantity(removeProds1?.OrderQty || 1)
return;
}
} else if (itemWiseLimitPreferenece) {
let editedProduct = CartOrderDetails?.find((_, index) => index === editedProductIndex)
const exceptEditedItemCart = calculateOverAllQtyLimit(CartOrderDetails?.filter((_, index) => index !== editedProductIndex && _.ProdId === editedProduct?.ProdId && _.InwardDtlId === editedProduct?.InwardDtlId));
const totalQtyForItem = ((exceptEditedItemCart || 0) + (editedQty || 0));
if (totalQtyForItem > maxQtyLimit) {
setMessageData(`Item Quantity Limit Exceeds than ${maxQtyLimit}`);
setMessageType('warning');
setQuantity(editedProduct?.OrderQty || 1)
return;
}
}
}
const editedProduct = CartOrderDetails[editedProductIndex];

View File

@ -1292,6 +1292,8 @@ const ComboSalesBillTable = () => {
await dispatch(ChangeOverAllDiscEstimate(null));
await dispatch(changeSelProdWiseEst([]));
dispatch(changeBillEditingMode(false));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
}
@ -2610,8 +2612,7 @@ const ComboSalesBillTable = () => {
}}
key={`qty-${index}`}
tabIndex={0}
className={`${
EditQtyCombo && row?.localId === Index
className={`${EditQtyCombo && row?.localId === Index
? 'EditQTYcomboTD'
: 'qtyTd'
} ${isActiveCell ? 'active-cell' : ''}`}

View File

@ -1170,6 +1170,8 @@ const StandardTable = () => {
await dispatch(changeUnpaidData(false));
await dispatch(changeBookingType('TakeAway'));
await dispatch(changeTokenOnly(false));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
await dispatch(ChangeTotalAmount([]));
await dispatch(changeAllProductTokenAvailable(false));
await dispatch(ChangeOverAllDiscSales(null));

View File

@ -312,6 +312,8 @@ export const useRemoveFromCart = () => {
dispatch(changeBillEditingMode(false));
await dispatch(changePreviousOrderPayment([]));
await dispatch(changePreviousOrderOfferDetail([]));
await dispatch(changeSelectedOption(null));
await dispatch(ChangeSelectedCustDisable(false));
} else {
let putData = { OrderId: [ReportholdData?.OrderId] };
let response = await dispatch(puttinghold(putData)).unwrap();

View File

@ -59,6 +59,7 @@
padding: 10px 10px;
border-radius: 8px;
width: 60%;
@media (max-width: 768px) {
width: 100%;
}
@ -105,6 +106,7 @@
width: 100%;
overflow-x: hidden;
}
.BSOTPKioskPayment-dailpad-1,
.BSOTPKioskPayment-dailpad-2,
.BSOTPKioskPayment-dailpad-3 {
@ -338,10 +340,7 @@
padding: 54px 35px !important;
}
.paymentCardMain
.ant-collapse
.ant-collapse-item:last-child
> .ant-collapse-content {
.paymentCardMain .ant-collapse .ant-collapse-item:last-child>.ant-collapse-content {
overflow: scroll;
height: 26vh;
}
@ -465,6 +464,7 @@
color: #fff;
border-radius: 10px;
cursor: pointer;
@media (max-width: 768px) {
width: 100%;
}
@ -573,6 +573,7 @@
}
}
}
.BSOTPItem3Warning {
position: fixed;
top: 0%;
@ -635,12 +636,14 @@
align-items: center;
justify-content: center;
flex-direction: column;
.input-err {
font-family: 'Poppins', sans-serif;
font-size: 12px;
margin-top: 6px;
color: rgb(224, 0, 0);
}
input {
width: 60%;
outline: none;
@ -652,11 +655,13 @@
border-radius: 6px;
border: 1px solid #333;
font-size: 20px;
@media (max-width: 768px) {
width: 100%;
}
}
}
.BSOTPdailpad-main {
display: flex;
flex-direction: column;
@ -688,11 +693,14 @@
.BSOTPotp-box.active {
border: 2px solid #28a745;
}
.BSOTPpaymentModal-Master {
scrollbar-width: thin;
height: 90vh;
height: max-content;
max-height: 90vh;
overflow: auto;
}
.optEnterResendOTP {
display: flex;
align-items: center;

View File

@ -26,6 +26,7 @@ import {
changeOrderCardDetails,
changeCustomerID,
changeCombofocus,
getSearchedCustomer,
} from '../../../../Features/BookingScreen/BookingData/BookingData';
import Select from 'react-select';
import {
@ -45,6 +46,7 @@ import {
FaPlus,
FaMinus,
FaEye,
FaLessThanEqual,
} from 'react-icons/fa';
import { DefaultModal } from '../../../../Components/Modal/DefaultModal';
import WsPreOrderForm from '../../../Wholesalespreorder/WholesalePreorderForm';
@ -246,10 +248,16 @@ const BSCustomerSelect = ({ TopName = null }) => {
// Customer data
const [allCustomers, setAllCustomers] = useState([]);
// useEffect(() => {
// dispatch(getAllCustomer({ CompId, AppId, branchId: BranchId }))
// .unwrap()
// .then((res) => setAllCustomers(res?.data?.data || []));
// setProductQuantities({});
// }, [CompId, AppId, BranchId, dispatch, customerRefreshTrigger]);
useEffect(() => {
dispatch(getAllCustomer({ CompId, AppId, branchId: BranchId }))
.unwrap()
.then((res) => setAllCustomers(res?.data?.data || []));
if (!CompId || !AppId || !BranchId) return;
setAllCustomers([]);
setProductQuantities({});
}, [CompId, AppId, BranchId, dispatch, customerRefreshTrigger]);
@ -540,6 +548,9 @@ const BSCustomerSelect = ({ TopName = null }) => {
)
);
}
if (selectedOption === undefined || selectedOption === null) {
setAllCustomers([]);
}
setCustomerpreorder(true);
};
@ -978,6 +989,33 @@ const BSCustomerSelect = ({ TopName = null }) => {
setMessageType(null);
}, []);
let debounceTimer;
const debounceSearch = (value) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
handleSearchCustomer(value, false);
}, 500);
};
const handleSearchCustomer = async (value, open = true) => {
const data = {
AppId,
CompId,
branchId: BranchId,
searchValue: value,
}
const response = await dispatch(getSearchedCustomer(data))?.unwrap(); // your API
if (response?.data?.data?.length > 0 && response?.data?.statusCode === 1) {
setAllCustomers(response?.data?.data || []);
} else if (open) {
handleAddCustomer(value);
} else if (!open) {
setAllCustomers([]);
}
};
// Render
return (
<>
@ -1078,14 +1116,25 @@ const BSCustomerSelect = ({ TopName = null }) => {
className="customer-select-option"
onInputChange={(value) => {
if (!value) return;
const onlyNumbers = /^\d+$/.test(value);
const isIndianMobile =
/^\d{10}$/.test(value) && /^[6-9]/.test(value);
const existingCustomer = options?.filter(
(option) => option?.value === value || option?.label === value
);
if (isIndianMobile && existingCustomer?.length === 0) {
handleAddCustomer(value);
// const existingCustomer = options?.filter(
// (option) => option?.value === value || option?.label === value
// );
// if (isIndianMobile && existingCustomer?.length === 0) {
// handleAddCustomer(value);
// }
if (onlyNumbers && isIndianMobile) {
handleSearchCustomer(value);
return;
}
if (/[a-zA-Z]/.test(value)) {
debounceSearch(value);
}
}}
/>

View File

@ -433,11 +433,16 @@ const BranchLogin = () => {
{CompBranchData?.map((branch) => (
<div
key={branch.BrId}
style={{ cursor: 'pointer' }}
className={
branch?.LocationType === 'W'
? 'GodownLoginCard'
: 'brachLoginCard'
}
onClick={(e) => {
e.stopPropagation();
onChangeBranch(branch?.BrId);
}}
>
<div className="branchLoginCardContent">
{branch?.LocationType === 'W' ? (
@ -477,7 +482,7 @@ const BranchLogin = () => {
? 'openGodownBTN'
: 'openBrachBTN'
}
onClick={() => onChangeBranch(branch?.BrId)}
// onClick={() => onChangeBranch(branch?.BrId)}
>
{branch?.LocationType === 'W'
? 'Open Warehouse'
@ -562,13 +567,11 @@ const BranchLogin = () => {
{SelectTypeName === 'OTP'
? !FirstTimeOtp
? `send ${SelectTypeName.toLocaleLowerCase()}`
: `resend ${SelectTypeName.toLocaleLowerCase()}${
seconds > 0 ? ` in ${seconds}s` : ''
: `resend ${SelectTypeName.toLocaleLowerCase()}${seconds > 0 ? ` in ${seconds}s` : ''
}`
: !FirstTimePin
? `send ${SelectTypeName.toLocaleLowerCase()}`
: `resend ${SelectTypeName.toLocaleLowerCase()}${
seconds > 0 ? ` in ${seconds}s` : ''
: `resend ${SelectTypeName.toLocaleLowerCase()}${seconds > 0 ? ` in ${seconds}s` : ''
}`}
</button>
</div>

View File

@ -28,6 +28,9 @@ import '../../../Styles/Reports/LedgerReport/LedgerReport.scss';
import { isMobile } from 'react-device-detect';
import { ReportMobilePDFPrint } from '../../paymentpdfPage/ReportMobilePDFPrint.js';
import { useSelector } from 'react-redux';
import excelExport from '../../../Images/xls-export.png';
import ExcelJS from 'exceljs';
import { saveAs } from 'file-saver';
dayjs.extend(customParseFormat);
@ -403,6 +406,215 @@ const LedgerReport = () => {
}
};
const exportToExcel = async () => {
if (!LedgerData || LedgerData.length === 0) return;
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("Ledger Report");
worksheet.views = [
{
state: "frozen",
ySplit: 2
}
];
// HEADER ROW 1
worksheet.addRow([
"SI No",
"Type",
"Cus-Id",
"Cus-Name",
"RC.NO",
"Mob.No",
"Address",
"Payment Mode",
"Date",
"Debit",
"Credit",
"Balance in",
""
]);
// HEADER ROW 2
worksheet.addRow([
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Credit",
"Debit"
]);
// MERGE CELLS
worksheet.mergeCells("A1:A2");
worksheet.mergeCells("B1:B2");
worksheet.mergeCells("C1:C2");
worksheet.mergeCells("D1:D2");
worksheet.mergeCells("E1:E2");
worksheet.mergeCells("F1:F2");
worksheet.mergeCells("G1:G2");
worksheet.mergeCells("H1:H2");
worksheet.mergeCells("I1:I2");
worksheet.mergeCells("J1:J2");
worksheet.mergeCells("K1:K2");
worksheet.mergeCells("L1:M1");
// worksheet.eachRow((row) => {
// row.eachCell((cell) => {
// cell.protection = {
// locked: true
// };
// });
// });
// Lock header rows
[1, 2].forEach((rowNumber) => {
const row = worksheet.getRow(rowNumber);
row.eachCell((cell) => {
cell.protection = { locked: true };
});
});
// HEADER STYLE
const headerRows = [1, 2];
headerRows.forEach((rowNumber) => {
const row = worksheet.getRow(rowNumber);
row.eachCell((cell) => {
cell.font = {
bold: true,
color: { argb: "FFFFFFFF" } // white text
};
cell.alignment = {
vertical: "middle",
horizontal: "center"
};
cell.fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: "FF2E7D32" } // green header
};
cell.border = {
top: { style: "thin" },
left: { style: "thin" },
bottom: { style: "thin" },
right: { style: "thin" }
};
});
});
// specifically ensure Balance in header center
worksheet.getCell("L1").alignment = { horizontal: "center", vertical: "middle" };
// COLUMN WIDTH
worksheet.columns = [
{ width: 8 },
{ width: 10 },
{ width: 12 },
{ width: 20 },
{ width: 12 },
{ width: 15 },
{ width: 25 },
{ width: 15 },
{ width: 15 },
{ width: 12 },
{ width: 12 },
{ width: 12 },
{ width: 12 }
];
// DATA ROWS
LedgerData.forEach((row, index) => {
const r = worksheet.addRow([
index + 1,
row.TypeName === "OB" ? "OB" : row.TypeName,
row.CustId ? extractLastNumber(row.CustId) : "GEN",
row.CustName || "",
row.ReceiptNo || "",
row.MobileNo || "",
row.Address1 || "",
row.PaymentTypeName || "",
ExtractDateFormate(row.Date) || "",
row.Debit > 0 ? row.Debit : "",
row.Credit > 0 ? row.Credit : "",
row.BalCredit > 0 ? row.BalCredit : "",
row.BalDebit > 0 ? row.BalDebit : ""
]);
// 🔓 Unlock every cell in this row
r.eachCell({ includeEmpty: true }, (cell) => {
cell.protection = { locked: false };
});
// Credit red
if (row.BalCredit > 0) {
r.getCell(12).font = { color: { argb: "FFFF0000" } };
}
// Debit green
if (row.BalDebit > 0) {
r.getCell(13).font = { color: { argb: "FF008000" } };
}
});
// Unlock all data rows
worksheet.eachRow((row, rowNumber) => {
if (rowNumber > 2) {
row.eachCell((cell) => {
cell.protection = { locked: false };
});
}
});
await worksheet.protect("ledger123", {
selectLockedCells: true,
selectUnlockedCells: true,
formatColumns: true, // allow column resize
formatRows: false,
insertColumns: false,
insertRows: false,
deleteColumns: false,
deleteRows: false
});
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-of ficedocument.spreadsheetml.sheet"
});
const now = new Date();
const day = String(now.getDate()).padStart(2, "0");
const month = String(now.getMonth() + 1).padStart(2, "0");
const year = now.getFullYear();
let hours = now.getHours();
const minutes = String(now.getMinutes()).padStart(2, "0");
const ampm = hours >= 12 ? "PM" : "AM";
hours = hours % 12;
hours = hours ? hours : 12;
hours = String(hours).padStart(2, "0");
const fileName = `Ledger Report_${day}-${month}-${year}_${hours}-${minutes}-${ampm}.xlsx`;
saveAs(blob, fileName);
};
const FirstOrderLedgerDateRaw = dayjs(FirstOrderLedgerDate);
const disabledDate = (current) => {
@ -621,13 +833,24 @@ const LedgerReport = () => {
</div>
<div className="ledger-PrintIcon">
<BiSolidPrinter
onClick={Print}
onClick={LedgerData?.length > 0 ? () => Print() : (() => { })}
className={
LedgerData?.length > 0
? 'ItemWiseReport-printerIcon'
: 'ItemWiseReport-printerIcon-disabled'
}
/>
<Tooltip title={LedgerData?.length > 0 ? "Export as Excel" : "No data to Export"} placement="top">
<div style={{ width: '35px', height: '35px', display: 'flex', justifyContent: 'center', alignItems: 'center', cursor: LedgerData?.length > 0 ? 'pointer' : 'not-allowed', opacity: LedgerData?.length > 0 ? 1 : 0.5 }}>
<img
width={'95%'}
height={'95%'}
src={excelExport}
alt="Excel Export"
onClick={LedgerData?.length > 0 ? () => exportToExcel() : (() => { })}
/>
</div>
</Tooltip>
</div>
</div>
</div>

View File

@ -88,8 +88,30 @@
// overflow-x: scroll;
}
.ItemWiseReport-printerIcon-disabled {
opacity: 0.5;
cursor: not-allowed;
font-size: 30px;
}
.ItemWiseReport-printerIcon {
font-size: 25px;
cursor: pointer;
}
.ItemWiseReport-printerIcon:hover {
color: #414141;
}
.ItemWiseReport-printerIcon {
font-size: 30px;
}
.ledger-PrintIcon {
font-size: xx-large;
display: flex;
align-items: center;
gap: 0.5rem;
}
.RadioButton-DMYPicker {
@ -332,6 +354,7 @@
}
.custom-table {
Button:disabled,
Button[disabled] {
width: unset !important;