Files
cbsnexora/src/app/digital/imps-report/imps-report.component.ts
T
AdityaandClaude Opus 4.7 325228c514 feat: letter-mgmt module + digital UPI/IMPS/ATM-POS reports + header redesign
letter-mgmt (new module):
- Notice page: overdue loan list with filters, KPI strip, bulk actions,
  call disposition logging (Promise-to-Pay, Not Reachable, etc.), Speed
  Post dispatch dialog with consignment + post-office tracking,
  PDF preview + download, call-contact dialog with primary / alt /
  family / nominee numbers and per-contact disposition history.
- Certificates: Loan Interest, Share, Balance, Form 60 (no-PAN flow),
  Form 15G/H (auto age-based), Hypothecation, NOC - each with shared
  preview dialog (six tone variants) and jsPDF generator using a
  common letterhead / summary-grid / signature-seal helper.

digital:
- IMPS module: report (P2A/P2P/Aadhaar tabs) + entry form with
  MMID/mobile lookup, NPCI switch resolve-to-A/C+IFSC BANL flow,
  sender autocomplete, hide sender field for P2P/Aadhaar, charges +
  18% GST + waive checkbox, per-sender today-only history dialog.
- UPI report with app-mix tab and full transaction filtering.
- ATM/POS/ECOM hub with three ticket cards routing to today/status/cycle.
- NEFT/RTGS entry: sender-account autocomplete, charges + GST + waive,
  field reorder (sender before amount), NEFT cap / RTGS floor
  validation, History button opening per-sender today's transactions.
- NEFT/RTGS report: horizontal-bar trend leaderboard replacing tall bars.

shell + theme:
- Header redesigned with IBM Plex Sans 12/500 typography, 11-column grid
  per row, top-accent hover indicator, bordered cells via grid-gap.
- Live KPI ticker below menu (CASH, TXN TODAY, CLEARING IN/OUT, NPA,
  CASA, CD RATIO, RBI CIRC, REPO) with marquee scroll, pause-on-hover,
  brand-blue gradient, amber bottom strip, pulsing red LIVE chip.
- Sidebar 'KYC Management' -> 'KYC & ReKYC Management'.
- Letter Mgmt / certificate menu items wired with green icon hints for
  items that have a working page.

access-control:
- MFA card layout compacted; method header inlines back button + title.

icons:
- Register faTruck/TruckFast, faEllipsisV/H, faCommentDots.
- Add IBM Plex Sans Google Fonts import to index.html.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 10:09:06 +05:30

718 lines
21 KiB
TypeScript

