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"; import axios from "axios"; const { v4: uuidv4 } = require('uuid'); const corsHandler = getCorsHandler(); const admin = getAdmin(); const logger = getLogger(); interface CashfreeLinkRequest { amount: number; customerName?: string; customerEmail: string; customerPhone: string; productInfo?: string; userId?: string; gymId?: string; orderId: string; } interface CashfreeLinkResponse { link_id: string; link_url: string; link_expiry_time: string; link_status: string; link_qrcode: string; [key: string]: any; } export const createCashfreeLink = 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]; const decodedToken = await admin.auth().verifyIdToken(idToken); const uid = decodedToken.uid; const linkRequest = request.body as CashfreeLinkRequest; if (!linkRequest.amount || !linkRequest.customerEmail || !linkRequest.customerPhone) { response.status(400).json({ error: 'Missing required fields' }); return; } const clientId = process.env.CASHFREE_CLIENT_ID; const clientSecret = process.env.CASHFREE_CLIENT_SECRET; if (!clientId || !clientSecret) { logger.error('Cashfree credentials not configured'); response.status(500).json({ error: 'Payment gateway configuration error' }); return; } const expirationDate = new Date(Date.now() + 24 * 60 * 60 * 1000); const expirationString = expirationDate.toISOString(); const apiUrl = process.env.CASHFREE_LINK_URL; const linkId = uuidv4(); const requestHeaders = { 'x-client-id': clientId, 'x-client-secret': clientSecret, 'x-api-version': '2025-01-01', 'Content-Type': 'application/json' }; const requestBody = { link_id: linkId, link_amount: linkRequest.amount, link_currency: "INR", link_purpose: linkRequest.productInfo, customer_details: { customer_phone: linkRequest.customerPhone, customer_email: linkRequest.customerEmail, customer_name: linkRequest.customerName, }, link_partial_payments: false, link_notify: { send_sms: true, send_email: true }, link_expiry_time: expirationString, link_notes: { order_id: linkRequest.orderId, gym_id: linkRequest.gymId, user_id: linkRequest.userId } }; const cashfreeResponse = await axios.post( apiUrl!, requestBody, { headers: requestHeaders } ); await admin.firestore().collection('payment_links').doc(linkRequest.orderId).set({ requestUserId: uid, amount: linkRequest.amount, customerEmail: linkRequest.customerEmail, customerPhone: linkRequest.customerPhone, userId: linkRequest.userId, gymId: linkRequest.gymId, orderId: linkRequest.orderId, ...cashfreeResponse.data, createdAt: admin.firestore.FieldValue.serverTimestamp(), }); response.json({ success: true, linkId: linkId, linkUrl: cashfreeResponse.data.link_url, linkExpiryTime: cashfreeResponse.data.link_expiry_time, linkStatus: cashfreeResponse.data.link_status, linkQRCode: cashfreeResponse.data.link_qrcode }); } catch (error: any) { logger.error('Cashfree link creation error:', error); const statusCode = error.response?.status || 500; response.status(statusCode).json({ success: false, error: error.response?.data?.message || 'Failed to create payment link', details: error.response?.data || error.message }); } }); });