feat: send ticket receipts via WhatsApp and normalize phone numbers

Add WhatsApp API integration for automated receipt delivery
Enforce country codes for all phone number inputs (defaults to +60)
This commit is contained in:
2026-04-27 13:12:25 +08:00
parent faa998c7e1
commit c214d643dd
18 changed files with 208 additions and 28 deletions

View File

@@ -7,6 +7,7 @@ import { createBooking } from '../../utils/booking-repository'
import { buildBookingMessage, parseCreateBookingInput } from '../../utils/bookings'
import { assertBadRequest } from '../../utils/http'
import { getPublicContactById } from '../../utils/user-repository'
import { buildWhatsAppDeepLink } from '../../utils/whatsapp'
export default defineEventHandler(async (event): Promise<CreateBookingResponse> => {
const body = await readBody<{
@@ -46,7 +47,7 @@ export default defineEventHandler(async (event): Promise<CreateBookingResponse>
const confirmationUrl = buildAppUrl(event, `/confirmation/${confirmationToken}`)
const whatsappMessage = buildBookingMessage(booking, confirmationUrl)
const whatsappUrl = `https://wa.me/${booking.personInChargePhoneNumber}?text=${encodeURIComponent(whatsappMessage)}`
const whatsappUrl = buildWhatsAppDeepLink(booking.personInChargePhoneNumber, whatsappMessage)
return {
booking,

View File

@@ -1,7 +1,10 @@
import type { ConfirmBookingResponse } from '~~/shared/booking'
import { confirmBookingByConfirmationToken, getBookingByConfirmationToken, getBookingInventorySummary } from '../../../../utils/booking-repository'
import { getRequiredRouteParam, httpError } from '../../../../utils/http'
import { sendBookingTicketReceiptViaWhatsApp } from '../../../../utils/whatsapp'
export default defineEventHandler(async (event) => {
export default defineEventHandler(async (event): Promise<ConfirmBookingResponse> => {
const token = getRequiredRouteParam(event, 'token', 'Confirmation token')
const existingBooking = await getBookingByConfirmationToken(token)
@@ -12,7 +15,14 @@ export default defineEventHandler(async (event) => {
if (existingBooking.status === 'confirmed') {
return {
booking: existingBooking,
alreadyConfirmed: true
alreadyConfirmed: true,
ticketReceiptWhatsApp: {
sent: false,
skipped: true,
recipientPhone: existingBooking.customerPhone,
apiRecipientPhone: existingBooking.customerPhone.replace(/\D/g, ''),
error: 'Booking was already confirmed earlier.'
}
}
}
@@ -28,8 +38,11 @@ export default defineEventHandler(async (event) => {
httpError(404, 'Booking not found')
}
const ticketReceiptWhatsApp = await sendBookingTicketReceiptViaWhatsApp(event, booking)
return {
booking,
alreadyConfirmed: false
alreadyConfirmed: false,
ticketReceiptWhatsApp
}
})