import { phoneNumberOnly, toTime, } from 'src/modules/queue/domain/helpers/time.helper'; import { WhatsappQueue } from './entity/whatsapp-queue.entity'; import { BOOKING_QR_URL, BOOKING_TICKET_URL, WHATSAPP_BUSINESS_ACCESS_TOKEN, WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID, WHATSAPP_BUSINESS_API_URL, WHATSAPP_BUSINESS_QUEUE_URL, WHATSAPP_BUSINESS_VERSION, } from './whatsapp.constant'; import axios from 'axios'; import { Logger } from '@nestjs/common'; import { apm } from 'src/core/apm'; import { WhatsappBookingCreate } from './entity/booking.entity'; import * as moment from 'moment'; export class WhatsappService { async sendMessage(data) { const config = { method: 'post', url: `${WHATSAPP_BUSINESS_API_URL}/${WHATSAPP_BUSINESS_VERSION}/${WHATSAPP_BUSINESS_ACCOUNT_NUMBER_ID}/messages`, headers: { Authorization: `Bearer ${WHATSAPP_BUSINESS_ACCESS_TOKEN}`, 'Content-Type': 'application/json', }, data: data, }; try { const response = await axios(config); return response.data; } catch (error) { if (axios.isAxiosError(error)) { if (error.response) { console.error('Axios error response:', { status: error.response.status, data: error.response.data, headers: error.response.headers, error: error.response.data?.error?.error_data, }); } else if (error.request) { console.error('Axios error request:', error.request); } else { console.error('Axios error message:', error.message); } } Logger.error(error); apm?.captureError(error); return null; } } async queueRegister(data: WhatsappQueue) { const queueUrl = `${WHATSAPP_BUSINESS_QUEUE_URL}?id=${data.id}`; const payload = { messaging_product: 'whatsapp', to: phoneNumberOnly(data.phone), // recipient's phone number type: 'template', template: { name: 'queue_created', language: { code: 'id', // language code }, components: [ { type: 'header', parameters: [ { parameter_name: 'queue_code', type: 'text', text: data.code, // replace with queue_code variable }, ], }, { type: 'body', parameters: [ { parameter_name: 'name', type: 'text', text: data.name, // replace with name variable }, { parameter_name: 'item_name', type: 'text', text: data.item_name, // replace with item_name variable }, { parameter_name: 'queue_code', type: 'text', text: data.code, // replace with queue_code variable }, { parameter_name: 'queue_time', type: 'text', text: toTime(data.time), // replace with queue_time variable }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: queueUrl, // replace with dynamic URL }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log( `Notification register for ${data.code} send to ${data.phone}`, ); } async bookingCreated(data: WhatsappBookingCreate) { const imageUrl = `${BOOKING_QR_URL}${data.id}`; const momentDate = moment(data.time); const fallbackValue = momentDate.locale('id').format('dddd, DD MMMM YYYY'); // const dayOfWeek = momentDate.day(); // const dayOfMonth = momentDate.date(); // const year = momentDate.year(); // const month = momentDate.month() + 1; // const hour = momentDate.hour(); // const minute = momentDate.minute(); const payload = { messaging_product: 'whatsapp', to: phoneNumberOnly(data.phone), // recipient's phone number type: 'template', template: { name: 'booking_online', language: { code: 'id', // language code }, components: [ { type: 'header', parameters: [ { type: 'image', image: { link: imageUrl, }, }, ], }, { type: 'body', parameters: [ { type: 'text', parameter_name: 'customer', text: data.name, // replace with name variable }, { type: 'text', parameter_name: 'booking_code', text: data.code, // replace with queue_code variable }, { type: 'text', parameter_name: 'booking_date', text: fallbackValue, }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: data.id, // replace with dynamic URL }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log( `Notification register Booking for ${data.code} send to ${data.phone}`, ); } async rescheduleCreated(data: WhatsappBookingCreate) { const imageUrl = `${BOOKING_QR_URL}${data.id}`; const momentDate = moment(data.time); const fallbackValue = momentDate.locale('id').format('dddd, DD MMMM YYYY'); // const dayOfWeek = momentDate.day(); // const dayOfMonth = momentDate.date(); // const year = momentDate.year(); // const month = momentDate.month() + 1; // const hour = momentDate.hour(); // const minute = momentDate.minute(); const payload = { messaging_product: 'whatsapp', to: phoneNumberOnly(data.phone), // recipient's phone number type: 'template', template: { name: 'reschedule_created', language: { code: 'id', // language code }, components: [ { type: 'header', parameters: [ { type: 'image', image: { link: imageUrl, }, }, ], }, { type: 'body', parameters: [ { type: 'text', parameter_name: 'customer', text: data.name, // replace with name variable }, { type: 'text', parameter_name: 'booking_code', text: data.code, // replace with queue_code variable }, { type: 'text', parameter_name: 'booking_date', text: fallbackValue, }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: data.id, // replace with dynamic URL }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log( `Notification register Booking for ${data.code} send to ${data.phone}`, ); } async bookingRegister(data: WhatsappBookingCreate, paymentUrl: string) { const momentDate = moment(data.time); const fallbackValue = momentDate.locale('id').format('dddd, DD MMMM YYYY'); const payload = { messaging_product: 'whatsapp', to: phoneNumberOnly(data.phone), // recipient's phone number type: 'template', template: { name: 'booking_register', language: { code: 'id', // language code }, components: [ { type: 'body', parameters: [ { type: 'text', parameter_name: 'customer', text: data.name, // replace with name variable }, { type: 'text', parameter_name: 'booking_date', text: fallbackValue, }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: paymentUrl, // replace with dynamic URL }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log( `Notification register Booking for ${data.code} send to ${data.phone}`, ); } async bookingRescheduleOTP(data: WhatsappBookingCreate) { const momentDate = moment(data.time); const fallbackValue = momentDate.locale('id').format('dddd, DD MMMM YYYY'); const payload = { messaging_product: 'whatsapp', to: phoneNumberOnly(data.phone), // recipient's phone number type: 'template', template: { name: 'booking_reschedule', language: { code: 'id', // language code }, components: [ { type: 'body', parameters: [ { type: 'text', parameter_name: 'customer', text: data.name, // replace with name variable }, { type: 'text', parameter_name: 'booking_code', text: data.code, // replace with queue_code variable }, { type: 'text', parameter_name: 'booking_date', text: fallbackValue, }, { type: 'text', parameter_name: 'otp', text: data.code, }, ], }, { type: 'button', sub_type: 'copy_code', index: '0', parameters: [ { type: 'coupon_code', coupon_code: data.code, }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log( `Notification reschedule Booking for ${data.code} send to ${data.phone}`, ); } async sendOtpNotification(data: { phone: string; code: string }) { // Compose the WhatsApp message payload for OTP using Facebook WhatsApp API const payload = { messaging_product: 'whatsapp', to: data.phone, // recipient's phone number in international format type: 'template', template: { name: 'booking_otp', // Make sure this template is approved in WhatsApp Business Manager language: { code: 'id', // or 'en' if you want English }, components: [ { type: 'body', parameters: [ { type: 'text', text: parseInt(data.code), // OTP code }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: `${data.code}`, }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) { Logger.log( `OTP notification for code ${data.code} sent to ${data.phone}`, ); } } async sendTemplateMessage(data: { phone: string; templateMsg: any }) { const payload = { messaging_product: 'whatsapp', to: data.phone, type: 'template', template: data?.templateMsg, }; const response = await this.sendMessage(payload); if (response) { Logger.log( `OTP notification for template ${data.templateMsg} sent to ${data.phone}`, ); } } async queueProcess(data: WhatsappQueue) { const queueUrl = `${WHATSAPP_BUSINESS_QUEUE_URL}?id=${data.id}`; const payload = { messaging_product: 'whatsapp', to: data.phone, // recipient's phone number type: 'template', template: { name: 'queue_process', language: { code: 'id', // language code }, components: [ { type: 'header', parameters: [ { parameter_name: 'queue_code', type: 'text', text: data.item_name, // replace with queue_code variable }, ], }, { type: 'body', parameters: [ { parameter_name: 'name', type: 'text', text: data.name, // replace with name variable }, { parameter_name: 'queue_code', type: 'text', text: data.code, // replace with queue_code variable }, { parameter_name: 'queue_time', type: 'text', text: toTime(data.time), // replace with queue_time variable }, ], }, { type: 'button', sub_type: 'url', index: '0', parameters: [ { type: 'text', text: queueUrl, // replace with dynamic URL }, ], }, ], }, }; const response = await this.sendMessage(payload); if (response) Logger.log(`Notification process for ${data.code} send to ${data.phone}`); } }