e29a5891c8
Reviewed-on: #5 Co-authored-by: ISMAIL MASSERAN <ismail@koppkb.com> Co-committed-by: ISMAIL MASSERAN <ismail@koppkb.com>
133 lines
3.8 KiB
PHP
133 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class WhatsAppCloudService
|
|
{
|
|
public function isEnabled()
|
|
{
|
|
return (bool) config('whatsapp.whatsapp_cloud_enabled')
|
|
&& ! empty(config('whatsapp.token'))
|
|
&& ! empty(config('whatsapp.phone_number_id'));
|
|
}
|
|
|
|
/**
|
|
* Normalize Malaysian phone numbers to digits with country code (e.g. 60123456789).
|
|
*/
|
|
public function normalizePhone($phone)
|
|
{
|
|
if ($phone === null || $phone === '') {
|
|
return null;
|
|
}
|
|
|
|
$digits = preg_replace('/\D+/', '', (string) $phone);
|
|
if ($digits === '') {
|
|
return null;
|
|
}
|
|
|
|
if (strpos($digits, '60') === 0) {
|
|
return $digits;
|
|
}
|
|
|
|
if (strpos($digits, '0') === 0) {
|
|
return '6'.$digits;
|
|
}
|
|
|
|
return '60'.ltrim($digits, '0');
|
|
}
|
|
|
|
/**
|
|
* In non-production, always send to ADMIN_PHONE_NUMBER.
|
|
*/
|
|
public function resolveRecipient($phone)
|
|
{
|
|
if (config('app.env') !== 'production') {
|
|
return $this->normalizePhone(config('app.admin_phone_number'));
|
|
}
|
|
|
|
return $this->normalizePhone($phone);
|
|
}
|
|
|
|
/**
|
|
* Send an approved WhatsApp Cloud API template message.
|
|
*
|
|
* @param string $to E.164-ish digits without +
|
|
* @param string $templateName
|
|
* @param array<int, string> $bodyParams Ordered body variables {{1}}, {{2}}, ...
|
|
* @return array{ok:bool,status:int,body:mixed}
|
|
*/
|
|
public function sendTemplate($to, $templateName, array $bodyParams = [], $languageCode = null)
|
|
{
|
|
if (! $this->isEnabled()) {
|
|
Log::warning('WhatsApp Cloud API skipped: not enabled or missing credentials.');
|
|
|
|
return ['ok' => false, 'status' => 0, 'body' => 'disabled'];
|
|
}
|
|
|
|
$to = $this->normalizePhone($to);
|
|
if (! $to) {
|
|
return ['ok' => false, 'status' => 0, 'body' => 'invalid_phone'];
|
|
}
|
|
|
|
$languageCode = $languageCode ?: config('whatsapp.template_lang', 'en_US');
|
|
$version = config('whatsapp.api_version', 'v25.0');
|
|
$phoneNumberId = config('whatsapp.phone_number_id');
|
|
$url = "https://graph.facebook.com/{$version}/{$phoneNumberId}/messages";
|
|
|
|
$template = [
|
|
'name' => $templateName,
|
|
'language' => ['code' => $languageCode],
|
|
];
|
|
|
|
if (! empty($bodyParams)) {
|
|
$template['components'] = [[
|
|
'type' => 'body',
|
|
'parameters' => array_map(function ($value) {
|
|
return [
|
|
'type' => 'text',
|
|
'text' => (string) $value,
|
|
];
|
|
}, array_values($bodyParams)),
|
|
]];
|
|
}
|
|
|
|
$payload = [
|
|
'messaging_product' => 'whatsapp',
|
|
'to' => $to,
|
|
'type' => 'template',
|
|
'template' => $template,
|
|
];
|
|
|
|
$response = Http::withToken(config('whatsapp.token'))
|
|
->acceptJson()
|
|
->asJson()
|
|
->post($url, $payload);
|
|
|
|
$result = [
|
|
'ok' => $response->successful(),
|
|
'status' => $response->status(),
|
|
'body' => $response->json() ?? $response->body(),
|
|
];
|
|
|
|
if (! $result['ok']) {
|
|
Log::error('WhatsApp Cloud API template send failed', [
|
|
'to' => $to,
|
|
'template' => $templateName,
|
|
'status' => $result['status'],
|
|
'body' => $result['body'],
|
|
]);
|
|
} else {
|
|
Log::info('WhatsApp Cloud API template sent', [
|
|
'to' => $to,
|
|
'template' => $templateName,
|
|
'message_id' => data_get($result['body'], 'messages.0.id'),
|
|
]);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|