Files
meet-hub/supabase/functions/create-payment/index.ts
dwindown eba37df4d7 Remove PayPal, simplify to QRIS-only with in-app QR display
- Remove PayPal payment option from checkout
- Add qr_string and qr_expires_at columns to orders table
- Update create-payment to store QR string in database
- Update pakasir-webhook to clear QR string after payment
- Simplify Checkout to redirect to order detail page
- Clean up unused imports and components

Flow:
1. User checks out with QRIS (only option)
2. Order created with payment_method='qris'
3. QR string stored in database
4. User redirected to Order Detail page
5. QR code displayed in-app with polling
6. After payment, QR string cleared, access granted

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-24 00:12:04 +07:00

141 lines
4.5 KiB
TypeScript

import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
interface CreatePaymentRequest {
order_id: string;
amount: number;
description: string;
}
serve(async (req: Request) => {
// Handle CORS preflight
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders });
}
if (req.method !== "POST") {
return new Response("Method not allowed", { status: 405, headers: corsHeaders });
}
try {
const body: CreatePaymentRequest = await req.json();
const { order_id, amount, description } = body;
if (!order_id || !amount) {
return new Response(
JSON.stringify({ success: false, error: "order_id and amount are required" }),
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
const PAYMENT_PROJECT_SLUG = Deno.env.get("PAKASIR_PROJECT_SLUG") || "";
const PAYMENT_API_KEY = Deno.env.get("PAKASIR_API_KEY") || "";
const PAYMENT_CALLBACK_URL = `${Deno.env.get("SUPABASE_URL")}/functions/v1/pakasir-webhook`;
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
);
if (!PAYMENT_PROJECT_SLUG || !PAYMENT_API_KEY) {
console.error("[PAYMENT] Missing credentials");
return new Response(
JSON.stringify({ success: false, error: "Payment provider credentials not configured" }),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
console.log("[PAYMENT] Creating QRIS transaction:", { order_id, amount });
// Call Pakasir API to create QRIS transaction
const paymentResponse = await fetch(`https://app.pakasir.com/api/transactioncreate/qris`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
project: PAYMENT_PROJECT_SLUG,
order_id: order_id,
amount: amount,
api_key: PAYMENT_API_KEY,
description: description || `Order ${order_id}`,
callback_url: PAYMENT_CALLBACK_URL,
}),
});
if (!paymentResponse.ok) {
const errorText = await paymentResponse.text();
console.error("[PAYMENT] Provider API error:", paymentResponse.status, errorText);
// Fallback: return direct payment URL
const fallbackUrl = `https://app.pakasir.com/pay/${PAYMENT_PROJECT_SLUG}/${amount}?order_id=${order_id}`;
return new Response(
JSON.stringify({
success: true,
data: {
payment_url: fallbackUrl,
fallback: true,
order_id: order_id,
}
}),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
const result = await paymentResponse.json();
console.log("[PAYMENT] Payment created:", result);
// Extract QR data from response
const qrData = result.payment || result;
const qrString = qrData.payment_number || qrData.qr_string || null;
const expiresAt = qrData.expired_at || null;
// Store QR string in database for in-app display
if (qrString) {
const { error: updateError } = await supabase
.from("orders")
.update({
qr_string: qrString,
qr_expires_at: expiresAt,
})
.eq("id", order_id);
if (updateError) {
console.error("[PAYMENT] Failed to store QR string:", updateError);
// Don't fail the request, just log the error
} else {
console.log("[PAYMENT] QR string stored in database");
}
}
// Return QRIS data for display in app
return new Response(
JSON.stringify({
success: true,
data: {
method: 'qris',
qr_string: qrString,
expired_at: expiresAt,
// Fallback URL if QR code is not available
payment_url: `https://app.pakasir.com/pay/${PAYMENT_PROJECT_SLUG}/${amount}?order_id=${order_id}`,
order_id: order_id,
}
}),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (error: any) {
console.error("[PAYMENT] Unexpected error:", error);
return new Response(
JSON.stringify({
success: false,
error: error.message || "Internal server error"
}),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
});