<?php
 namespace App\Modules\Sms\Plivo; use App\Core\Sms\AbstractSms; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; class Plivo extends AbstractSms { public function sendSms(array $params): array { $to = $params['to'] ?? null; $content = $params['content'] ?? null; if (! $to || ! $content) { return ['success' => false, 'error' => 'Required fields missing (to, content)']; } if ($this->isTestMode) { Log::info('Plivo TEST SMS', ['to' => $to]); return ['success' => true, 'message_id' => 'test_plivo_'.uniqid()]; } $authId = $this->getConfig('auth_id'); $authToken = $this->getConfig('auth_token'); $from = $this->getConfig('from'); if (! $authId || ! $authToken || ! $from) { return ['success' => false, 'error' => 'Plivo configuration incomplete']; } try { $resp = Http::withBasicAuth($authId, $authToken) ->timeout(30) ->post("https://api.plivo.com/v1/Account/{$authId}/Message/", [ 'src' => $from, 'dst' => $this->normalizeMsisdn($to, $this->getConfig('default_country_code')), 'text' => $content, ]); if (! $resp->successful()) { return ['success' => false, 'error' => 'Plivo HTTP '.$resp->status()]; } $data = $resp->json(); if (isset($data['error']) && $data['error'] !== null && $data['error'] !== '') { return ['success' => false, 'error' => 'Plivo rejected the message']; } $messageId = $data['message_uuid'][0] ?? ($data['message_uuid'] ?? null); if (! $messageId) { return ['success' => false, 'error' => 'Plivo did not return a message_uuid']; } return ['success' => true, 'message_id' => $messageId]; } catch (\Throwable $e) { return ['success' => false, 'error' => $e->getMessage()]; } } public function testConnection(array $params): array { $authId = $params['auth_id'] ?? $this->getConfig('auth_id'); $authToken = $params['auth_token'] ?? $this->getConfig('auth_token'); if (! $authId || ! $authToken) { return ['success' => false, 'message' => 'auth_id/auth_token required']; } try { $resp = Http::withBasicAuth($authId, $authToken)->timeout(15) ->get("https://api.plivo.com/v1/Account/{$authId}/"); if ($resp->successful()) { return ['success' => true, 'message' => 'Plivo connection OK']; } if ($resp->status() === 401) { return ['success' => false, 'message' => 'Plivo authentication failed (check auth_id/auth_token)']; } return ['success' => false, 'message' => 'Plivo HTTP '.$resp->status()]; } catch (\Throwable $e) { return ['success' => false, 'message' => 'Plivo connection error']; } } public function handleDeliveryReport(array $payload): ?array { $messageId = $payload['MessageUUID'] ?? $payload['message_uuid'] ?? $payload['MessageUuid'] ?? null; $rawStatus = $payload['Status'] ?? $payload['status'] ?? null; if (! $messageId || ! $rawStatus) { return null; } $normalized = strtolower((string) $rawStatus); $status = $normalized === 'delivered' ? 'delivered' : 'failed'; return [ 'provider_message_id' => (string) $messageId, 'status' => $status, 'detail' => $normalized, ]; } public function getFeatures(): array { return array_merge(parent::getFeatures(), [ 'delivery_reports' => true, ]); } public function getRequiredConfigFields(): array { return ['auth_id', 'auth_token', 'from']; } public function getConfigFields(): array { return [ 'auth_id' => ['type' => 'text', 'label' => 'Plivo Auth ID', 'required' => true], 'auth_token' => ['type' => 'password', 'label' => 'Plivo Auth Token', 'required' => true, 'encrypted' => true], 'from' => ['type' => 'text', 'label' => 'Sender Number / Short Code', 'required' => true], 'default_country_code' => ['type' => 'text', 'label' => 'Default Country Code (e.g. 1, 44)', 'required' => false], 'test_mode' => ['type' => 'boolean', 'label' => 'Test Mode', 'default' => true], ]; } } 