Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions Services/BankStatementProcessor/HDFC.js/bankStatementProcessor-HDFC.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/**
* Generated by Gemini AI - Attempt 1
* Processes bank statement data from Excel
* @param {Array} rawData - Array of objects from bank statement Excel
* @returns {Object} Processed bank statement data
*/
function processBankStatement(rawData) {
const bank_details = {
bank_name: null,
opening_balance: 0,
ifsc: null,
address: null,
city: null,
account_no: null,
account_holder_name: null,
branch_name: null,
branch_code: null
};
const transactions = [];
let headerRowIndex = -1;
let headerKeys = {};
let voucher_number = 1;

// Helper function to format dates
const formatDate = (dateString) => {
if (!dateString) return null;

// Attempt to parse different date formats
let date = new Date(dateString);

if (isNaN(date.getTime())) {
// Try parsing as DD/MM/YYYY
const parts = dateString.split('/');
if (parts.length === 3) {
date = new Date(`${parts[2]}-${parts[1]}-${parts[0]}`);
}
}

if (isNaN(date.getTime())) {
// Try parsing as DD-MM-YYYY
const parts = dateString.split('-');
if (parts.length === 3) {
date = new Date(`${parts[2]}-${parts[1]}-${parts[0]}`);
}
}

if (isNaN(date.getTime())) {
return null;
}

const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};

// Extract bank details and find the header row
for (let i = 0; i < rawData.length; i++) {
const row = rawData[i];
for (const key in row) {
if (typeof row[key] === 'string') {
const lowerCaseValue = row[key].toLowerCase();
if (lowerCaseValue.includes('ifsc') || lowerCaseValue.includes('ifs code') || lowerCaseValue.includes('ifsc code')) {
const ifscValue = row[key].split(':').pop().trim() || "";
bank_details.ifsc = ifscValue;
} else if (lowerCaseValue.includes('account no') || lowerCaseValue.includes('account number') || lowerCaseValue.includes('accountnumber')) {
const accountValue = row[key].split(':').pop().trim() || "";
bank_details.account_no = accountValue;
}


}
if (row[key] === "Date" || row[key] === "Narration" || row[key] === "Narration or Details" || row[key] === "Withdrawal Amt." || row[key] === "Withdrawal Amt. or Debit" || row[key] === "Deposit Amt." || row[key] === "Deposit Amt. or Credit" || row[key] === "Closing Balance" || row[key] === "Closing Balance or Balance") {
headerRowIndex = i;
break;
}
}

if (headerRowIndex !== -1) {
break; // Header row found, exit the loop
}
}

//Extract Bank Details
for (let i = 0; i < headerRowIndex; i++){
const row = rawData[i];
for(const key in row){
const value = row[key];
if(typeof value === 'string'){
if(!bank_details.bank_name && value.toLowerCase().includes('bank')){
bank_details.bank_name = value.split(' ')[0];
}

if(!bank_details.account_holder_name && value.toLowerCase().includes('mr') || value.toLowerCase().includes('mrs')|| value.toLowerCase().includes('ms')){
bank_details.account_holder_name = value
}

if(!bank_details.address && value.toLowerCase().includes('address')){
bank_details.address = row["__EMPTY_3"]
bank_details.city = rawData[i+2]["__EMPTY_3"]

}
}
if(bank_details.ifsc == null){
const row = rawData[i];
for(const key in row){
const value = row[key];
if(typeof value == 'string'){
if(value.toLowerCase().includes('ifsc') || value.toLowerCase().includes('rtgs/neft ifsc')|| value.toLowerCase().includes('ifs code') || value.toLowerCase().includes('ifsc code')){
const ifscValue = value.split(':').pop().trim() || "";
bank_details.ifsc = ifscValue.split(' ')[0]
break;
}

}


}

}

if(bank_details.ifsc == null){
const row = rawData[i];
for(const key in row){

if(typeof row["__EMPTY_3"] == 'string'){
const value = row["__EMPTY_3"]
if(value.toLowerCase().includes('ifsc') || value.toLowerCase().includes('rtgs/neft ifsc')|| value.toLowerCase().includes('ifs code') || value.toLowerCase().includes('ifsc code')){
const ifscValue = value.split(':').pop().trim() || "";
bank_details.ifsc = ifscValue.split(' ')[0]
break;
}
}
}

}
}

}

if (headerRowIndex !== -1) {
const headerRow = rawData[headerRowIndex];
for (const key in headerRow) {
const headerValue = headerRow[key];

if (typeof headerValue === 'string') {
const lowerCaseHeader = headerValue.toLowerCase();

if (lowerCaseHeader === "date") {
headerKeys.date = key;
} else if (lowerCaseHeader === "narration" || lowerCaseHeader === "narration or details") {
headerKeys.desc = key;
} else if (lowerCaseHeader.includes("withdrawal")) {
headerKeys.withdrawal = key;
} else if (lowerCaseHeader.includes("deposit")) {
headerKeys.deposit = key;
} else if (lowerCaseHeader.includes("balance")) {
headerKeys.balance = key;
} else if(lowerCaseHeader === "chq./ref.no."){
headerKeys.ref = key;
}

}
}
}

// Process transactions
for (let i = headerRowIndex + 1; i < rawData.length; i++) {
const row = rawData[i];
if (!row) continue;

let date = null;
if(headerKeys.date){
date = formatDate(row[headerKeys.date]);
}

if (!date) continue; // Skip if date is missing or invalid

const desc = row[headerKeys.desc] || null;
let type = null;
let amount = null;

if (headerKeys.withdrawal && row[headerKeys.withdrawal] !== null && row[headerKeys.withdrawal] !== undefined) {
type = "withdrawal";
amount = Number(row[headerKeys.withdrawal]) || null;

} else if (headerKeys.deposit && row[headerKeys.deposit] !== null && row[headerKeys.deposit] !== undefined) {
type = "deposit";
amount = Number(row[headerKeys.deposit]) || null;
}

if (amount === null || isNaN(amount)) {
// If amount is not valid, attempt to extract it from the narration
if(desc){
const amountRegex = /(\d{1,3}(,\d{3})*(\.\d+)?|\.\d+)/;
const amountMatch = desc.match(amountRegex);
if (amountMatch) {
amount = Number(amountMatch[0].replace(/,/g, '')); // Remove commas and convert to number
}
}

if (amount === null || isNaN(amount)) continue; //Skip row for invalid amount
}

let balance = null;
if (headerKeys.balance && row[headerKeys.balance] !== null && row[headerKeys.balance] !== undefined ) {
balance = Number(row[headerKeys.balance]) || null;
if(isNaN(balance)) {
balance = null
}
}

const transaction = {
date,
voucher_number,
amount,
desc,
from: null,
to: null,
type,
balance
};
transactions.push(transaction);
voucher_number++;
}

return { bank_details, transactions };
}

module.exports = processBankStatement;