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 HandlePaidOrderRequest { order_id: string; user_id: string; total_amount: number; payment_method?: string; payment_provider?: string; } serve(async (req: Request): Promise => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const body: HandlePaidOrderRequest = await req.json(); const { order_id } = body; console.log("[HANDLE-PAID] Processing paid order:", order_id); const supabaseUrl = Deno.env.get("SUPABASE_URL")!; const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const supabase = createClient(supabaseUrl, supabaseServiceKey); // Get full order details with items const { data: order, error: orderError } = await supabase .from("orders") .select(` *, profiles(email, full_name), order_items ( product_id, product:products (title, type) ) `) .eq("id", order_id) .single(); if (orderError || !order) { console.error("[HANDLE-PAID] Order not found:", order_id); return new Response( JSON.stringify({ success: false, error: "Order not found" }), { status: 404, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } const userEmail = order.profiles?.email || ""; const userName = order.profiles?.full_name || "Pelanggan"; const orderItems = order.order_items as Array<{ product_id: string; product: { title: string; type: string }; }>; // Check if this is a consulting order const hasConsulting = orderItems.some(item => item.product.type === "consulting"); if (hasConsulting) { console.log("[HANDLE-PAID] Consulting order detected, processing slots"); // Update consulting slots status await supabase .from("consulting_slots") .update({ status: "confirmed" }) .eq("order_id", order_id); // Create Google Meet events for each slot const { data: consultingSlots } = await supabase .from("consulting_slots") .select("*") .eq("order_id", order_id); if (consultingSlots && consultingSlots.length > 0) { for (const slot of consultingSlots) { try { console.log("[HANDLE-PAID] Creating Google Meet for slot:", slot.id); const topic = orderItems.find(i => i.product.type === "consulting")?.product.title || "Konsultasi 1-on-1"; const meetResponse = await fetch( `${supabaseUrl}/functions/v1/create-google-meet-event`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${Deno.env.get("SUPABASE_ANON_KEY")}`, }, body: JSON.stringify({ slot_id: slot.id, date: slot.date, start_time: slot.start_time, end_time: slot.end_time, client_name: userName, client_email: userEmail, topic: topic, }), } ); if (meetResponse.ok) { const meetData = await meetResponse.json(); if (meetData.success) { console.log("[HANDLE-PAID] Meet created:", meetData.meet_link); } } } catch (error) { console.error("[HANDLE-PAID] Meet creation failed:", error); // Don't fail the entire process } } // Refresh slots to get meet_link const { data: updatedSlots } = await supabase .from("consulting_slots") .select("*") .eq("order_id", order_id); const slots = (updatedSlots || []) as Array<{ date: string; start_time: string; meet_link?: string; }>; // Send consulting notification await sendNotification(supabase, "consulting_scheduled", userEmail, { nama: userName, email: userEmail, order_id: order_id.substring(0, 8), tanggal_pesanan: new Date().toLocaleDateString("id-ID"), total: `Rp ${order.total_amount.toLocaleString("id-ID")}`, metode_pembayaran: order.payment_method || "Unknown", tanggal_konsultasi: slots[0]?.date || "", jam_konsultasi: slots.map(s => s.start_time.substring(0, 5)).join(", "), link_meet: slots[0]?.meet_link || "Akan dikirim terpisah", }, { event: "consulting_scheduled", order_id, user_id: order.user_id, user_email: userEmail, user_name: userName, total_amount: order.total_amount, payment_method: order.payment_method, slots: updatedSlots, }); } } else { // Regular product order - grant access console.log("[HANDLE-PAID] Regular product order, granting access"); for (const item of orderItems) { // Check if access already exists const { data: existingAccess } = await supabase .from("user_access") .select("id") .eq("user_id", order.user_id) .eq("product_id", item.product_id) .maybeSingle(); if (!existingAccess) { await supabase .from("user_access") .insert({ user_id: order.user_id, product_id: item.product_id, }); console.log("[HANDLE-PAID] Access granted for product:", item.product_id); } } const productTitles = orderItems.map(i => i.product.title); // Send payment success notification await sendNotification(supabase, "payment_success", userEmail, { nama: userName, email: userEmail, order_id: order_id.substring(0, 8), tanggal_pesanan: new Date().toLocaleDateString("id-ID"), total: `Rp ${order.total_amount.toLocaleString("id-ID")}`, metode_pembayaran: order.payment_method || "Unknown", produk: productTitles.join(", "), link_akses: `${Deno.env.get("SITE_URL") || ""}/access`, }, { event: "payment_success", order_id, user_id: order.user_id, user_email: userEmail, user_name: userName, total_amount: order.total_amount, payment_method: order.payment_method, products: productTitles, }); // Send access granted notification await sendNotification(supabase, "access_granted", userEmail, { nama: userName, produk: productTitles.join(", "), }, { event: "access_granted", order_id, user_id: order.user_id, user_email: userEmail, user_name: userName, products: productTitles, }); } return new Response( JSON.stringify({ success: true, order_id }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { console.error("[HANDLE-PAID] Error:", error); return new Response( JSON.stringify({ success: false, error: error.message || "Internal server error" }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } }); // Helper function to send notification async function sendNotification( supabase: any, templateKey: string, shortcodeData: Record, webhookPayload: Record ): Promise { console.log("[HANDLE-PAID] Sending notification:", templateKey); // Fetch template const { data: template } = await supabase .from("notification_templates") .select("*") .eq("key", templateKey) .single(); if (!template) { console.log("[HANDLE-PAID] Template not found:", templateKey); return; } // Send webhook if configured if (template.webhook_url) { try { await fetch(template.webhook_url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(webhookPayload), }); console.log("[HANDLE-PAID] Webhook sent to:", template.webhook_url); } catch (error) { console.error("[HANDLE-PAID] Webhook failed:", error); } } // Skip email if template is inactive if (!template.is_active) { console.log("[HANDLE-PAID] Template inactive, skipping email"); return; } // Send email via Mailketing await fetch(`${Deno.env.get("SUPABASE_URL")}/functions/v1/send-email-v2`, { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${Deno.env.get("SUPABASE_ANON_KEY")}`, }, body: JSON.stringify({ to: shortcodeData.email, subject: template.email_subject, html: template.email_body_html, shortcodeData, }), }); }