510 lines
14 KiB
TypeScript
510 lines
14 KiB
TypeScript
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}`);
|
|
}
|
|
}
|