149 lines
4.4 KiB
Markdown
149 lines
4.4 KiB
Markdown
# Helcim Payment Flow Fix
|
|
|
|
## Issue
|
|
The initial implementation had a mismatch in the payment flow:
|
|
- **Error**: "Customer ID is required" when attempting to purchase event tickets
|
|
- **Cause**: The payment initialization endpoint required a `customerId`, but event tickets are one-time purchases that don't need customer accounts
|
|
|
|
## Solution
|
|
|
|
### 1. Updated Payment Initialization (`server/api/helcim/initialize-payment.post.js`)
|
|
|
|
**Changed from:**
|
|
- Always requiring `customerId`
|
|
- Always using `verify` payment type (for card verification)
|
|
- Amount fixed at 0
|
|
|
|
**Changed to:**
|
|
- `customerId` is now optional
|
|
- Detects event ticket purchases via `metadata.type === 'event_ticket'`
|
|
- Uses `purchase` type for event tickets with amount > 0
|
|
- Uses `verify` type for subscription setup (card verification)
|
|
|
|
```javascript
|
|
// For event tickets: HelcimPay.js completes the purchase immediately
|
|
const paymentType = isEventTicket && amount > 0 ? 'purchase' : 'verify'
|
|
```
|
|
|
|
### 2. Updated Ticket Purchase Endpoint (`server/api/events/[id]/tickets/purchase.post.js`)
|
|
|
|
**Changed from:**
|
|
- Expecting `paymentToken` from client
|
|
- Calling `processHelcimPayment()` to process the payment
|
|
- Payment happens server-side after modal closes
|
|
|
|
**Changed to:**
|
|
- Expecting `transactionId` from client
|
|
- Payment already completed by HelcimPay.js modal
|
|
- Server just records the transaction
|
|
|
|
**Why?**
|
|
When using HelcimPay.js with `purchase` type, the payment is processed inside the modal and we get a completed transaction back. We don't need to make a second API call to charge the card.
|
|
|
|
### 3. Updated Frontend Component (`app/components/EventTicketPurchase.vue`)
|
|
|
|
**Changed from:**
|
|
- Getting `cardToken` from payment modal
|
|
- Sending `paymentToken` to purchase endpoint
|
|
|
|
**Changed to:**
|
|
- Getting `transactionId` from payment modal
|
|
- Sending `transactionId` to purchase endpoint
|
|
- Added validation to ensure transaction ID exists
|
|
|
|
## Payment Flow Comparison
|
|
|
|
### Old Flow (Subscriptions)
|
|
```
|
|
1. Initialize payment session (verify mode, amount: 0)
|
|
2. User enters card in modal
|
|
3. Modal returns cardToken
|
|
4. Send cardToken to server
|
|
5. Server calls Helcim API to charge card
|
|
6. Create registration
|
|
```
|
|
|
|
### New Flow (Event Tickets)
|
|
```
|
|
1. Initialize payment session (purchase mode, amount: actual price)
|
|
2. User enters card in modal
|
|
3. Helcim charges card immediately
|
|
4. Modal returns transactionId
|
|
5. Send transactionId to server
|
|
6. Server records transaction and creates registration
|
|
```
|
|
|
|
## Benefits
|
|
|
|
1. **Simpler**: One API call instead of two
|
|
2. **Faster**: Payment completes in the modal
|
|
3. **More Secure**: No need to handle card tokens server-side
|
|
4. **PCI Compliant**: Card data never touches our server
|
|
5. **Better UX**: User sees immediate payment confirmation
|
|
|
|
## Testing
|
|
|
|
### Free Member Tickets
|
|
```bash
|
|
# Should work without payment modal
|
|
1. Member logs in
|
|
2. Views event with member.isFree: true
|
|
3. Fills name/email
|
|
4. Clicks "Complete Registration"
|
|
5. ✓ Registers immediately (no payment)
|
|
```
|
|
|
|
### Paid Public Tickets
|
|
```bash
|
|
# Should trigger Helcim modal
|
|
1. Non-member views event
|
|
2. Sees public ticket price
|
|
3. Fills name/email
|
|
4. Clicks "Pay $XX.XX"
|
|
5. Helcim modal opens
|
|
6. Enters test card: 4242 4242 4242 4242
|
|
7. Payment processes
|
|
8. ✓ Modal closes with success
|
|
9. ✓ Registration created with transaction ID
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
Ensure these are set in `.env`:
|
|
|
|
```bash
|
|
# Public (client-side)
|
|
NUXT_PUBLIC_HELCIM_TOKEN=your_helcim_api_token
|
|
NUXT_PUBLIC_HELCIM_ACCOUNT_ID=your_account_id
|
|
|
|
# Private (server-side)
|
|
HELCIM_API_TOKEN=your_helcim_api_token
|
|
```
|
|
|
|
## Common Issues
|
|
|
|
### "Customer ID is required"
|
|
- ✅ **Fixed** - This error should no longer occur for event tickets
|
|
- If you still see it, check that `metadata.type: 'event_ticket'` is being passed
|
|
|
|
### "No transaction ID received"
|
|
- Check browser console for HelcimPay.js errors
|
|
- Verify Helcim credentials are correct
|
|
- Ensure test mode is enabled for testing
|
|
|
|
### Payment modal doesn't open
|
|
- Check that HelcimPay.js script loaded (see console)
|
|
- Verify `NUXT_PUBLIC_HELCIM_TOKEN` is set
|
|
- Check browser console for initialization errors
|
|
|
|
## Files Changed
|
|
|
|
1. `server/api/helcim/initialize-payment.post.js` - Smart payment type detection
|
|
2. `server/api/events/[id]/tickets/purchase.post.js` - Accept transactionId instead of token
|
|
3. `app/components/EventTicketPurchase.vue` - Pass transactionId instead of cardToken
|
|
|
|
---
|
|
|
|
**Status**: ✅ Fixed
|
|
**Date**: 2025-10-14
|
|
**Impact**: Event ticket purchases now work correctly with Helcim
|