Files
dticket.tootaio.com/server/utils/whatsapp.ts
xiaomai 3f7025c8e4 feat(booking): move event and ticket configuration to database
Replace hardcoded event details and ticket types with dynamic DB records
Add booking-config API endpoint to serve active event settings
2026-05-04 10:09:08 +08:00

105 lines
2.9 KiB
TypeScript

import type { H3Event } from 'h3'
import type { PublicBooking, WhatsAppDeliveryResult } from '~~/shared/booking'
import {
formatBookingCurrency
} from '~~/shared/booking'
import { normalizePhoneNumber } from '~~/shared/auth'
import { buildAppUrl } from './app-url'
type WhatsAppMessagesResponse = {
messages?: Array<{
id?: string
}>
}
export function toWhatsAppPhoneNumber(phoneNumber: string) {
return normalizePhoneNumber(phoneNumber).replace(/\D/g, '')
}
export function buildWhatsAppDeepLink(phoneNumber: string, message: string) {
return `https://wa.me/${toWhatsAppPhoneNumber(phoneNumber)}?text=${encodeURIComponent(message)}`
}
export function buildBookingTicketReceiptMessage(event: H3Event, booking: PublicBooking) {
const receiptUrl = buildAppUrl(event, `/receipt/${booking.receiptToken}`)
return [
booking.event.title,
'',
`Hi ${booking.customerName}, your ticket receipt has been confirmed.`,
'',
`Receipt: ${receiptUrl}`,
`Seats: ${booking.seatCount}`,
`Ticket Category: ${booking.ticketLabel || booking.ticketType.toUpperCase()}`,
`Total Price: ${formatBookingCurrency(booking.totalPrice)}`,
`Date: ${booking.event.dateLabel}`,
`Time: ${booking.event.timeLabel}`,
`Venue: ${booking.event.venue}`,
'',
'Please present the QR code from the receipt at the event.'
].join('\n')
}
export async function sendBookingTicketReceiptViaWhatsApp(
event: H3Event,
booking: PublicBooking
): Promise<WhatsAppDeliveryResult> {
const recipientPhone = normalizePhoneNumber(booking.customerPhone)
const to = toWhatsAppPhoneNumber(recipientPhone)
const config = useRuntimeConfig()
const accessToken = String(config.whatsappAccessToken || '')
const phoneNumberId = String(config.whatsappPhoneNumberId || '')
const apiVersion = String(config.whatsappApiVersion || 'v23.0')
if (!accessToken || !phoneNumberId) {
return {
sent: false,
skipped: true,
recipientPhone,
apiRecipientPhone: to,
error: 'WhatsApp API credentials are not configured.'
}
}
try {
const response = await $fetch<WhatsAppMessagesResponse>(
`https://graph.facebook.com/${apiVersion}/${phoneNumberId}/messages`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`
},
body: {
messaging_product: 'whatsapp',
recipient_type: 'individual',
to,
type: 'text',
text: {
preview_url: true,
body: buildBookingTicketReceiptMessage(event, booking)
}
}
}
)
return {
sent: true,
skipped: false,
recipientPhone,
apiRecipientPhone: to,
messageId: response.messages?.[0]?.id
}
} catch (error: any) {
return {
sent: false,
skipped: false,
recipientPhone,
apiRecipientPhone: to,
error: error?.data?.error?.message || error?.message || 'WhatsApp API request failed.'
}
}
}