import axios from "axios"; import { onRequest } from "firebase-functions/v2/https"; import { Request} from "firebase-functions/v2/https"; import { getCorsHandler } from "../../shared/middleware"; import { getAdmin, getLogger } from "../../shared/config"; const admin = getAdmin(); const logger = getLogger(); const corsHandler = getCorsHandler(); export const checkPhonePePaymentStatus = onRequest({ region: '#{SERVICES_RGN}#' }, async (request: Request, response) => { return corsHandler(request, response, async () => { try { const authHeader = request.headers.authorization || ''; if (!authHeader || !authHeader.startsWith('Bearer ')) { response.status(401).json({ error: 'Unauthorized' }); return; } const idToken = authHeader.split('Bearer ')[1]; try { await admin.auth().verifyIdToken(idToken); const merchantOrderId = request.query.merchantOrderId as string; if (!merchantOrderId) { response.status(400).json({ error: 'Missing merchant order ID' }); return; } const details = request.query.details === 'true'; const errorContext = request.query.errorContext === 'true'; const clientId = process.env.PHONEPE_CLIENT_ID; const clientSecret = process.env.PHONEPE_CLIENT_SECRET; const apiUrl = process.env.PHONEPE_API_URL; const clientVersion = process.env.PHONEPE_CLIENT_VERSION || '1'; if (!clientId || !clientSecret || !apiUrl) { logger.error('PhonePe credentials not configured'); response.status(500).json({ error: 'Payment gateway configuration error' }); return; } const tokenResponse = await axios.post( `${apiUrl}/v1/oauth/token`, { client_id: clientId, client_version: clientVersion, client_secret: clientSecret, grant_type: 'client_credentials', }, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, } ); const accessToken = tokenResponse.data.access_token; const queryParams = new URLSearchParams(); if (details) queryParams.append('details', 'true'); if (errorContext) queryParams.append('errorContext', 'true'); const queryString = queryParams.toString() ? `?${queryParams.toString()}` : ''; const statusResponse = await axios.get( `${apiUrl}/checkout/v2/order/${merchantOrderId}/status${queryString}`, { headers: { 'Content-Type': 'application/json', 'Authorization': `O-Bearer ${accessToken}`, }, } ); const orderQuery = await admin.firestore() .collection('payment_orders') .where('merchantOrderId', '==', merchantOrderId) .limit(1) .get(); if (orderQuery.empty) { logger.error(`No payment order found with PhonePe orderId: ${merchantOrderId}`); response.status(404).json({ success: false, error: 'Payment order not found', message: `No record found for PhonePe order ID: ${merchantOrderId}` }); return; } const orderDoc = orderQuery.docs[0]; await orderDoc.ref.update({ orderStatus: statusResponse.data.state || 'UNKNOWN', lastChecked: new Date(), statusResponse: statusResponse.data }); logger.info('PhonePe status response data:', JSON.stringify(statusResponse.data)); response.json({ success: true, state: statusResponse.data.state, data: statusResponse.data }); } catch (authError: any) { logger.error('Authentication error:', authError); if (authError.response) { logger.error('API error details:', { status: authError.response.status, data: authError.response.data }); response.status(authError.response.status).json({ success: false, error: 'API error', details: authError.response.data }); } else { response.status(401).json({ success: false, error: 'Invalid authentication token or API error', message: authError.message }); } } } catch (error: any) { logger.error('PhonePe payment status check error:', error); response.status(500).json({ success: false, error: 'Failed to check payment status', details: error.message }); } }); });