first commit
This commit is contained in:
64
app/api/create-payment-intent/route.ts
Normal file
64
app/api/create-payment-intent/route.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { stripe } from '@/lib/stripe';
|
||||
import { supabaseAdmin } from '@/lib/supabase';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { amount, currency, ref_id, callback_url, customer_name, customer_phone } = await req.json();
|
||||
|
||||
if (!amount || !currency) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Tutar ve para birimi zorunludur.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const useMock = process.env.NEXT_PUBLIC_USE_MOCK_PAYMENTS === 'true';
|
||||
let clientSecret = 'mock_secret_' + Math.random().toString(36).substring(7);
|
||||
let stripeId = 'mock_pi_' + Math.random().toString(36).substring(7);
|
||||
|
||||
if (!useMock) {
|
||||
// 1. Create PaymentIntent in Stripe
|
||||
const paymentIntent = await stripe.paymentIntents.create({
|
||||
amount: Math.round(amount * 100), // Stripe uses subunits (e.g., cents)
|
||||
currency: currency.toLowerCase(),
|
||||
metadata: {
|
||||
ref_id,
|
||||
callback_url,
|
||||
customer_name,
|
||||
customer_phone,
|
||||
},
|
||||
});
|
||||
clientSecret = paymentIntent.client_secret!;
|
||||
stripeId = paymentIntent.id;
|
||||
}
|
||||
|
||||
// 2. Log transaction in Supabase with 'pending' status
|
||||
const { error: dbError } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.insert({
|
||||
amount,
|
||||
currency,
|
||||
status: 'pending',
|
||||
stripe_pi_id: stripeId,
|
||||
source_ref_id: ref_id,
|
||||
customer_name,
|
||||
customer_phone,
|
||||
callback_url,
|
||||
});
|
||||
|
||||
if (dbError) {
|
||||
console.error('Database log error:', dbError);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
clientSecret: clientSecret,
|
||||
});
|
||||
} catch (err: any) {
|
||||
console.error('Internal Error:', err);
|
||||
return NextResponse.json(
|
||||
{ error: `Internal Server Error: ${err.message}` },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
31
app/api/mock-complete-payment/route.ts
Normal file
31
app/api/mock-complete-payment/route.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { supabaseAdmin } from '@/lib/supabase';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { clientSecret, status, customer_name, customer_phone } = await req.json();
|
||||
|
||||
if (process.env.NEXT_PUBLIC_USE_MOCK_PAYMENTS !== 'true') {
|
||||
return NextResponse.json({ error: 'Mock payments are disabled' }, { status: 403 });
|
||||
}
|
||||
|
||||
// Update transaction in Supabase
|
||||
const { error } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.update({
|
||||
status,
|
||||
customer_name,
|
||||
customer_phone
|
||||
})
|
||||
.eq('stripe_pi_id', clientSecret); // In mock mode, we use clientSecret as the ID
|
||||
|
||||
if (error) {
|
||||
console.error('Mock update DB error:', error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (err: any) {
|
||||
return NextResponse.json({ error: err.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
29
app/api/update-transaction-info/route.ts
Normal file
29
app/api/update-transaction-info/route.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { supabaseAdmin } from '@/lib/supabase';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { stripe_id, customer_name, customer_phone } = await req.json();
|
||||
|
||||
if (!stripe_id) {
|
||||
return NextResponse.json({ error: 'Missing stripe_id' }, { status: 400 });
|
||||
}
|
||||
|
||||
const { error } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.update({
|
||||
customer_name,
|
||||
customer_phone
|
||||
})
|
||||
.eq('stripe_pi_id', stripe_id);
|
||||
|
||||
if (error) {
|
||||
console.error('Update transaction info error:', error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (err: any) {
|
||||
return NextResponse.json({ error: err.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
57
app/api/webhooks/stripe/route.ts
Normal file
57
app/api/webhooks/stripe/route.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { stripe } from '@/lib/stripe';
|
||||
import { supabaseAdmin } from '@/lib/supabase';
|
||||
|
||||
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const body = await req.text();
|
||||
const sig = req.headers.get('stripe-signature')!;
|
||||
|
||||
let event;
|
||||
|
||||
try {
|
||||
event = stripe.webhooks.constructEvent(body, sig, webhookSecret);
|
||||
} catch (err: any) {
|
||||
console.error(`Webhook Error: ${err.message}`);
|
||||
return NextResponse.json({ error: `Webhook Error: ${err.message}` }, { status: 400 });
|
||||
}
|
||||
|
||||
const session = event.data.object as any;
|
||||
|
||||
// Handle the business logic based on event type
|
||||
switch (event.type) {
|
||||
case 'payment_intent.succeeded':
|
||||
await handlePaymentSucceeded(session);
|
||||
break;
|
||||
case 'payment_intent.payment_failed':
|
||||
await handlePaymentFailed(session);
|
||||
break;
|
||||
default:
|
||||
console.log(`Unhandled event type ${event.type}`);
|
||||
}
|
||||
|
||||
return NextResponse.json({ received: true });
|
||||
}
|
||||
|
||||
async function handlePaymentSucceeded(paymentIntent: any) {
|
||||
const { error } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.update({ status: 'succeeded' })
|
||||
.eq('stripe_pi_id', paymentIntent.id);
|
||||
|
||||
if (error) {
|
||||
console.error('Error updating transaction success:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function handlePaymentFailed(paymentIntent: any) {
|
||||
const { error } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.update({ status: 'failed' })
|
||||
.eq('stripe_pi_id', paymentIntent.id);
|
||||
|
||||
if (error) {
|
||||
console.error('Error updating transaction failure:', error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user