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>
This commit is contained in:
dwindown
2025-12-24 00:12:04 +07:00
parent 1a36f831cc
commit eba37df4d7
4 changed files with 78 additions and 141 deletions

View File

@@ -1,4 +1,5 @@
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": "*",
@@ -9,7 +10,6 @@ interface CreatePaymentRequest {
order_id: string;
amount: number;
description: string;
method?: 'qris' | 'paypal';
}
serve(async (req: Request) => {
@@ -24,7 +24,7 @@ serve(async (req: Request) => {
try {
const body: CreatePaymentRequest = await req.json();
const { order_id, amount, description, method = 'qris' } = body;
const { order_id, amount, description } = body;
if (!order_id || !amount) {
return new Response(
@@ -36,6 +36,10 @@ serve(async (req: Request) => {
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");
@@ -45,26 +49,9 @@ serve(async (req: Request) => {
);
}
console.log("[PAYMENT] Creating payment transaction:", { order_id, amount, method });
console.log("[PAYMENT] Creating QRIS transaction:", { order_id, amount });
if (method === 'paypal') {
// Return PayPal payment URL
const paypalUrl = `https://app.pakasir.com/paypal/${PAYMENT_PROJECT_SLUG}/${amount}?order_id=${order_id}`;
return new Response(
JSON.stringify({
success: true,
data: {
payment_url: paypalUrl,
method: 'paypal',
order_id: order_id,
}
}),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// Default: QRIS - Call provider API
// 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' },
@@ -90,7 +77,6 @@ serve(async (req: Request) => {
success: true,
data: {
payment_url: fallbackUrl,
method: 'qris',
fallback: true,
order_id: order_id,
}
@@ -102,14 +88,37 @@ serve(async (req: Request) => {
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: result.qr_string || result.qr || null,
expired_at: result.expired_at || null,
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,

View File

@@ -95,6 +95,9 @@ serve(async (req) => {
payment_provider: "pakasir",
payment_method: payload.payment_method || "unknown",
updated_at: new Date().toISOString(),
// Clear QR string after payment
qr_string: null,
qr_expires_at: null,
})
.eq("id", order.id);

View File

@@ -0,0 +1,19 @@
-- ============================================================================
-- Add QR String Support to Orders
-- ============================================================================
-- Stores QRIS string and expiry for in-app QR code display
-- Eliminates need to redirect to external payment page
-- ============================================================================
-- Add columns for QRIS payment data
ALTER TABLE orders
ADD COLUMN IF NOT EXISTS qr_string TEXT,
ADD COLUMN IF NOT EXISTS qr_expires_at TIMESTAMPTZ;
-- Add index for cleanup of expired QR codes
CREATE INDEX IF NOT EXISTS idx_orders_qr_expires_at ON orders(qr_expires_at)
WHERE qr_expires_at IS NOT NULL;
-- Add comment
COMMENT ON COLUMN orders.qr_string IS 'QRIS payment string for generating QR code in-app. Cleared after payment or expiration.';
COMMENT ON COLUMN orders.qr_expires_at IS 'QRIS code expiration timestamp. Used for cleanup and validation.';