Add self-healing for pincode taluk field
This commit is contained in:
parent
dc49d6f432
commit
5c964d1917
1
data/IFSC.csv
Normal file
1
data/IFSC.csv
Normal file
@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
|
1446
data/IFSC_complete.csv
Normal file
1446
data/IFSC_complete.csv
Normal file
File diff suppressed because one or more lines are too long
1
data/rbi_ifsc.json
Normal file
1
data/rbi_ifsc.json
Normal file
@ -0,0 +1 @@
|
||||
404: Not Found
|
||||
113
src/database/importIFSC.js
Normal file
113
src/database/importIFSC.js
Normal file
@ -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);
|
||||
92
src/database/importPincodes.js
Normal file
92
src/database/importPincodes.js
Normal file
@ -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);
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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()}`,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user