/**
* Copyright since 2025 Mifos Initiative
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Component, inject, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { MatDialog } from '@angular/material/dialog';
import { MatTooltip } from '@angular/material/tooltip';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
import { ImpsEntryComponent } from '../imps-entry/imps-entry.component';
/** Person-to-Account, Person-to-Person (MMID+Mobile), Person-to-Aadhaar. */
export type ImpsTxnType = 'P2A' | 'P2P' | 'P2AADHAAR';
export type ImpsState = 'INITIATED' | 'SENT' | 'SUCCESS' | 'PENDING' | 'FAILED' | 'REVERSED';
export interface ImpsTxn {
rrn: string;
utr: string;
remitterAcc: string;
remitterBranch: string;
remitterUser: string;
remitterChannel: 'BRANCH' | 'MOBILE';
/** P2A populates these. */
beneAcc?: string;
beneIfsc?: string;
/** P2P populates these. */
beneMmid?: string;
beneMobile?: string;
/** P2AADHAAR populates this. */
beneAadhaar?: string;
beneName: string;
beneBank: string;
txnType: ImpsTxnType;
amount: number;
valueDate: string;
purposeCode: string;
state: ImpsState;
failureCode?: string;
failureReason?: string;
sentTimestamp: string;
}
type ReportTab = 'trends' | 'bank' | 'date' | 'pending' | 'channel' | 'user';
interface BankRow {
bank: string;
count: number;
amount: number;
success: number;
pending: number;
failed: number;
}
interface DateRow {
date: string;
count: number;
amount: number;
p2a: number;
p2p: number;
}
interface UserRow {
user: string;
count: number;
amount: number;
branch: string;
}
interface ChannelRow {
channel: 'BRANCH' | 'MOBILE';
count: number;
amount: number;
share: number;
}
@Component({
selector: 'mifosx-imps-report',
templateUrl: './imps-report.component.html',
styleUrls: ['../neft-rtgs-report/neft-rtgs-report.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
FormsModule,
FaIconComponent,
MatTooltip
]
})
export class ImpsReportComponent implements OnInit {
private dialog = inject(MatDialog);
activeTab: ReportTab = 'trends';
search = '';
typeFilter: '' | ImpsTxnType = '';
stateFilter: '' | ImpsState = '';
txns: ImpsTxn[] = [];
readonly tabs: { id: ReportTab; label: string; icon: string }[] = [
{ id: 'trends', label: 'Trends', icon: 'chart-line' },
{ id: 'bank', label: 'Bank-wise', icon: 'university' },
{ id: 'date', label: 'Date-wise', icon: 'calendar-alt' },
{ id: 'pending', label: 'Success / Pending / Failed', icon: 'tasks' },
{ id: 'channel', label: 'Branch / Mobile', icon: 'mobile-alt' },
{ id: 'user', label: 'User-wise', icon: 'user-tie' }
];
ngOnInit(): void {
this.txns = seedImpsTransactions();
}
// ───────────────────── KPIs ─────────────────────
get totalCount(): number {
return this.txns.length;
}
get totalAmount(): number {
return this.txns.reduce((s, t) => s + t.amount, 0);
}
get successCount(): number {
return this.txns.filter((t) => t.state === 'SUCCESS').length;
}
get pendingCount(): number {
return this.txns.filter((t) => [
'INITIATED',
'SENT',
'PENDING'
].includes(t.state)).length;
}
get failedCount(): number {
return this.txns.filter((t) => t.state === 'FAILED' || t.state === 'REVERSED').length;
}
get p2aCount(): number {
return this.txns.filter((t) => t.txnType === 'P2A').length;
}
get p2pCount(): number {
return this.txns.filter((t) => t.txnType === 'P2P').length;
}
get successRate(): number {
if (this.totalCount === 0) return 0;
return (this.successCount / this.totalCount) * 100;
}
get avgTicket(): number {
if (this.totalCount === 0) return 0;
return this.totalAmount / this.totalCount;
}
// ───────────────────── Filtered list ─────────────────────
get filteredTxns(): ImpsTxn[] {
const q = this.search.trim().toLowerCase();
return this.txns.filter((t) => {
if (this.typeFilter && t.txnType !== this.typeFilter) return false;
if (this.stateFilter && t.state !== this.stateFilter) return false;
if (!q) return true;
return (
t.rrn.toLowerCase().includes(q) ||
t.utr.toLowerCase().includes(q) ||
(t.beneAcc || '').toLowerCase().includes(q) ||
(t.beneIfsc || '').toLowerCase().includes(q) ||
(t.beneMmid || '').toLowerCase().includes(q) ||
(t.beneMobile || '').toLowerCase().includes(q) ||
t.beneName.toLowerCase().includes(q) ||
t.remitterAcc.toLowerCase().includes(q)
);
});
}
// ───────────────────── Aggregations ─────────────────────
get bankRows(): BankRow[] {
const map = new Map<string, BankRow>();
for (const t of this.txns) {
const key = t.beneBank;
if (!map.has(key)) {
map.set(key, { bank: key, count: 0, amount: 0, success: 0, pending: 0, failed: 0 });
}
const r = map.get(key)!;
r.count++;
r.amount += t.amount;
if (t.state === 'SUCCESS') r.success++;
else if (t.state === 'FAILED' || t.state === 'REVERSED') r.failed++;
else r.pending++;
}
return Array.from(map.values()).sort((a, b) => b.amount - a.amount);
}
get dateRows(): DateRow[] {
const map = new Map<string, DateRow>();
for (const t of this.txns) {
if (!map.has(t.valueDate)) {
map.set(t.valueDate, { date: t.valueDate, count: 0, amount: 0, p2a: 0, p2p: 0 });
}
const r = map.get(t.valueDate)!;
r.count++;
r.amount += t.amount;
if (t.txnType === 'P2A') r.p2a++;
else if (t.txnType === 'P2P') r.p2p++;
}
return Array.from(map.values()).sort((a, b) => (a.date < b.date ? 1 : -1));
}
get userRows(): UserRow[] {
const map = new Map<string, UserRow>();
for (const t of this.txns) {
const key = `${t.remitterUser}|${t.remitterBranch}`;
if (!map.has(key)) {
map.set(key, { user: t.remitterUser, branch: t.remitterBranch, count: 0, amount: 0 });
}
const r = map.get(key)!;
r.count++;
r.amount += t.amount;
}
return Array.from(map.values()).sort((a, b) => b.amount - a.amount);
}
get channelRows(): ChannelRow[] {
const total = this.totalAmount || 1;
const map = new Map<'BRANCH' | 'MOBILE', ChannelRow>();
for (const t of this.txns) {
if (!map.has(t.remitterChannel)) {
map.set(t.remitterChannel, { channel: t.remitterChannel, count: 0, amount: 0, share: 0 });
}
const r = map.get(t.remitterChannel)!;
r.count++;
r.amount += t.amount;
}
map.forEach((r) => (r.share = (r.amount / total) * 100));
return Array.from(map.values());
}
get trendBuckets(): DateRow[] {
return this.dateRows.slice(0, 7).reverse();
}
get trendMaxAmount(): number {
const buckets = this.trendBuckets;
if (!buckets.length) return 1;
return Math.max(...buckets.map((b) => b.amount));
}
get failureCodeRows(): { code: string; reason: string; count: number; amount: number }[] {
const map = new Map<string, { code: string; reason: string; count: number; amount: number }>();
for (const t of this.txns) {
if (!(t.state === 'FAILED' || t.state === 'REVERSED') || !t.failureCode) continue;
if (!map.has(t.failureCode)) {
map.set(t.failureCode, {
code: t.failureCode,
reason: t.failureReason || '',
count: 0,
amount: 0
});
}
const r = map.get(t.failureCode)!;
r.count++;
r.amount += t.amount;
}
return Array.from(map.values()).sort((a, b) => b.count - a.count);
}
// ───────────────────── Actions ─────────────────────
showTab(tab: ReportTab): void {
this.activeTab = tab;
}
openInitiateDialog(): void {
const ref = this.dialog.open(ImpsEntryComponent, {
width: '880px',
maxWidth: '94vw',
maxHeight: '88vh',
disableClose: true,
autoFocus: false,
restoreFocus: true,
panelClass: 'nr-entry-dialog',
backdropClass: 'nr-entry-backdrop'
});
ref.afterClosed().subscribe((result) => {
if (result && result.submitted && result.payload) {
this.txns = [
this.toTxn(result.payload),
...this.txns
];
}
});
}
exportCsv(): void {
const headers = [
'RRN',
'UTR',
'Remitter Acc',
'Bene Acc / MMID / Aadhaar',
'Bene IFSC / Mobile',
'Bene Name',
'Txn Type',
'Amount',
'Value Date',
'Purpose Code',
'State',
'Failure Code',
'Sent Timestamp'
];
const rows: string[][] = [headers];
for (const t of this.filteredTxns) {
rows.push([
t.rrn,
t.utr,
t.remitterAcc,
t.beneAcc || t.beneMmid || t.beneAadhaar || '',
t.beneIfsc || t.beneMobile || '',
t.beneName,
t.txnType,
t.amount.toFixed(2),
t.valueDate,
t.purposeCode,
t.state,
t.failureCode || '',
t.sentTimestamp
]);
}
const escape = (v: string): string => {
const s = (v || '').replace(/"/g, '""');
return /[,"\n]/.test(s) ? `"${s}"` : s;
};
const csv = rows.map((r) => r.map(escape).join(',')).join('\n') + '\n';
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `IMPS_Report_${new Date().toISOString().slice(0, 10)}.csv`;
a.click();
URL.revokeObjectURL(url);
}
clearFilters(): void {
this.search = '';
this.typeFilter = '';
this.stateFilter = '';
}
// ───────────────────── Helpers ─────────────────────
stateColor(state: ImpsState): string {
switch (state) {
case 'SUCCESS':
return 'green';
case 'FAILED':
case 'REVERSED':
return 'red';
case 'SENT':
return 'blue';
case 'INITIATED':
return 'teal';
case 'PENDING':
return 'amber';
}
}
trendBarHeight(amount: number): number {
return Math.max(6, Math.round((amount / this.trendMaxAmount) * 100));
}
private toTxn(p: any): ImpsTxn {
const valueDate = p.valueDate
? new Date(p.valueDate).toISOString().slice(0, 10)
: new Date().toISOString().slice(0, 10);
const ts = new Date();
const pad = (n: number) => String(n).padStart(2, '0');
return {
rrn: 'IMPS' + Date.now().toString().slice(-10),
utr: 'UTR' + Date.now().toString().slice(-11),
remitterAcc: p.senderAccount || '',
remitterBranch: 'Main Branch',
remitterUser: 'Current User',
remitterChannel: 'BRANCH',
beneAcc: p.beneficiaryAccount,
beneIfsc: (p.ifscCode || '').toUpperCase() || undefined,
beneMmid: p.beneMmid,
beneMobile: p.beneMobile,
beneAadhaar: p.beneAadhaar,
beneName: p.beneficiaryName || '',
beneBank: this.bankFromIfsc(p.ifscCode || ''),
txnType: p.txnType || 'P2A',
amount: Number(p.amount) || 0,
valueDate,
purposeCode: this.purposeCodeFor(p.purposeOfRemittance),
state: 'INITIATED',
sentTimestamp:
ts.getFullYear() +
'-' +
pad(ts.getMonth() + 1) +
'-' +
pad(ts.getDate()) +
' ' +
pad(ts.getHours()) +
':' +
pad(ts.getMinutes()) +
':' +
pad(ts.getSeconds())
};
}
private bankFromIfsc(ifsc: string): string {
const code = ifsc.slice(0, 4).toUpperCase();
const map: Record<string, string> = {
HDFC: 'HDFC Bank',
ICIC: 'ICICI Bank',
SBIN: 'State Bank of India',
KKBK: 'Kotak Mahindra Bank',
AXIS: 'Axis Bank',
UTIB: 'Axis Bank',
PUNB: 'Punjab National Bank',
BARB: 'Bank of Baroda',
CNRB: 'Canara Bank',
YESB: 'YES Bank',
IDFB: 'IDFC FIRST Bank'
};
return map[code] || code + ' Bank';
}
private purposeCodeFor(p: string): string {
const map: Record<string, string> = {
CAPITAL_TRANSFER: 'P0102',
FAMILY_MAINTENANCE: 'P1301',
TRADE_SETTLEMENT: 'P0801',
SALARY_PAYMENT: 'P1006',
LOAN_REPAYMENT: 'P0103',
TAX_PAYMENT: 'P1099',
VENDOR_PAYMENT: 'P0802',
INVESTMENT: 'P0202',
GIFT: 'P1302',
OTHER: 'P0099'
};
return map[p] || 'P0099';
}
// ───────────────────── Mock seed data ─────────────────────
/** @deprecated Use the exported `seedImpsTransactions()` instead. */
private seedTransactions(): ImpsTxn[] {
return seedImpsTransactions();
}
}
// ───────────────────── Shared mock seed (top-level export) ─────────────────────
/**
* Mock IMPS history. Exported so the entry form (and any per-sender history dialogs)
* can render from the same dataset. Replace with an API call when the back-end is wired.
*/
export function seedImpsTransactions(): ImpsTxn[] {
const today = new Date();
const dt = (offset: number, h = 10, m = 0): string => {
const d = new Date(today);
d.setDate(d.getDate() - offset);
const pad = (n: number) => String(n).padStart(2, '0');
return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate()) + ' ' + pad(h) + ':' + pad(m) + ':00';
};
const vd = (offset: number): string => dt(offset).slice(0, 10);
return [
{
rrn: 'IMPS2608517721',
utr: 'UTRKKBK52026081',
remitterAcc: '50200012345678',
remitterBranch: 'Mumbai — BKC',
remitterUser: 'Anita Desai',
remitterChannel: 'MOBILE',
beneMmid: '9234567',
beneMobile: '9821234567',
beneName: 'Rohan S. Mehta',
beneBank: 'HDFC Bank',
txnType: 'P2P',
amount: 12500,
valueDate: vd(0),
purposeCode: 'P1301',
state: 'SUCCESS',
sentTimestamp: dt(0, 14, 5)
},
{
rrn: 'IMPS2608517722',
utr: 'UTRHDFC2608712',
remitterAcc: '50200012345678',
remitterBranch: 'Mumbai — BKC',
remitterUser: 'Anita Desai',
remitterChannel: 'BRANCH',
beneAcc: '345678901234',
beneIfsc: 'ICIC0000567',
beneName: 'Bluestone Trading Co.',
beneBank: 'ICICI Bank',
txnType: 'P2A',
amount: 78500,
valueDate: vd(0),
purposeCode: 'P0802',
state: 'SENT',
sentTimestamp: dt(0, 14, 6)
},
{
rrn: 'IMPS2608517723',
utr: 'UTRSBIN2608902',
remitterAcc: '50200099887766',
remitterBranch: 'Bengaluru — MG Road',
remitterUser: 'Karthik Rao',
remitterChannel: 'MOBILE',
beneMmid: '9128831',
beneMobile: '9845112233',
beneName: 'Anita Verma',
beneBank: 'State Bank of India',
txnType: 'P2P',
amount: 4500,
valueDate: vd(1),
purposeCode: 'P1301',
state: 'SUCCESS',
sentTimestamp: dt(1, 11, 22)
},
{
rrn: 'IMPS2608517724',
utr: 'UTRAXIS2608811',
remitterAcc: '50200099887766',
remitterBranch: 'Bengaluru — MG Road',
remitterUser: 'Karthik Rao',
remitterChannel: 'MOBILE',
beneAcc: '6789012345',
beneIfsc: 'UTIB0000456',
beneName: 'Rakesh Industries',
beneBank: 'Axis Bank',
txnType: 'P2A',
amount: 195000,
valueDate: vd(1),
purposeCode: 'P0801',
state: 'FAILED',
failureCode: 'E03',
failureReason: 'Beneficiary Bank Not Available',
sentTimestamp: dt(1, 11, 25)
},
{
rrn: 'IMPS2608517725',
utr: 'UTRPUNB2608619',
remitterAcc: '50100221122334',
remitterBranch: 'Delhi — Connaught',
remitterUser: 'Sushma Iyer',
remitterChannel: 'BRANCH',
beneAcc: '50100998877665',
beneIfsc: 'PUNB0123400',
beneName: 'Madhavi Singh',
beneBank: 'Punjab National Bank',
txnType: 'P2A',
amount: 42000,
valueDate: vd(2),
purposeCode: 'P1006',
state: 'SUCCESS',
sentTimestamp: dt(2, 9, 35)
},
{
rrn: 'IMPS2608517726',
utr: 'UTRYESB2608520',
remitterAcc: '50100221122334',
remitterBranch: 'Delhi — Connaught',
remitterUser: 'Sushma Iyer',
remitterChannel: 'BRANCH',
beneMmid: '9001122',
beneMobile: '9818877665',
beneName: 'Sigma Constructions',
beneBank: 'YES Bank',
txnType: 'P2P',
amount: 18500,
valueDate: vd(2),
purposeCode: 'P0102',
state: 'PENDING',
sentTimestamp: dt(2, 9, 38)
},
{
rrn: 'IMPS2608517727',
utr: 'UTRCNRB2608417',
remitterAcc: '50100887766554',
remitterBranch: 'Chennai — T. Nagar',
remitterUser: 'Ramesh Krishnan',
remitterChannel: 'MOBILE',
beneMmid: '9889911',
beneMobile: '9840012345',
beneName: 'Padma Rao',
beneBank: 'Canara Bank',
txnType: 'P2P',
amount: 2800,
valueDate: vd(3),
purposeCode: 'P1302',
state: 'SUCCESS',
sentTimestamp: dt(3, 16, 15)
},
{
rrn: 'IMPS2608517728',
utr: 'UTRBARB2608318',
remitterAcc: '50100887766554',
remitterBranch: 'Chennai — T. Nagar',
remitterUser: 'Ramesh Krishnan',
remitterChannel: 'BRANCH',
beneAcc: '50100123456987',
beneIfsc: 'BARB0VJVATA',
beneName: 'Vijaya Traders',
beneBank: 'Bank of Baroda',
txnType: 'P2A',
amount: 125000,
valueDate: vd(3),
purposeCode: 'P0802',
state: 'INITIATED',
sentTimestamp: dt(3, 16, 20)
},
{
rrn: 'IMPS2608517729',
utr: 'UTRIDFB2608215',
remitterAcc: '50200445566778',
remitterBranch: 'Pune — Koregaon Park',
remitterUser: 'Vikram Joshi',
remitterChannel: 'BRANCH',
beneAadhaar: 'XXXX-XXXX-7891',
beneName: 'Pinnacle Realty Pvt Ltd',
beneBank: 'IDFC FIRST Bank',
txnType: 'P2AADHAAR',
amount: 145000,
valueDate: vd(4),
purposeCode: 'P0202',
state: 'SUCCESS',
sentTimestamp: dt(4, 12, 45)
},
{
rrn: 'IMPS2608517730',
utr: 'UTRHDFC2608116',
remitterAcc: '50200445566778',
remitterBranch: 'Pune — Koregaon Park',
remitterUser: 'Vikram Joshi',
remitterChannel: 'MOBILE',
beneMmid: '9650432',
beneMobile: '9890065432',
beneName: 'Neha Kapoor',
beneBank: 'HDFC Bank',
txnType: 'P2P',
amount: 6500,
valueDate: vd(4),
purposeCode: 'P1301',
state: 'SUCCESS',
sentTimestamp: dt(4, 12, 50)
},
{
rrn: 'IMPS2608517731',
utr: 'UTRKKBK2608013',
remitterAcc: '50200778899001',
remitterBranch: 'Hyderabad — Banjara',
remitterUser: 'Lakshmi Naidu',
remitterChannel: 'BRANCH',
beneAcc: '12345678900011',
beneIfsc: 'KKBK0001899',
beneName: 'Aarav Enterprises',
beneBank: 'Kotak Mahindra Bank',
txnType: 'P2A',
amount: 67000,
valueDate: vd(5),
purposeCode: 'P0802',
state: 'REVERSED',
failureCode: 'E11',
failureReason: 'Beneficiary Account Closed',
sentTimestamp: dt(5, 10, 5)
},
{
rrn: 'IMPS2608517732',
utr: 'UTRSBIN2607914',
remitterAcc: '50200778899001',
remitterBranch: 'Hyderabad — Banjara',
remitterUser: 'Lakshmi Naidu',
remitterChannel: 'BRANCH',
beneMmid: '9445566',
beneMobile: '9849988776',
beneName: 'Spectra Components',
beneBank: 'State Bank of India',
txnType: 'P2P',
amount: 9800,
valueDate: vd(5),
purposeCode: 'P0801',
state: 'SUCCESS',
sentTimestamp: dt(5, 10, 10)
},
{
rrn: 'IMPS2608517733',
utr: 'UTRICIC2607812',
remitterAcc: '50100334455667',
remitterBranch: 'Kolkata — Park Street',
remitterUser: 'Arjun Banerjee',
remitterChannel: 'MOBILE',
beneAcc: '88990011223344',
beneIfsc: 'ICIC0001234',
beneName: 'Eastern Logistics',
beneBank: 'ICICI Bank',
txnType: 'P2A',
amount: 88000,
valueDate: vd(6),
purposeCode: 'P0802',
state: 'SUCCESS',
sentTimestamp: dt(6, 14, 30)
},
{
rrn: 'IMPS2608517734',
utr: 'UTRAXIS2607711',
remitterAcc: '50100334455667',
remitterBranch: 'Kolkata — Park Street',
remitterUser: 'Arjun Banerjee',
remitterChannel: 'BRANCH',
beneMmid: '9009988',
beneMobile: '9831100225',
beneName: 'Indrani Sen',
beneBank: 'Axis Bank',
txnType: 'P2P',
amount: 2200,
valueDate: vd(6),
purposeCode: 'P1302',
state: 'SUCCESS',
sentTimestamp: dt(6, 14, 32)
}
];
}