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", }; serve(async (req: Request): Promise => { if (req.method === "OPTIONS") { return new Response(null, { headers: corsHeaders }); } try { const supabaseUrl = Deno.env.get("SUPABASE_URL")!; const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!; const supabase = createClient(supabaseUrl, supabaseServiceKey); console.log("[CANCEL-EXPIRED] Starting check for expired consulting orders"); // Find expired pending consulting orders const now = new Date().toISOString(); // Get orders with consulting_sessions that are pending payment and QR is expired const { data: expiredOrders, error: queryError } = await supabase .from("orders") .select(` id, payment_status, qr_expires_at, consulting_sessions ( id, topic_category, notes, session_date, start_time, end_time ) `) .eq("payment_status", "pending") .lt("qr_expires_at", now) .not("consulting_sessions", "is", null); if (queryError) { console.error("[CANCEL-EXPIRED] Query error:", queryError); throw queryError; } if (!expiredOrders || expiredOrders.length === 0) { console.log("[CANCEL-EXPIRED] No expired orders found"); return new Response( JSON.stringify({ success: true, message: "No expired orders to process", processed: 0 }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } console.log(`[CANCEL-EXPIRED] Found ${expiredOrders.length} expired orders`); let processedCount = 0; // Process each expired order for (const order of expiredOrders) { console.log(`[CANCEL-EXPIRED] Processing order: ${order.id}`); // Update order status to cancelled const { error: updateError } = await supabase .from("orders") .update({ status: "cancelled" }) .eq("id", order.id); if (updateError) { console.error(`[CANCEL-EXPIRED] Failed to update order ${order.id}:`, updateError); continue; } // Cancel all consulting sessions for this order if (order.consulting_sessions && order.consulting_sessions.length > 0) { for (const session of order.consulting_sessions) { // Delete calendar event if exists if (session.calendar_event_id) { try { await supabase.functions.invoke('delete-calendar-event', { body: { session_id: session.id } }); console.log(`[CANCEL-EXPIRED] Deleted calendar event for session: ${session.id}`); } catch (err) { console.log(`[CANCEL-EXPIRED] Failed to delete calendar event: ${err}`); // Continue anyway } } // Update session status to cancelled await supabase .from("consulting_sessions") .update({ status: "cancelled" }) .eq("id", session.id); // Delete or release time slots await supabase .from("consulting_time_slots") .delete() .eq("session_id", session.id); console.log(`[CANCEL-EXPIRED] Cancelled session: ${session.id}`); } } processedCount++; } console.log(`[CANCEL-EXPIRED] Successfully processed ${processedCount} orders`); return new Response( JSON.stringify({ success: true, message: `Successfully cancelled ${processedCount} expired consulting orders`, processed: processedCount }), { headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } catch (error: any) { console.error("[CANCEL-EXPIRED] Error:", error); return new Response( JSON.stringify({ success: false, error: error.message || "Internal server error" }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } } ); } });