1+ import { serve } from "https://deno.land/std@0.190.0/http/server.ts" ;
2+ import Stripe from "https://esm.sh/stripe@14.21.0" ;
3+ import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.0" ;
4+
5+ const corsHeaders = {
6+ "Access-Control-Allow-Origin" : "*" ,
7+ "Access-Control-Allow-Headers" : "authorization, x-client-info, apikey, content-type" ,
8+ } ;
9+
10+ serve ( async ( req ) => {
11+ // Handle CORS preflight requests
12+ if ( req . method === "OPTIONS" ) {
13+ return new Response ( null , { headers : corsHeaders } ) ;
14+ }
15+
16+ try {
17+ console . log ( '💳 STRIPE PAYMENT METHODS - Début traitement' ) ;
18+
19+ // Initialize Supabase client
20+ const supabaseClient = createClient (
21+ Deno . env . get ( "SUPABASE_URL" ) ?? "" ,
22+ Deno . env . get ( "SUPABASE_ANON_KEY" ) ?? ""
23+ ) ;
24+
25+ // Get authenticated user
26+ const authHeader = req . headers . get ( "Authorization" ) ! ;
27+ const token = authHeader . replace ( "Bearer " , "" ) ;
28+ const { data } = await supabaseClient . auth . getUser ( token ) ;
29+ const user = data . user ;
30+
31+ if ( ! user ?. email ) {
32+ throw new Error ( "User not authenticated" ) ;
33+ }
34+
35+ console . log ( '👤 STRIPE PAYMENT METHODS - Utilisateur:' , user . email ) ;
36+
37+ // Initialize Stripe
38+ const stripe = new Stripe ( Deno . env . get ( "STRIPE_SECRET_KEY" ) || "" , {
39+ apiVersion : "2023-10-16" ,
40+ } ) ;
41+
42+ // Handle different HTTP methods
43+ if ( req . method === "GET" ) {
44+ return await handleGetPaymentMethods ( stripe , user . email ) ;
45+ } else if ( req . method === "POST" ) {
46+ const body = await req . json ( ) ;
47+ return await handlePaymentMethodAction ( stripe , body , user . email ) ;
48+ } else if ( req . method === "DELETE" ) {
49+ const body = await req . json ( ) ;
50+ return await handleDeletePaymentMethod ( stripe , body ) ;
51+ }
52+
53+ return new Response ( JSON . stringify ( { error : "Method not allowed" } ) , {
54+ status : 405 ,
55+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
56+ } ) ;
57+
58+ } catch ( error ) {
59+ console . error ( '❌ STRIPE PAYMENT METHODS - Erreur:' , error ) ;
60+ return new Response ( JSON . stringify ( {
61+ error : error instanceof Error ? error . message : "Internal server error"
62+ } ) , {
63+ status : 500 ,
64+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
65+ } ) ;
66+ }
67+ } ) ;
68+
69+ async function handleGetPaymentMethods ( stripe : Stripe , userEmail : string ) {
70+ console . log ( '📋 GET PAYMENT METHODS - Récupération pour:' , userEmail ) ;
71+
72+ try {
73+ // Find customer by email
74+ const customers = await stripe . customers . list ( {
75+ email : userEmail ,
76+ limit : 1
77+ } ) ;
78+
79+ if ( customers . data . length === 0 ) {
80+ console . log ( '👤 GET PAYMENT METHODS - Aucun client Stripe trouvé' ) ;
81+ return new Response ( JSON . stringify ( { paymentMethods : [ ] } ) , {
82+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
83+ status : 200 ,
84+ } ) ;
85+ }
86+
87+ const customer = customers . data [ 0 ] ;
88+ console . log ( '👤 GET PAYMENT METHODS - Client trouvé:' , customer . id ) ;
89+
90+ // Get payment methods for customer
91+ const paymentMethods = await stripe . paymentMethods . list ( {
92+ customer : customer . id ,
93+ type : 'card' ,
94+ } ) ;
95+
96+ console . log ( '💳 GET PAYMENT METHODS - Méthodes trouvées:' , paymentMethods . data . length ) ;
97+
98+ // Format payment methods for frontend
99+ const formattedMethods = paymentMethods . data . map ( pm => ( {
100+ id : pm . id ,
101+ type : pm . type ,
102+ card : pm . card ? {
103+ brand : pm . card . brand ,
104+ last4 : pm . card . last4 ,
105+ exp_month : pm . card . exp_month ,
106+ exp_year : pm . card . exp_year ,
107+ } : null ,
108+ created : pm . created ,
109+ } ) ) ;
110+
111+ return new Response ( JSON . stringify ( {
112+ paymentMethods : formattedMethods ,
113+ customerId : customer . id
114+ } ) , {
115+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
116+ status : 200 ,
117+ } ) ;
118+
119+ } catch ( error ) {
120+ console . error ( '❌ GET PAYMENT METHODS - Erreur:' , error ) ;
121+ throw error ;
122+ }
123+ }
124+
125+ async function handlePaymentMethodAction ( stripe : Stripe , body : any , userEmail : string ) {
126+ const { action, customerId, paymentMethodId } = body ;
127+
128+ console . log ( '⚙️ PAYMENT METHOD ACTION - Action:' , action ) ;
129+
130+ if ( action === 'attach' ) {
131+ // Attach payment method to customer
132+ await stripe . paymentMethods . attach ( paymentMethodId , {
133+ customer : customerId ,
134+ } ) ;
135+
136+ console . log ( '✅ PAYMENT METHOD ACTION - Méthode attachée' ) ;
137+ return new Response ( JSON . stringify ( { success : true } ) , {
138+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
139+ status : 200 ,
140+ } ) ;
141+
142+ } else if ( action === 'set_default' ) {
143+ // Set as default payment method
144+ await stripe . customers . update ( customerId , {
145+ invoice_settings : {
146+ default_payment_method : paymentMethodId ,
147+ } ,
148+ } ) ;
149+
150+ console . log ( '✅ PAYMENT METHOD ACTION - Méthode définie par défaut' ) ;
151+ return new Response ( JSON . stringify ( { success : true } ) , {
152+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
153+ status : 200 ,
154+ } ) ;
155+ }
156+
157+ return new Response ( JSON . stringify ( { error : "Invalid action" } ) , {
158+ status : 400 ,
159+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
160+ } ) ;
161+ }
162+
163+ async function handleDeletePaymentMethod ( stripe : Stripe , body : any ) {
164+ const { paymentMethodId } = body ;
165+
166+ console . log ( '🗑️ DELETE PAYMENT METHOD - ID:' , paymentMethodId ) ;
167+
168+ if ( ! paymentMethodId ) {
169+ return new Response ( JSON . stringify ( { error : "Payment method ID required" } ) , {
170+ status : 400 ,
171+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
172+ } ) ;
173+ }
174+
175+ // Detach payment method (this effectively deletes it from the customer)
176+ await stripe . paymentMethods . detach ( paymentMethodId ) ;
177+
178+ console . log ( '✅ DELETE PAYMENT METHOD - Méthode supprimée' ) ;
179+ return new Response ( JSON . stringify ( { success : true } ) , {
180+ headers : { ...corsHeaders , "Content-Type" : "application/json" } ,
181+ status : 200 ,
182+ } ) ;
183+ }
0 commit comments