2025-08-19 22:07:44 -07:00
const testEmails = [
2025-08-21 16:54:47 -07:00
` Dear Customer, Rs.20.00 has been debited from account 5488 to VPA paytm.s1eeznf@pty SHS CANTEEN 1 on 18-08-25. Your UPI transaction reference number is 109983023268. If you did not authorize this `
2025-08-19 22:07:44 -07:00
] ;
2025-08-21 20:11:18 -07:00
function parseBankMessage ( email ) {
2025-08-19 22:07:44 -07:00
const result = {
amount : null ,
vendor : null ,
2025-08-21 20:11:18 -07:00
rawVendor : null ,
2025-08-19 22:07:44 -07:00
type : null ,
date : null ,
referenceNumber : null ,
} ;
2025-08-21 22:17:16 -07:00
// ---------- Amount ----------
2025-08-21 20:11:18 -07:00
const amtMatch = email . match ( /(?:Rs\.?|INR)\s*([\d,]+\.?\d*)/i ) ;
2025-08-19 22:07:44 -07:00
if ( amtMatch ) result . amount = parseFloat ( amtMatch [ 1 ] . replace ( /,/g , "" ) ) ;
2025-08-21 22:17:16 -07:00
// ---------- Debit / Credit ----------
2025-08-21 20:11:18 -07:00
if ( /debited/i . test ( email ) ) result . type = "debit" ;
else if ( /credited/i . test ( email ) ) result . type = "credit" ;
2025-08-19 22:07:44 -07:00
2025-08-21 22:17:16 -07:00
// ---------- Date ----------
2025-08-21 20:11:18 -07:00
const dateMatch = email . match ( /on\s+(\d{2}[-/]\d{2}[-/]\d{2,4})/i ) ;
if ( dateMatch ) result . date = dateMatch [ 1 ] ;
2025-08-21 16:54:47 -07:00
2025-08-21 22:17:16 -07:00
// ---------- Reference Number ----------
const refMatch = email . match ( /(?:reference number is|UPI transaction reference number is|Ref No:?)\s*([A-Za-z0-9]+)/i ) ;
2025-08-21 20:11:18 -07:00
if ( refMatch ) result . referenceNumber = refMatch [ 1 ] . trim ( ) ;
2025-08-19 22:07:44 -07:00
2025-08-21 22:17:16 -07:00
// ---------- Vendor Extraction ----------
let vendorCandidate = null ;
// 1. Prefer "to VPA ..." pattern, stop at 'on|your|Ref|Txn' etc.
const toMatch = email . match ( /to\s+(?:VPA\s+)?(?:[^\s@]+\@[^\s]+\s+)?([A-Za-z0-9\s&.-]+)/i ) ;
if ( toMatch ) {
vendorCandidate = toMatch [ 1 ]
. split ( / on | your | ref | txn | transaction | number /i ) [ 0 ] // cut off junk
. trim ( ) ;
}
// 2. Fallback: fully uppercase phrases
if ( ! vendorCandidate ) {
const upperMatch = email . match ( /(?:\b[A-Z][A-Z0-9&.-]+\b(?:\s)?)+/g ) ;
if ( upperMatch ) {
vendorCandidate = upperMatch [ upperMatch . length - 1 ] . trim ( ) ;
2025-08-19 22:07:44 -07:00
}
}
2025-08-21 22:17:16 -07:00
// Assign rawVendor
if ( vendorCandidate ) {
result . rawVendor = vendorCandidate ;
}
2025-08-21 20:11:18 -07:00
// ---------- Cleaning Pipeline ----------
if ( result . rawVendor ) {
let v = result . rawVendor ;
// Remove noise keywords
2025-08-21 22:17:16 -07:00
v = v . replace ( /\b(?:UPI|VPA|REF|Txn|Order|Payment|NEFT|IMPS|Transaction|Number|Your)\b/gi , "" ) ;
// Remove emails
v = v . replace ( /[a-z0-9._%+-]+@[a-z0-9.-]+/gi , "" ) ;
// Remove dates & numbers that sneak in
v = v . replace ( /\d{2}[-/]\d{2}[-/]\d{2,4}/g , "" ) ;
v = v . replace ( /\b\d{6,}\b/g , "" ) ; // strip long numbers like reference ids
2025-08-21 20:11:18 -07:00
// Replace underscores/dashes with space
2025-08-21 22:17:16 -07:00
v = v . replace ( /[_\-]+/g , " " ) ;
2025-08-21 20:11:18 -07:00
// Collapse multiple spaces
2025-08-21 22:17:16 -07:00
v = v . replace ( /\s{2,}/g , " " ) . trim ( ) ;
2025-08-21 20:11:18 -07:00
2025-08-21 22:17:16 -07:00
// Normalize casing
v = v . toLowerCase ( ) . replace ( /\b\w/g , ( c ) => c . toUpperCase ( ) ) ;
2025-08-21 20:11:18 -07:00
result . vendor = v ;
2025-08-21 16:54:47 -07:00
}
2025-08-19 22:07:44 -07:00
return result ;
}
2025-08-21 22:17:16 -07:00
2025-08-19 22:07:44 -07:00
console . log ( "=== Bank Email Regex Test ===" ) ;
testEmails . forEach ( ( email , idx ) => {
console . log ( ` \n -- Email ${ idx + 1 } -- ` ) ;
console . log ( email ) ;
const parsed = parseBankMessage ( email ) ;
console . log ( "Parsed Result:" , parsed ) ;
} ) ;