Files
fourge-portal/supabase/functions/stripe-webhook/index.ts
T
Krao Hasanee d6e49a4c67 Add Stripe fee tracking on paid invoices + backfill function
- Store stripe_fee on invoices when webhook receives checkout.session.completed
- Display Stripe fee and net received in InvoiceDetail when paid via Stripe
- Add backfill-stripe-fees edge function to populate fee on existing paid invoices
- Migration: add stripe_fee column to invoices table
- Includes all pending portal changes (brand book, sign survey, task/project/company updates, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 12:16:22 -04:00

57 lines
2.1 KiB
TypeScript

import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
import Stripe from 'https://esm.sh/stripe@14?target=deno';
const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!, { apiVersion: '2023-10-16' });
const webhookSecret = Deno.env.get('STRIPE_WEBHOOK_SECRET')!;
serve(async (req) => {
const body = await req.text();
const sig = req.headers.get('stripe-signature');
let event: Stripe.Event;
try {
event = await stripe.webhooks.constructEventAsync(body, sig!, webhookSecret);
} catch (err) {
console.error('Webhook signature failed:', err.message);
return new Response(`Webhook Error: ${err.message}`, { status: 400 });
}
if (event.type === 'checkout.session.completed') {
const session = event.data.object as Stripe.Checkout.Session;
const invoice_id = session.metadata?.invoice_id;
if (invoice_id) {
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
);
// Retrieve the Stripe processing fee from the balance transaction
let stripe_fee: number | null = null;
try {
const paymentIntentId = session.payment_intent as string;
if (paymentIntentId) {
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId, {
expand: ['latest_charge.balance_transaction'],
});
const charge = paymentIntent.latest_charge as Stripe.Charge | null;
const balanceTx = charge?.balance_transaction as Stripe.BalanceTransaction | null;
if (balanceTx?.fee != null) {
stripe_fee = balanceTx.fee / 100;
}
}
} catch (err) {
console.error('Failed to retrieve Stripe fee:', err.message);
}
const updateData: Record<string, unknown> = { status: 'paid' };
if (stripe_fee !== null) updateData.stripe_fee = stripe_fee;
await supabase.from('invoices').update(updateData).eq('id', invoice_id);
}
}
return new Response(JSON.stringify({ received: true }), { status: 200 });
});