From a0c3194e88b8be389d9c2fb9b9a8604106951c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20P=C3=A9rez?= Date: Thu, 28 May 2026 20:44:13 -0600 Subject: [PATCH] =?UTF-8?q?feat:=20WhatsApp=20=E2=80=94=20par=C3=A1metros?= =?UTF-8?q?=20nombrados=20en=20template,=20API=20v25.0=20e=20imagenUrl=20c?= =?UTF-8?q?on=20soporte=20de=20URL=20externas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Actualiza graph.facebook.com de v19.0 a v25.0 - Cambia parámetros posicionales a nombrados (parameter_name) en enviarTemplate para compatibilidad con plantillas avanzadas - enviarPromocion ahora pasa nombre fallback 'estudiante' y claves explícitas - imagenUrl() soporta imágenes con URL absoluta (http/https) además de rutas relativas de storage - Agrega Log::info del payload completo antes del envío para facilitar debugging Co-Authored-By: Claude Sonnet 4.6 --- .claude/settings.local.json | 9 +++++- app/Models/Promocion.php | 8 ++++- app/Services/WhatsAppService.php | 55 ++++++++++++++++++++++---------- 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index adf59c80..d09ec082 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -23,7 +23,14 @@ "Bash(Select-String -Pattern \"entrega|Entrega\" -Context 0,0)", "Bash(php -l app/Services/WhatsAppService.php)", "Bash(php -l app/Http/Controllers/WhatsAppWebhookController.php)", - "Bash(php -l app/Http/Controllers/WhatsAppAnalyticsController.php)" + "Bash(php -l app/Http/Controllers/WhatsAppAnalyticsController.php)", + "Bash(Test-Path *)", + "Bash(git -C \"C:/Proyectos/SistemaEducativoLaravel\" status)", + "Bash(git -C \"C:/Proyectos/SistemaEducativoLaravel\" diff)", + "Bash(git *)", + "Bash(dir C:\\\\Proyectos\\\\SistemaEducativoLaravel\\\\public *)", + "Bash(findstr \"APP_URL\" \"C:\\\\Proyectos\\\\SistemaEducativoLaravel\\\\.env.example\")", + "Bash(findstr \"APP_URL\" \"C:\\\\Proyectos\\\\SistemaEducativoLaravel\\\\.env\")" ] } } diff --git a/app/Models/Promocion.php b/app/Models/Promocion.php index e13b13ad..c56d2898 100644 --- a/app/Models/Promocion.php +++ b/app/Models/Promocion.php @@ -34,6 +34,12 @@ class Promocion extends Model public function imagenUrl(): ?string { - return $this->imagen ? asset('storage/' . $this->imagen) : null; + if (!$this->imagen) return null; + + if (str_starts_with($this->imagen, 'http')) { + return $this->imagen; + } + + return asset('storage/' . $this->imagen); } } diff --git a/app/Services/WhatsAppService.php b/app/Services/WhatsAppService.php index 548211d5..4172d450 100644 --- a/app/Services/WhatsAppService.php +++ b/app/Services/WhatsAppService.php @@ -28,7 +28,7 @@ class WhatsAppService $this->token = $token; $this->phoneId = $phoneId; - $this->apiUrl = "https://graph.facebook.com/v19.0/{$this->phoneId}/messages"; + $this->apiUrl = "https://graph.facebook.com/v25.0/{$this->phoneId}/messages"; } public function enviarTemplate(string $telefono, string $templateName, array $parametros = [], ?string $imagenUrl = null): ?string @@ -48,11 +48,30 @@ class WhatsAppService } if (!empty($parametros)) { - $components[] = [ - 'type' => 'body', - 'parameters' => array_map(fn($p) => ['type' => 'text', 'text' => $p], $parametros), - ]; - } + $components[] = [ + 'type' => 'body', + 'parameters' => array_map(fn($nombre, $valor) => [ + 'type' => 'text', + 'text' => (string) $valor, + 'parameter_name' => $nombre, + ], array_keys($parametros), array_values($parametros)), + ]; +} + +Log::info('WhatsApp payload', [ + 'url' => $this->apiUrl, + 'body' => [ + 'messaging_product' => 'whatsapp', + 'to' => $this->normalizarTelefono($telefono), + 'type' => 'template', + 'template' => [ + 'name' => $templateName, + 'language' => ['code' => 'es_MX'], + 'components' => $components, + ], + ] +]); + $response = Http::withToken($this->token)->post($this->apiUrl, [ 'messaging_product' => 'whatsapp', @@ -66,7 +85,7 @@ class WhatsAppService ]); if ($response->failed()) { - Log::error('WhatsApp template error', ['telefono' => $telefono, 'response' => $response->json()]); + Log::error('WhatsApp template error', ['telefono' => $telefono, 'response' => $response->json(), 'body' => $response->body()]); return null; } @@ -111,16 +130,18 @@ public function enviarPromocion(string $telefono, Promocion $promocion, string $ $codigo = 'PROMO-' . strtoupper(substr(md5($promocion->id . $telefono), 0, 6)); $mensajeId = $this->enviarTemplate( - $telefono, - 'promocion_laravel', - [ - $nombre, - $promocion->fecha_inicio->locale('es')->isoFormat('D [de] MMMM'), - $promocion->fecha_fin->locale('es')->isoFormat('D [de] MMMM'), - $codigo, - ], - $promocion->imagenUrl() - ); + $telefono, + 'promocion_laravel', + [ + 'nombre' => $nombre ?: 'estudiante', + 'fecha_inicio' => $promocion->fecha_inicio->locale('es')->isoFormat('D [de] MMMM'), + 'fecha_fin' => $promocion->fecha_fin->locale('es')->isoFormat('D [de] MMMM'), + 'codigo' => $codigo, + ], + $promocion->imagenUrl() +); + + if (!$mensajeId) { throw new \RuntimeException('No se pudo enviar la plantilla');