mirror of
https://github.com/marcogll/AnchorOS.git
synced 2026-03-15 13:24:27 +00:00
Major changes: - Add customer registration with email/phone lookup (app/booking/registro) - Add customers API endpoint (app/api/customers/route) - Implement business hours for locations (mon-fri 10-7, sat 10-6, sun closed) - Fix availability function type casting issues - Add business hours utilities (lib/utils/business-hours.ts) - Update Location type to include business_hours JSONB - Add mock payment component for testing - Remove Supabase auth from booking flow - Fix /cita redirect path in booking flow Database migrations: - Add category column to services table - Add business_hours JSONB column to locations table - Fix availability functions with proper type casting - Update get_detailed_availability to use business_hours Features: - Customer lookup by email or phone - Auto-redirect to registration if customer not found - Pre-fill customer data if exists - Business hours per day of week - Location-specific opening/closing times
201 lines
5.4 KiB
Markdown
201 lines
5.4 KiB
Markdown
# Stripe Payment Integration
|
|
|
|
## Current Status
|
|
Stripe is **ENABLED in mock mode** for testing. Real Stripe integration is partially implemented but not yet activated.
|
|
|
|
## Current Implementation
|
|
|
|
### Mock Payment System
|
|
- **Component**: `components/booking/mock-payment-form.tsx`
|
|
- **Usage**: Used in `/booking/cita` for customer bookings
|
|
- **Functionality**:
|
|
- Validates card number format (Luhn algorithm)
|
|
- Accepts any card with correct format
|
|
- Simulates payment processing
|
|
- Does not charge real payments
|
|
|
|
### Environment Variables
|
|
Currently set in `.env.local` (keys removed for security - use your own Stripe keys):
|
|
```bash
|
|
NEXT_PUBLIC_STRIPE_ENABLED=false
|
|
STRIPE_SECRET_KEY=sk_live_your_stripe_secret_key_here
|
|
STRIPE_PUBLISHABLE_KEY=pk_live_your_stripe_publishable_key_here
|
|
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
|
|
```
|
|
|
|
**Note**: `NEXT_PUBLIC_STRIPE_ENABLED=false` means we use mock payments. Stripe keys are stored but not used yet.
|
|
|
|
## To Enable Real Stripe Payments
|
|
|
|
### 1. Update Environment Variables
|
|
|
|
In `.env.local`:
|
|
|
|
```bash
|
|
NEXT_PUBLIC_STRIPE_ENABLED=true
|
|
STRIPE_SECRET_KEY=sk_test_your_real_stripe_secret_key
|
|
STRIPE_PUBLISHABLE_KEY=pk_test_your_real_stripe_publishable_key
|
|
STRIPE_WEBHOOK_SECRET=whsec_your_real_webhook_secret
|
|
```
|
|
|
|
### 2. Create Stripe Webhook Endpoint
|
|
|
|
Create `app/api/stripe/webhook/route.ts`:
|
|
|
|
```typescript
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
import Stripe from 'stripe'
|
|
import { supabaseAdmin } from '@/lib/supabase/admin'
|
|
|
|
const stripe = new Stripe(process.env.STRIPE_WEBHOOK_SECRET!)
|
|
|
|
export async function POST(request: NextRequest) {
|
|
const body = await request.text()
|
|
const sig = request.headers.get('stripe-signature')!
|
|
|
|
let event
|
|
|
|
try {
|
|
event = stripe.webhooks.constructEvent(
|
|
body,
|
|
sig,
|
|
process.env.STRIPE_WEBHOOK_SECRET!
|
|
)
|
|
} catch (err) {
|
|
return NextResponse.json({ error: 'Invalid signature' }, { status: 400 })
|
|
}
|
|
|
|
switch (event.type) {
|
|
case 'payment_intent.succeeded':
|
|
const paymentIntent = event.data.object as Stripe.PaymentIntent
|
|
// Update booking status to confirmed
|
|
await supabaseAdmin
|
|
.from('bookings')
|
|
.update({ status: 'confirmed', is_paid: true })
|
|
.eq('payment_reference', paymentIntent.id)
|
|
break
|
|
|
|
case 'payment_intent.payment_failed':
|
|
const failedIntent = event.data.object as Stripe.PaymentIntent
|
|
// Update booking status to pending/notify customer
|
|
await supabaseAdmin
|
|
.from('bookings')
|
|
.update({ status: 'pending' })
|
|
.eq('payment_reference', failedIntent.id)
|
|
break
|
|
|
|
case 'charge.refunded':
|
|
// Handle refunds - mark as cancelled or retain deposit
|
|
break
|
|
|
|
default:
|
|
console.log(`Unhandled event type: ${event.type}`)
|
|
}
|
|
|
|
return NextResponse.json({ received: true })
|
|
}
|
|
```
|
|
|
|
### 3. Replace Mock Payment with Real Stripe
|
|
|
|
In `app/booking/cita/page.tsx`:
|
|
|
|
Replace the `MockPaymentForm` component usage with real Stripe integration:
|
|
|
|
```tsx
|
|
import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js'
|
|
|
|
// Replace the mock payment section with:
|
|
<CardElement
|
|
options={{
|
|
style: {
|
|
base: {
|
|
fontSize: '16px',
|
|
color: 'var(--charcoal-brown)',
|
|
'::placeholder': {
|
|
color: 'var(--mocha-taupe)',
|
|
},
|
|
},
|
|
},
|
|
}}
|
|
/>
|
|
```
|
|
|
|
### 4. Update Payment Handling
|
|
|
|
Replace the `handleMockPayment` function with real Stripe confirmation:
|
|
|
|
```tsx
|
|
const handlePayment = async () => {
|
|
if (!stripe || !elements) return
|
|
|
|
const { error, paymentIntent } = await stripe.confirmCardPayment(
|
|
paymentIntent.clientSecret,
|
|
{
|
|
payment_method: {
|
|
card: elements.getElement(CardElement)!,
|
|
}
|
|
}
|
|
)
|
|
|
|
if (error) {
|
|
// Handle error
|
|
setErrors({ submit: error.message })
|
|
setPageLoading(false)
|
|
} else {
|
|
// Payment succeeded, create booking
|
|
createBooking(paymentIntent.id)
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. Configure Stripe Dashboard
|
|
|
|
1. Go to Stripe Dashboard > Webhooks
|
|
2. Add endpoint: `https://booking.anchor23.mx/api/stripe/webhook`
|
|
3. Select events:
|
|
- `payment_intent.succeeded`
|
|
- `payment_intent.payment_failed`
|
|
- `charge.refunded`
|
|
4. Copy the webhook signing secret to `STRIPE_WEBHOOK_SECRET`
|
|
|
|
### 6. Update Create Payment Intent API
|
|
|
|
Ensure `/api/create-payment-intent` uses your real Stripe secret key.
|
|
|
|
## Deposit Calculation Logic
|
|
|
|
According to PRD, deposit is calculated as:
|
|
- **Weekday (Mon-Fri)**: 50% of service price, max $200
|
|
- **Weekend (Sat-Sun)**: $200 flat rate
|
|
|
|
Current implementation: `Math.min(service.base_price * 0.5, 200)`
|
|
|
|
Weekend logic needs to be added.
|
|
|
|
## Testing
|
|
|
|
### Mock Payment Testing (Current)
|
|
- Use any valid card number (Luhn algorithm compliant)
|
|
- Any expiration date in the future
|
|
- Any 3-digit CVC
|
|
- Payment always succeeds
|
|
|
|
### Real Stripe Testing (When Enabled)
|
|
- Use Stripe test cards: https://stripe.com/docs/testing
|
|
- Test success scenarios: `4242 4242 4242 4242`
|
|
- Test failure scenarios: `4000 0000 0002` (generic decline)
|
|
- Verify webhooks are received correctly
|
|
- Test refunds via Stripe Dashboard
|
|
|
|
## Deployment Checklist
|
|
|
|
Before going live with Stripe:
|
|
- [ ] Update `NEXT_PUBLIC_STRIPE_ENABLED=true`
|
|
- [ ] Use live Stripe keys (not test keys)
|
|
- [ ] Configure production webhook endpoint
|
|
- [ ] Test payment flow end-to-end
|
|
- [ ] Verify bookings are marked as confirmed
|
|
- [ ] Test refund flow
|
|
- [ ] Monitor Stripe dashboard for errors
|
|
- [ ] Set up email notifications for payment failures |