restaurantId = $restaurantId; $this->loadConfig(); $this->initClient(); } /** * Load configuration from database */ protected function loadConfig(): void { $this->configModel = WhatsappConfig::where('restaurant_id', $this->restaurantId)->first(); if ($this->configModel) { $this->config = $this->configModel->config ?? []; $this->restaurantName = $this->config['restaurant_name'] ?? ''; $this->restaurantPhone = $this->config['phone'] ?? ''; $this->dateFormat = $this->config['date_format'] ?? 'dmy'; $this->timeFormat = $this->config['time_format'] ?? '24h'; $this->loadProviderConfig(); } } /** * Load provider-specific configuration * Override in child classes */ abstract protected function loadProviderConfig(): void; /** * Initialize HTTP client * Override in child classes for provider-specific setup */ abstract protected function initClient(): void; /** * Get restaurant ID * * @return int */ public function getRestaurantId(): int { return $this->restaurantId; } /** * Get restaurant name * * @return string */ public function getRestaurantName(): string { return $this->restaurantName; } /** * Format phone number to international format * * @param string $phone * @return string */ protected function formatPhoneNumber(string $phone): string { // Remove spaces, dashes, parentheses $phone = preg_replace('/[\s\-\(\)]/', '', $phone); // Remove any whatsapp: prefix $phone = str_replace('whatsapp:', '', $phone); // Ensure it starts with + if (strpos($phone, '+') !== 0) { $phone = '+' . $phone; } return $phone; } /** * Normalize phone number (digits only) * * @param string $phone * @return string */ protected function normalizePhone(string $phone): string { return preg_replace('/[^0-9]/', '', $phone); } /** * Format date according to configuration * * @param string $date Date in Y-m-d format * @return string */ protected function formatDate(string $date): string { if (empty($date)) { return ''; } try { $dateObj = new \DateTime($date); switch ($this->dateFormat) { case 'mdy': return $dateObj->format('m/d/Y'); case 'dmy': return $dateObj->format('d/m/Y'); case 'locale': default: if (function_exists('date_i18n')) { return date_i18n(get_option('date_format', 'd/m/Y'), $dateObj->getTimestamp()); } return $dateObj->format('d/m/Y'); } } catch (\Exception $e) { return $date; } } /** * Format time according to configuration * * @param string $time Time in H:i format * @return string */ protected function formatTime(string $time): string { if (empty($time)) { return ''; } try { $timeObj = new \DateTime($time); switch ($this->timeFormat) { case '12h': return $timeObj->format('g:i A'); case '24h': default: return $timeObj->format('H:i'); } } catch (\Exception $e) { return $time; } } /** * Get base URL for webhooks * * @return string */ protected function getWebhookBaseUrl(): string { $host = $_SERVER['HTTP_HOST'] ?? ''; // Local development domains $localDomains = [ 'wp_alexreservations.test', 'localhost', '.test', '.local', ]; $isLocal = false; foreach ($localDomains as $domain) { if (str_contains($host, $domain)) { $isLocal = true; break; } } // Use tunnel URL for local development if ($isLocal && defined('ALEXR_WHATSAPP_WEBHOOK_BASE_URL')) { return ALEXR_WHATSAPP_WEBHOOK_BASE_URL; } return home_url(); } /** * Create a successful response array * * @param string $message * @param array $data * @return array */ protected function successResponse(string $message, array $data = []): array { return [ 'success' => true, 'message' => $message, 'data' => $data, ]; } /** * Create an error response array * * @param string $message * @param array $data * @return array */ protected function errorResponse(string $message, array $data = []): array { return [ 'success' => false, 'message' => $message, 'data' => $data, ]; } /** * Log debug information * * @param string $message * @param array $context */ protected function debug(string $message, array $context = []): void { if (function_exists('ray')) { ray($message, $context)->blue(); } if (defined('ALEXR_WHATSAPP_DEBUG') && ALEXR_WHATSAPP_DEBUG) { error_log('[WhatsApp ' . $this->getProviderName() . '] ' . $message . ' ' . json_encode($context)); } } /** * Log error information * * @param string $message * @param array $context */ protected function logError(string $message, array $context = []): void { if (function_exists('ray')) { ray($message, $context)->red(); } error_log('[WhatsApp ' . $this->getProviderName() . ' Error] ' . $message . ' ' . json_encode($context)); } /** * Get configuration value * * @param string $key * @param mixed $default * @return mixed */ protected function getConfigValue(string $key, mixed $default = null): mixed { return $this->config[$key] ?? $default; } /** * Mark an inbound message as read (default no-op implementation) * * @param string $messageId * @return array */ public function markAsRead(string $messageId): array { return $this->successResponse(__eva('Mark as read not supported by this provider')); } }