Files
acmcc/supabase/functions/confirm-reservation-payment/index.ts
T
2026-06-01 20:19:26 -04:00

136 lines
4.9 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.39.3";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers":
"authorization, x-client-info, apikey, content-type, x-supabase-client-platform, x-supabase-client-platform-version, x-supabase-client-runtime, x-supabase-client-runtime-version",
};
serve(async (req) => {
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);
const { booking_id, session_id } = await req.json();
if (!booking_id) {
return new Response(
JSON.stringify({ error: "Missing booking_id" }),
{ status: 400, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// Fetch booking
const { data: booking, error: bookingErr } = await supabase
.from("amenity_bookings")
.select("*")
.eq("id", booking_id)
.single();
if (bookingErr || !booking) {
return new Response(
JSON.stringify({ error: "Booking not found" }),
{ status: 404, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// Only process if still pending_payment
if (booking.status !== "pending_payment") {
return new Response(
JSON.stringify({ success: true, message: "Already processed" }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
// Update booking status to confirmed
await supabase
.from("amenity_bookings")
.update({ status: "confirmed" })
.eq("id", booking_id);
// Extract pin_id from notes
let pinId: string | null = null;
try {
const notes = typeof booking.notes === "string" ? JSON.parse(booking.notes) : booking.notes;
pinId = notes?.pin_id || null;
} catch { /* ignore */ }
// Mark pin as rented
if (pinId && booking.amenity_id) {
const { data: amenity } = await supabase
.from("amenities")
.select("map_config")
.eq("id", booking.amenity_id)
.single();
if (amenity?.map_config?.pins) {
const updatedPins = amenity.map_config.pins.map((pin: any) =>
pin.id === pinId ? { ...pin, status: "rented" } : pin
);
await supabase
.from("amenities")
.update({
map_config: { ...amenity.map_config, pins: updatedPins },
updated_at: new Date().toISOString(),
})
.eq("id", booking.amenity_id);
}
}
// Send confirmation email
if (booking.guest_email) {
try {
const { data: amenityRow } = await supabase
.from("amenities").select("name, association_id").eq("id", booking.amenity_id).single();
const { data: assocRow } = amenityRow?.association_id
? await supabase.from("associations").select("name").eq("id", amenityRow.association_id).single()
: { data: null };
const { data: pageRow } = amenityRow?.association_id
? await supabase.from("association_public_pages").select("slug").eq("association_id", amenityRow.association_id).maybeSingle()
: { data: null };
const origin = req.headers.get("origin") || "https://avria.cloud";
const dateObj = booking.booking_date ? new Date(`${booking.booking_date}T12:00:00`) : null;
const formattedDate = dateObj
? dateObj.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })
: "";
await supabase.functions.invoke("send-transactional-email", {
body: {
templateName: "amenity-booking-confirmation",
recipientEmail: booking.guest_email,
idempotencyKey: `amenity-booking-confirmed-${booking.id}`,
templateData: {
guestName: booking.guest_name,
amenityName: amenityRow?.name,
associationName: (assocRow as any)?.name,
bookingDate: formattedDate,
startTime: booking.start_time || "",
status: "confirmed",
confirmationLink: `${origin}/booking/${booking.id}`,
},
},
});
} catch (err) {
console.error("Failed to send confirmation email:", err);
}
}
return new Response(
JSON.stringify({ success: true }),
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
} catch (err) {
console.error("Error in confirm-reservation-payment:", err);
return new Response(
JSON.stringify({ error: err.message || "Internal server error" }),
{ status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } }
);
}
});