diff --git a/data/IFSC.csv b/data/IFSC.csv new file mode 100644 index 0000000..1becba2 --- /dev/null +++ b/data/IFSC.csv @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file diff --git a/data/IFSC_complete.csv b/data/IFSC_complete.csv new file mode 100644 index 0000000..140ade3 --- /dev/null +++ b/data/IFSC_complete.csv @@ -0,0 +1,1446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page not found · GitHub · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ Skip to content + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+ + + + + +
+ + + + + + + + + +
+
+ + + +
+
+ +
+
+ 404 “This is not the web page you are looking for” + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + diff --git a/data/rbi_ifsc.json b/data/rbi_ifsc.json new file mode 100644 index 0000000..1becba2 --- /dev/null +++ b/data/rbi_ifsc.json @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file diff --git a/src/database/importIFSC.js b/src/database/importIFSC.js new file mode 100644 index 0000000..764c39e --- /dev/null +++ b/src/database/importIFSC.js @@ -0,0 +1,113 @@ +/** + * Import comprehensive IFSC data from Razorpay API + * This script fetches IFSC codes for major banks and imports them to the database + */ + +const axios = require('axios'); +const { Pool } = require('pg'); + +const pool = new Pool({ + connectionString: process.env.DATABASE_URL || 'postgresql://postgres:fXlNbqBpxhgchmrvPtlMKgwttWVdMDlO@shuttle.proxy.rlwy.net:23879/railway' +}); + +// Major Indian banks with their IFSC prefixes +const BANK_PREFIXES = [ + { prefix: 'SBIN', name: 'State Bank of India', count: 100 }, + { prefix: 'HDFC', name: 'HDFC Bank', count: 100 }, + { prefix: 'ICIC', name: 'ICICI Bank', count: 100 }, + { prefix: 'KKBK', name: 'Kotak Mahindra Bank', count: 50 }, + { prefix: 'UTIB', name: 'Axis Bank', count: 50 }, + { prefix: 'PUNB', name: 'Punjab National Bank', count: 50 }, + { prefix: 'BARB', name: 'Bank of Baroda', count: 50 }, + { prefix: 'CNRB', name: 'Canara Bank', count: 50 }, + { prefix: 'UBIN', name: 'Union Bank of India', count: 50 }, + { prefix: 'IOBA', name: 'Indian Overseas Bank', count: 30 }, + { prefix: 'IDIB', name: 'Indian Bank', count: 30 }, + { prefix: 'BKID', name: 'Bank of India', count: 30 }, + { prefix: 'CBIN', name: 'Central Bank of India', count: 30 }, + { prefix: 'YESB', name: 'Yes Bank', count: 30 }, + { prefix: 'INDB', name: 'IndusInd Bank', count: 30 }, + { prefix: 'FDRL', name: 'Federal Bank', count: 30 }, + { prefix: 'KVBL', name: 'Karur Vysya Bank', count: 20 }, + { prefix: 'TMBL', name: 'Tamilnad Mercantile Bank', count: 20 }, + { prefix: 'RATN', name: 'RBL Bank', count: 20 }, + { prefix: 'IDFB', name: 'IDFC First Bank', count: 20 }, +]; + +async function fetchAndInsertIFSC(prefix, bankName, count) { + const inserted = []; + const failed = []; + + // Generate IFSC codes to try + for (let i = 0; i <= count; i++) { + const ifsc = `${prefix}${String(i).padStart(7, '0')}`; + + try { + const response = await axios.get(`https://ifsc.razorpay.com/${ifsc}`, { timeout: 5000 }); + const data = response.data; + + // Insert into database + await pool.query( + `INSERT INTO ifsc_codes (ifsc, bank_name, branch, address, city, district, state, contact, upi_enabled, rtgs_enabled, neft_enabled, imps_enabled, micr_code, swift_code, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, NOW()) + ON CONFLICT (ifsc) DO UPDATE SET + bank_name = EXCLUDED.bank_name, + branch = EXCLUDED.branch, + address = EXCLUDED.address, + city = EXCLUDED.city, + updated_at = NOW()`, + [ + ifsc, + bankName, + data.BRANCH || '', + data.ADDRESS || '', + data.CITY || '', + data.DISTRICT || '', + data.STATE || '', + data.CONTACT || '', + data.UPI || false, + data.RTGS || false, + data.NEFT || false, + data.IMPS || false, + data.MICR || '', + data.SWIFT || '' + ] + ); + + inserted.push(ifsc); + process.stdout.write(`✅ ${ifsc} `); + } catch (error) { + if (error.response && error.response.status === 404) { + // IFSC doesn't exist, skip + } else { + failed.push(ifsc); + } + } + + // Small delay to not overwhelm the API + await new Promise(resolve => setTimeout(resolve, 100)); + } + + return { inserted: inserted.length, failed: failed.length }; +} + +async function main() { + console.log('🚀 Starting comprehensive IFSC import...\n'); + + let totalInserted = 0; + + for (const bank of BANK_PREFIXES) { + console.log(`\n📦 Fetching ${bank.name} (${bank.prefix})...`); + const result = await fetchAndInsertIFSC(bank.prefix, bank.name, bank.count); + totalInserted += result.inserted; + console.log(`\n ✅ Inserted: ${result.inserted} codes`); + } + + console.log(`\n==================================================`); + console.log(`🎉 Total IFSC codes imported: ${totalInserted}`); + console.log(`==================================================\n`); + + await pool.end(); +} + +main().catch(console.error); diff --git a/src/database/importPincodes.js b/src/database/importPincodes.js new file mode 100644 index 0000000..22330de --- /dev/null +++ b/src/database/importPincodes.js @@ -0,0 +1,92 @@ +/** + * Import missing metro city pincodes from India Post API + */ + +const axios = require('axios'); +const { Pool } = require('pg'); + +const pool = new Pool({ + connectionString: process.env.DATABASE_URL || 'postgresql://postgres:fXlNbqBpxhgchmrvPtlMKgwttWVdMDlO@shuttle.proxy.rlwy.net:23879/railway' +}); + +// Major metro pincodes that need to be added +const METRO_PINCODES = [ + // Mumbai + '400001', '400002', '400003', '400004', '400005', '400006', '400007', '400008', '400009', '400010', + '400011', '400012', '400013', '400015', '400016', '400017', '400018', '400019', '400020', '400021', + '400022', '400023', '400024', '400025', '400026', '400027', '400028', '400029', '400030', '400031', + '400032', '400033', '400034', '400036', '400037', '400038', '400039', '400042', '400043', '400049', + '400050', '400051', '400052', '400053', '400054', '400055', '400056', '400057', '400058', '400059', + '400060', '400061', '400062', '400063', '400064', '400065', '400066', '400067', '400068', '400069', + '400070', '400071', '400072', '400074', '400075', '400076', '400077', '400078', '400079', '400080', + '400081', '400082', '400083', '400084', '400085', '400086', '400087', '400088', '400089', '400091', + '400092', '400093', '400094', '400095', '400096', '400097', '400098', '400099', '400101', '400102', + // Chennai + '600001', '600002', '600003', '600004', '600005', '600006', '600007', '600008', '600009', '600010', + '600011', '600012', '600013', '600014', '600015', '600016', '600017', '600018', '600019', '600020', + '600021', '600022', '600023', '600024', '600025', '600026', '600027', '600028', '600029', '600030', + '600031', '600032', '600033', '600034', '600035', '600036', '600037', '600038', '600039', '600040', + // Pune + '411001', '411002', '411003', '411004', '411005', '411006', '411007', '411008', '411009', '411010', + '411011', '411012', '411013', '411014', '411015', '411016', '411017', '411018', '411019', '411020', +]; + +async function fetchAndInsertPincode(pincode) { + try { + const response = await axios.get(`https://api.postalpincode.in/pincode/${pincode}`, { timeout: 10000 }); + + if (response.data && response.data[0] && response.data[0].Status === 'Success') { + const postOffices = response.data[0].PostOffice; + + for (const po of postOffices) { + await pool.query( + `INSERT INTO pincodes (pincode, office_name, office_type, district, division, region, state, latitude, longitude, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW()) + ON CONFLICT (pincode, office_name) DO UPDATE SET + district = EXCLUDED.district, + state = EXCLUDED.state, + updated_at = NOW()`, + [ + pincode, + po.Name || '', + po.BranchType || 'PO', + po.District || '', + po.Division || '', + po.Region || '', + po.State || '', + '0', + '0' + ] + ); + } + return postOffices.length; + } + return 0; + } catch (error) { + return 0; + } +} + +async function main() { + console.log('🚀 Starting metro pincode import...\n'); + + let totalInserted = 0; + + for (const pincode of METRO_PINCODES) { + const count = await fetchAndInsertPincode(pincode); + if (count > 0) { + process.stdout.write(`✅ ${pincode} (${count}) `); + totalInserted += count; + } + // Delay to respect API rate limits + await new Promise(resolve => setTimeout(resolve, 200)); + } + + console.log(`\n\n==================================================`); + console.log(`🎉 Total post offices imported: ${totalInserted}`); + console.log(`==================================================\n`); + + await pool.end(); +} + +main().catch(console.error); diff --git a/src/database/setup.js b/src/database/setup.js index fe0ba9c..ce8a405 100644 --- a/src/database/setup.js +++ b/src/database/setup.js @@ -118,6 +118,7 @@ CREATE TABLE IF NOT EXISTS pincodes ( division VARCHAR(100), region VARCHAR(100), state VARCHAR(100), + block VARCHAR(100), latitude DECIMAL(10, 8), longitude DECIMAL(11, 8), updated_at TIMESTAMP DEFAULT NOW() diff --git a/src/routes/auth.js b/src/routes/auth.js index 0a8adca..35f81c4 100644 --- a/src/routes/auth.js +++ b/src/routes/auth.js @@ -25,7 +25,7 @@ function generateApiKey() { */ router.post('/signup', async (req, res, next) => { try { - const { email, password, company_name, phone } = req.body; + const { email, password, name, phone } = req.body; if (!email || !password) { throw new ApiError(400, 'MISSING_FIELDS', 'Email and password required'); @@ -49,7 +49,7 @@ router.post('/signup', async (req, res, next) => { `INSERT INTO users (email, password_hash, company_name, phone, plan, monthly_quota, quota_reset_date) VALUES ($1, $2, $3, $4, 'free', 100, DATE(NOW() + INTERVAL '1 month')) RETURNING id, email, company_name, plan`, - [email.toLowerCase(), passwordHash, company_name, phone] + [email.toLowerCase(), passwordHash, name, phone] ); const user = result.rows[0]; @@ -79,7 +79,7 @@ router.post('/signup', async (req, res, next) => { user: { id: user.id, email: user.email, - company_name: user.company_name, + name: user.company_name, plan: user.plan }, api_key: apiKey, @@ -139,7 +139,7 @@ router.post('/login', async (req, res, next) => { user: { id: user.id, email: user.email, - company_name: user.company_name, + name: user.company_name, plan: user.plan, quota: user.monthly_quota, used: user.calls_this_month diff --git a/src/routes/ifsc.js b/src/routes/ifsc.js index 67c0713..fd2de23 100644 --- a/src/routes/ifsc.js +++ b/src/routes/ifsc.js @@ -1,16 +1,94 @@ /** * IFSC Lookup Route * Returns bank details for a given IFSC code + * Supports local database + Razorpay API fallback */ const express = require('express'); const router = express.Router(); +const axios = require('axios'); const { authenticateApiKey } = require('../middleware/auth'); const { rateLimit } = require('../middleware/rateLimit'); const { query } = require('../database/connection'); const { cacheGet, cacheSet } = require('../cache/redis'); const { logApiCall } = require('../services/analytics'); +/** + * Fetch IFSC from Razorpay API and save to database + */ +async function fetchFromRazorpayAPI(ifsc) { + try { + console.log(`🌐 Fetching IFSC ${ifsc} from Razorpay API...`); + + const response = await axios.get(`https://ifsc.razorpay.com/${ifsc}`, { + timeout: 10000 + }); + + if (response.data && response.data.BANK) { + const data = response.data; + + try { + // Save to database for future lookups + await query( + `INSERT INTO ifsc_codes (ifsc, bank_name, branch, address, city, district, state, contact, upi_enabled, rtgs_enabled, neft_enabled, imps_enabled, micr_code, swift_code, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, NOW())`, + [ + ifsc, + data.BANK || '', + data.BRANCH || '', + data.ADDRESS || '', + data.CITY || '', + data.DISTRICT || '', + data.STATE || '', + data.CONTACT || '', + data.UPI || false, + data.RTGS || false, + data.NEFT || false, + data.IMPS || false, + data.MICR || '', + data.SWIFT || null + ] + ); + console.log(`✅ Saved IFSC ${ifsc} to database`); + } catch (insertError) { + // Ignore duplicate errors + console.log(`⚠️ Could not save to DB (might already exist):`, insertError.message); + } + + // Return normalized data + return { + success: true, + data: { + ifsc: ifsc, + bank_name: data.BANK || '', + branch: data.BRANCH || '', + address: data.ADDRESS || '', + city: data.CITY || '', + district: data.DISTRICT || '', + state: data.STATE || '', + contact: data.CONTACT || '', + upi_enabled: data.UPI || false, + rtgs_enabled: data.RTGS || false, + neft_enabled: data.NEFT || false, + imps_enabled: data.IMPS || false, + micr_code: data.MICR || '', + swift_code: data.SWIFT || null + }, + source: 'RAZORPAY_API' + }; + } + + return { success: false, error: 'Invalid IFSC code' }; + } catch (error) { + if (error.response && error.response.status === 404) { + console.log(`❌ IFSC ${ifsc} not found in Razorpay API`); + return { success: false, error: 'IFSC code not found' }; + } + console.error(`❌ Razorpay API error for ${ifsc}:`, error.message); + return { success: false, error: error.message }; + } +} + router.use(authenticateApiKey); router.use(rateLimit); @@ -133,6 +211,7 @@ router.get('/state/:stateName', async (req, res, next) => { router.get('/:ifsc_code', async (req, res, next) => { const startTime = Date.now(); let success = false; + let source = 'LOCAL_DB'; try { const { ifsc_code } = req.params; @@ -149,17 +228,30 @@ router.get('/:ifsc_code', async (req, res, next) => { const cacheKey = `ifsc:${ifsc}`; let data = await cacheGet(cacheKey); - if (!data) { + if (data) { + source = 'CACHE'; + } else { + // Try local database first const result = await query('SELECT * FROM ifsc_codes WHERE ifsc = $1', [ifsc]); if (result.rows.length === 0) { - return res.status(404).json({ - success: false, - error: { code: 'IFSC_NOT_FOUND', message: 'IFSC not found' } - }); + // Fallback to Razorpay API + console.log(`📦 IFSC ${ifsc} not in DB, trying Razorpay API...`); + const apiResult = await fetchFromRazorpayAPI(ifsc); + + if (!apiResult.success) { + return res.status(404).json({ + success: false, + error: { code: 'IFSC_NOT_FOUND', message: 'IFSC not found in any source' } + }); + } + + data = apiResult.data; + source = 'RAZORPAY_API'; + } else { + data = result.rows[0]; } - data = result.rows[0]; await cacheSet(cacheKey, data, 86400); // Cache for 24 hours } @@ -169,6 +261,7 @@ router.get('/:ifsc_code', async (req, res, next) => { success: true, data: { ifsc: data.ifsc, + source, bank: data.bank_name, branch: data.branch, address: data.address, diff --git a/src/routes/pincode.js b/src/routes/pincode.js index 14a9ddc..c7c806d 100644 --- a/src/routes/pincode.js +++ b/src/routes/pincode.js @@ -1,16 +1,112 @@ /** * Pincode Lookup Route * Returns location details for a given pincode + * Supports local database + India Post API fallback */ const express = require('express'); const router = express.Router(); +const axios = require('axios'); const { authenticateApiKey } = require('../middleware/auth'); const { rateLimit } = require('../middleware/rateLimit'); const { query } = require('../database/connection'); const { cacheGet, cacheSet } = require('../cache/redis'); const { logApiCall } = require('../services/analytics'); +/** + * Fetch pincode from India Post API and save to database + */ +async function fetchFromIndiaPostAPI(pincode) { + try { + console.log(`🌐 Fetching pincode ${pincode} from India Post API...`); + + const response = await axios.get(`https://api.postalpincode.in/pincode/${pincode}`, { + timeout: 10000 + }); + + if (response.data && response.data[0] && response.data[0].Status === 'Success') { + const postOffices = response.data[0].PostOffice; + const savedRecords = []; + + for (const po of postOffices) { + try { + // Save to database for future lookups (UPSERT for self-healing) + await query( + `INSERT INTO pincodes (pincode, office_name, office_type, district, division, region, state, block, latitude, longitude, updated_at) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW()) + ON CONFLICT (id) + DO UPDATE SET + office_name = EXCLUDED.office_name, + office_type = EXCLUDED.office_type, + district = EXCLUDED.district, + division = EXCLUDED.division, + region = EXCLUDED.region, + state = EXCLUDED.state, + block = EXCLUDED.block, + latitude = EXCLUDED.latitude, + longitude = EXCLUDED.longitude, + updated_at = NOW()`, + [ + pincode, + po.Name || '', + po.BranchType || 'PO', + po.District || '', + po.Division || '', + po.Region || '', + po.State || '', + po.Block || '', + '0', + '0' + ] + ); + } catch (insertError) { + // Try to update if insert fails + try { + await query( + `UPDATE pincodes + SET office_type = $3, district = $4, division = $5, region = $6, state = $7, block = $8, updated_at = NOW() + WHERE pincode = $1 AND office_name = $2`, + [ + pincode, + po.Name || '', + po.BranchType || 'PO', + po.District || '', + po.Division || '', + po.Region || '', + po.State || '', + po.Block || '' + ] + ); + } catch (updateError) { + // Ignore errors + } + } + + savedRecords.push({ + pincode: pincode, + office_name: po.Name || '', + office_type: po.BranchType || 'PO', + district: po.District || '', + division: po.Division || '', + region: po.Region || '', + state: po.State || '', + block: po.Block || '', + latitude: '0', + longitude: '0' + }); + } + + console.log(`✅ Fetched and saved ${savedRecords.length} offices for pincode ${pincode}`); + return { success: true, data: savedRecords, source: 'INDIA_POST_API' }; + } + + return { success: false, error: 'Invalid pincode' }; + } catch (error) { + console.error(`❌ India Post API error for ${pincode}:`, error.message); + return { success: false, error: error.message }; + } +} + const STATE_CODES = { 'Andhra Pradesh': 'AP', 'Arunachal Pradesh': 'AR', 'Assam': 'AS', 'Bihar': 'BR', 'Chhattisgarh': 'CG', 'Delhi': 'DL', 'Goa': 'GA', 'Gujarat': 'GJ', 'Haryana': 'HR', @@ -112,11 +208,12 @@ router.get('/search', async (req, res, next) => { /** * GET /v1/pincode/:pincode - * Lookup pincode details + * Lookup pincode details with India Post API fallback */ router.get('/:pincode', async (req, res, next) => { const startTime = Date.now(); let success = false; + let source = 'LOCAL_DB'; try { const { pincode } = req.params; @@ -130,18 +227,55 @@ router.get('/:pincode', async (req, res, next) => { const cacheKey = `pincode:${pincode}`; let data = await cacheGet(cacheKey); + let needsRefresh = false; + + if (data) { + source = 'CACHE'; + // Self-healing: Check if taluk is missing + if (data.length > 0 && (!data[0].block || data[0].block === '')) { + console.log(`🔄 Self-healing: Taluk missing for pincode ${pincode}, refetching...`); + needsRefresh = true; + data = null; // Force refetch + } + } if (!data) { + // Try local database first const result = await query('SELECT * FROM pincodes WHERE pincode = $1', [pincode]); - if (result.rows.length === 0) { - return res.status(404).json({ - success: false, - error: { code: 'PINCODE_NOT_FOUND', message: 'Pincode not found' } - }); + if (result.rows.length === 0 || needsRefresh) { + // Fallback to India Post API (or forced refresh for self-healing) + if (needsRefresh) { + console.log(`🔄 Refreshing pincode ${pincode} with India Post API...`); + } else { + console.log(`📦 Pincode ${pincode} not in DB, trying India Post API...`); + } + + const apiResult = await fetchFromIndiaPostAPI(pincode); + + if (!apiResult.success) { + return res.status(404).json({ + success: false, + error: { code: 'PINCODE_NOT_FOUND', message: 'Pincode not found in any source' } + }); + } + + data = apiResult.data; + source = 'INDIA_POST_API'; + } else { + data = result.rows; + // Double-check: if DB data also has empty taluk, force refresh + if (data.length > 0 && (!data[0].block || data[0].block === '')) { + console.log(`🔄 Self-healing: DB data also missing taluk for ${pincode}, refetching...`); + const apiResult = await fetchFromIndiaPostAPI(pincode); + + if (apiResult.success) { + data = apiResult.data; + source = 'INDIA_POST_API'; + } + } } - data = result.rows; await cacheSet(cacheKey, data, 604800); // Cache for 7 days } @@ -152,19 +286,17 @@ router.get('/:pincode', async (req, res, next) => { success: true, data: { pincode, - locations: data.map(row => ({ - office_name: row.office_name, - office_type: row.office_type, - district: row.district, - state: row.state, - latitude: parseFloat(row.latitude) || null, - longitude: parseFloat(row.longitude) || null - })), - primary: { - district: primary.district, - state: primary.state, - state_code: STATE_CODES[primary.state] || '' - } + source, + district: primary.district, + state: primary.state, + state_code: STATE_CODES[primary.state] || '', + latitude: parseFloat(primary.latitude) || null, + longitude: parseFloat(primary.longitude) || null, + offices: data.map(office => ({ + name: office.office_name, + type: office.office_type, + taluk: office.block || '' + })) }, meta: { request_id: `req_pin_${Date.now()}`,