pdv.backend/app/Services/WhatsappService.php

200 lines
6.1 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
/**
* Servicio para envío de mensajes de WhatsApp
*/
class WhatsAppService
{
protected string $apiUrl;
protected int $orgId;
protected string $token;
public function __construct()
{
$this->apiUrl = config('services.whatsapp.api_url', 'https://whatsapp.golsystems.mx/api/send-whatsapp');
$this->orgId = config('services.whatsapp.org_id', 1);
$this->token = config('services.whatsapp.token');
if (!$this->token) {
throw new \Exception('El token de WhatsApp no está configurado. Agrega WHATSAPP_TOKEN en tu archivo .env');
}
}
/**
* Enviar documento por WhatsApp
*/
public function sendDocument(
string $phoneNumber,
string $documentUrl,
string $caption,
string $filename,
string $userEmail,
string $ticket,
string $customerName
): array {
try {
// Construir el mensaje de WhatsApp
$whatsappMessage = json_encode([
'messaging_product' => 'whatsapp',
'recipient_type' => 'individual',
'to' => $this->cleanPhoneNumber($phoneNumber),
'type' => 'document',
'document' => [
'link' => $documentUrl,
'caption' => $caption,
'filename' => $filename,
],
]);
// Preparar payload completo
$payload = [
'message' => $whatsappMessage,
'email' => $userEmail,
'org_id' => $this->orgId,
'ticket' => $ticket,
'customer' => $customerName,
];
// Enviar petición HTTP con token Bearer
$response = Http::timeout(30)
->withHeaders([
'Content-Type' => 'application/json',
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $this->token,
])
->post($this->apiUrl, $payload);
// Registrar en logs
Log::channel('daily')->info('WhatsApp message sent', [
'phone' => $phoneNumber,
'ticket' => $ticket,
'customer' => $customerName,
'status_code' => $response->status(),
]);
if ($response->successful()) {
return [
'success' => true,
'message' => 'Mensaje enviado correctamente',
'data' => $response->json(),
];
}
// Log detallado del error
Log::channel('daily')->error('WhatsApp API error', [
'phone' => $phoneNumber,
'status_code' => $response->status(),
'error_body' => $response->body(),
]);
return [
'success' => false,
'message' => 'Error al enviar el mensaje',
'error' => $response->body(),
'status_code' => $response->status(),
];
} catch (\Exception $e) {
Log::channel('daily')->error('WhatsApp sending failed', [
'phone' => $phoneNumber,
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
return [
'success' => false,
'message' => 'Error al conectar con el servicio de WhatsApp',
'error' => $e->getMessage(),
];
}
}
/**
* Enviar factura por WhatsApp
*/
public function sendInvoice(
string $phoneNumber,
string $pdfUrl,
?string $xmlUrl,
string $invoiceNumber,
string $customerName
): array {
$userEmail = auth()->user()->email ?? config('mail.from.address');
// Enviar PDF
$pdfResult = $this->sendDocument(
phoneNumber: $phoneNumber,
documentUrl: $pdfUrl,
caption: "Factura {$invoiceNumber} - {$customerName}",
filename: "Factura_{$invoiceNumber}.pdf",
userEmail: $userEmail,
ticket: $invoiceNumber,
customerName: $customerName
);
// Si hay XML y el PDF se envió correctamente, enviarlo también
if ($xmlUrl && $pdfResult['success']) {
$xmlResult = $this->sendDocument(
phoneNumber: $phoneNumber,
documentUrl: $xmlUrl,
caption: "XML - Factura {$invoiceNumber}",
filename: "Factura_{$invoiceNumber}.xml",
userEmail: $userEmail,
ticket: "{$invoiceNumber}_XML",
customerName: $customerName
);
return [
'success' => $pdfResult['success'] && $xmlResult['success'],
'pdf' => $pdfResult,
'xml' => $xmlResult,
];
}
return $pdfResult;
}
/**
* Enviar ticket de venta por WhatsApp
*/
public function sendSaleTicket(
string $phoneNumber,
string $ticketUrl,
string $saleNumber,
string $customerName
): array {
$userEmail = auth()->user()->email ?? config('mail.from.address');
return $this->sendDocument(
phoneNumber: $phoneNumber,
documentUrl: $ticketUrl,
caption: "Ticket de venta {$saleNumber} - {$customerName}. Gracias por su compra.",
filename: "Ticket_{$saleNumber}.pdf",
userEmail: $userEmail,
ticket: $saleNumber,
customerName: $customerName
);
}
/**
* Limpiar número de teléfono
*/
protected function cleanPhoneNumber(string $phone): string
{
// Eliminar todo excepto números
$cleaned = preg_replace('/[^0-9]/', '', $phone);
// Asegurar que tenga código de país (52 para México)
if (strlen($cleaned) === 10) {
$cleaned = '52' . $cleaned;
}
return $cleaned;
}
}