mywork / src /lib /actions /billing.ts
DeeCeeXxx's picture
Upload 114 files
e9d5b7d verified
"use server";
import type { CoinPurchaseInput } from "@/lib/schemas";
import { getLoggedInUser } from "./auth";
import { getDb } from "@/lib/mongodb";
import type { PaymentTransaction } from "@/lib/types";
import { ObjectId } from "mongodb";
import { revalidatePath } from "next/cache";
// These would typically be in environment variables for a real application
// For Paystack, the secret key is needed server-side. Public key is used client-side.
// For Flutterwave, similar setup.
// const PAYSTACK_SECRET_KEY = process.env.PAYSTACK_SECRET_KEY;
// const FLUTTERWAVE_SECRET_KEY = process.env.FLUTTERWAVE_SECRET_KEY;
export async function initiateCoinPurchase(
data: CoinPurchaseInput
): Promise<{ success: boolean; message: string; transactionReference?: string; paymentLink?: string; gateway?: 'paystack' | 'flutterwave'}> {
const user = await getLoggedInUser();
if (!user) {
return { success: false, message: "User not authenticated." };
}
const transactionReference = `anitadeploy_${user._id}_${new ObjectId().toString()}`;
// In a real scenario, you would:
// 1. Calculate the final amount based on selected package and currency.
// 2. Interact with Paystack or Flutterwave API using their SDKs or direct HTTP calls.
// - For Paystack: https://paystack.com/docs/api/transaction/#initialize
// - For Flutterwave: https://developer.flutterwave.com/docs/collecting-payments/standard/
// 3. Store a pending transaction record in your database.
// 4. Return the authorization_url (Paystack) or link (Flutterwave) to the client for redirect.
// Placeholder logic:
console.log("Initiating coin purchase:", data);
console.log("Generated Transaction Reference:", transactionReference);
// Log the data that would be sent to the payment gateway
// const payload = {
// email: data.email,
// amount: data.amountInSelectedCurrency * 100, // Amount in kobo/cents
// currency: data.currency,
// reference: transactionReference,
// callback_url: `${process.env.NEXT_PUBLIC_APP_URL}/dashboard/buy-coins/verify?gateway=${data.paymentGateway}`,
// metadata: {
// userId: user._id,
// coinsToCredit: data.coinsToCredit,
// package: data.package,
// }
// };
// console.log("Payload for gateway:", payload);
try {
const db = await getDb();
const transaction: Omit<PaymentTransaction, '_id'> = {
userId: user._id,
packageId: data.package,
coinsPurchased: data.coinsToCredit,
amountPaid: data.amountInSelectedCurrency, // Storing amount in the currency user paid with
currency: data.currency,
paymentGateway: data.paymentGateway,
transactionReference,
status: 'pending',
createdAt: new Date(),
updatedAt: new Date(),
};
await db.collection<PaymentTransaction>('payment_transactions').insertOne(transaction);
} catch (dbError) {
console.error("DB Error storing pending transaction:", dbError);
return { success: false, message: "Failed to record transaction. Please try again."};
}
// This is a SIMULATION.
// In a real app, you'd get a paymentLink from Paystack/Flutterwave.
// And you would NOT award coins here. Coins are awarded after webhook verification.
if (data.paymentGateway === "paystack") {
// Simulate Paystack giving a redirect URL
return {
success: true,
message: `Paystack payment initiated (simulation). Ref: ${transactionReference}. Redirecting...`,
transactionReference,
paymentLink: `https://checkout.paystack.com/success?trxref=${transactionReference}&reference=${transactionReference}`, // Example success URL
gateway: 'paystack'
};
} else if (data.paymentGateway === "flutterwave") {
// Simulate Flutterwave giving a redirect URL
return {
success: true,
message: `Flutterwave payment initiated (simulation). Ref: ${transactionReference}. Redirecting...`,
transactionReference,
paymentLink: `https://ravemodal-dev.herokuapp.com/v3/hosted/pay/successful?tx_ref=${transactionReference}`, // Example success URL
gateway: 'flutterwave'
};
}
return { success: false, message: "Invalid payment gateway selected (simulation)." };
}
// IMPORTANT: The following function is a placeholder for webhook verification.
// Webhook handling is CRITICAL for security and reliability.
// You MUST implement proper webhook verification from Paystack and Flutterwave.
export async function verifyPaymentAndAwardCoins(
gateway: 'paystack' | 'flutterwave',
reference: string,
gatewayResponse?: any // This would be the actual data from the gateway
): Promise<{ success: boolean; message: string }> {
console.log(`Verifying payment for ${gateway} with reference ${reference}`);
console.log("Gateway response (simulated or actual):", gatewayResponse);
const db = await getDb();
const transactionsCollection = db.collection<PaymentTransaction>("payment_transactions");
const usersCollection = db.collection("users");
const transaction = await transactionsCollection.findOne({ transactionReference: reference, status: 'pending' });
if (!transaction) {
console.error(`Transaction not found or not pending for reference: ${reference}`);
return { success: false, message: "Transaction not found or already processed." };
}
// In a real scenario:
// 1. Verify the webhook signature (Paystack) or hash (Flutterwave) to ensure authenticity.
// 2. Call the payment gateway's API to re-query the transaction status using the reference.
// - Paystack: https://paystack.com/docs/api/transaction/#verify
// - Flutterwave: https://developer.flutterwave.com/docs/integration-guides/verifying-transactions
// 3. Ensure the amount paid and currency match what's in your database for that transaction.
// 4. Ensure the transaction status is successful.
// 5. If all checks pass, update the transaction status to 'successful' and award coins.
// SIMULATED SUCCESS for now:
const isPaymentSuccessful = true; // Replace with actual verification logic
if (isPaymentSuccessful) {
const userUpdateResult = await usersCollection.updateOne(
{ _id: transaction.userId },
{ $inc: { coins: transaction.coinsPurchased } }
);
if (userUpdateResult.modifiedCount > 0) {
await transactionsCollection.updateOne(
{ _id: transaction._id },
{ $set: { status: 'successful', updatedAt: new Date(), gatewayResponse: gatewayResponse || { simulated: true } } }
);
revalidatePath("/dashboard");
revalidatePath("/dashboard/buy-coins");
return { success: true, message: `Payment successful! ${transaction.coinsPurchased} coins added to your account.` };
} else {
await transactionsCollection.updateOne(
{ _id: transaction._id },
{ $set: { status: 'failed', updatedAt: new Date(), gatewayResponse: { error: "Failed to update user coins."} } }
);
return { success: false, message: "Payment verified but failed to update coin balance." };
}
} else {
await transactionsCollection.updateOne(
{ _id: transaction._id },
{ $set: { status: 'failed', updatedAt: new Date(), gatewayResponse: gatewayResponse || { simulated_failure: true } } }
);
return { success: false, message: "Payment verification failed." };
}
}