Files
nomina_ventas/app/Services/TelegramBotService.php

337 lines
11 KiB
PHP
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services;
use App\Models\TelegramAccount;
use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class TelegramBotService
{
private ?string $botToken;
private ?string $webhookUrl;
public function __construct()
{
$this->botToken = config('services.telegram.bot_token');
$this->webhookUrl = rtrim(config('app.url'), '/') . '/telegram/webhook';
}
/**
* Procesar actualización recibida del webhook
*/
public function handleUpdate(array $update): array
{
if (!isset($update['message'])) {
return ['ok' => false, 'error' => 'No message found'];
}
$message = $update['message'];
$chatId = $message['chat']['id'];
$text = $message['text'] ?? '';
$from = $message['from'] ?? [];
Log::info('Telegram update received', [
'chat_id' => $chatId,
'text' => $text,
'from' => $from
]);
// Verificar si el usuario está verificado
$telegramAccount = TelegramAccount::where('chat_id', $chatId)->first();
if (!$telegramAccount || !$telegramAccount->is_verified) {
return $this->handleUnverifiedUser($chatId, $text);
}
// Procesar comandos del usuario verificado
return $this->handleCommand($telegramAccount->user, $text, $chatId);
}
/**
* Manejar usuario no verificado
*/
private function handleUnverifiedUser(string $chatId, string $text): array
{
// Si es un código de verificación (6 dígitos numéricos)
if (strlen($text) === 6 && is_numeric($text)) {
// Buscamos la cuenta que tiene este código de verificación y no está verificada
$telegramAccount = TelegramAccount::where('verification_code', $text)
->where('is_verified', false)
->first();
if ($telegramAccount) {
// Actualizar la cuenta con el chat_id del usuario que mandó el código
$telegramAccount->update([
'chat_id' => $chatId,
'is_verified' => true,
'verification_code' => null
]);
$user = $telegramAccount->user;
$this->sendMessage($chatId, "¡Hola {$user->name}! 👋\n\nVerificación exitosa. Tu cuenta de Telegram ha sido vinculada correctamente. Ahora puedes usar comandos como /resumen para ver tu estado.");
return ['ok' => true, 'verified' => true];
} else {
$this->sendMessage($chatId, "❌ El código $text es inválido o ya ha sido usado. Por favor, genera un código nuevo en tu panel de usuario.");
return ['ok' => true, 'verified' => false];
}
}
// Mensaje de bienvenida para usuarios no verificados
$this->sendMessage($chatId, "👋 ¡Hola! Soy el bot de Nómina Pegaso.\n\nPara usar este bot, primero debes vincular tu cuenta:\n\n1⃣ Ve a tu panel web\n2⃣ Sección Telegram -> Vincular\n3⃣ Envía aquí el código de 6 dígitos que veas allá.");
return ['ok' => true, 'verified' => false];
}
/**
* Manejar comandos de usuario verificado
*/
private function handleCommand(User $user, string $text, string $chatId): array
{
$command = strtolower(trim($text));
$commandParts = explode(' ', $command);
$mainCommand = $commandParts[0] ?? '';
switch ($mainCommand) {
case '/start':
$this->sendMessage($chatId, "¡Hola {$user->name}! Usa /help para ver los comandos disponibles.");
break;
case '/help':
$this->sendHelp($chatId);
break;
case '/mes':
$this->showCurrentMonth($user, $chatId);
break;
case '/ventas':
$this->showSales($user, $chatId);
break;
case '/gastos':
$this->showExpenses($user, $chatId);
break;
case '/resumen':
$this->showSummary($user, $chatId);
break;
default:
$this->sendMessage($chatId, "Comando no reconocido. Usa /help para ver los comandos disponibles.");
}
return ['ok' => true];
}
/**
* Enviar mensaje
*/
public function sendMessage(string $chatId, string $text): array
{
if (!$this->botToken) {
Log::warning('Telegram bot token not configured');
return ['ok' => false, 'error' => 'Bot token not configured'];
}
try {
$response = Http::post("https://api.telegram.org/bot{$this->botToken}/sendMessage", [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'Markdown'
]);
return $response->json();
} catch (\Exception $e) {
Log::error('Telegram send message error', ['error' => $e->getMessage()]);
return ['ok' => false, 'error' => $e->getMessage()];
}
}
/**
* Enviar mensaje de ayuda
*/
private function sendHelp(string $chatId): void
{
$text = "📋 *Comandos disponibles:*\n\n" .
"• /start - Iniciar bot\n" .
"• /help - Mostrar ayuda\n" .
"• /mes - Ver mes actual\n" .
"• /ventas - Ver ventas del mes\n" .
"• /gastos - Ver gastos del mes\n" .
"• /resumen - Resumen de comisiones\n";
$this->sendMessage($chatId, $text);
}
/**
* Mostrar mes actual
*/
private function showCurrentMonth(User $user, string $chatId): void
{
$month = $user->getCurrentMonth();
if (!$month) {
$this->sendMessage($chatId, "No tienes ningún mes abierto actualmente.");
return;
}
$statusText = match($month->status) {
'open' => '🟢 Abierto',
'closed' => '🟡 Cerrado',
'paid' => '✅ Pagado',
default => 'Desconocido'
};
$text = "📅 *Mes Actual*\n\n" .
"• *Nombre:* {$month->name} {$month->year}\n" .
"• *Estado:* {$statusText}";
$this->sendMessage($chatId, $text);
}
/**
* Mostrar ventas del mes
*/
private function showSales(User $user, string $chatId): void
{
$month = $user->getCurrentMonth();
if (!$month) {
$this->sendMessage($chatId, "No tienes ningún mes abierto actualmente.");
return;
}
$totalUserSales = $month->dailySales()->sum('user_sales');
$totalSystemSales = $month->dailySales()->sum('system_sales');
$diff = $totalUserSales - $totalSystemSales;
$text = "💰 *Ventas del Mes*\n\n" .
"• *Usuario:* $" . number_format($totalUserSales, 2) . "\n" .
"• *Sistema:* $" . number_format($totalSystemSales, 2) . "\n" .
"• *Diferencia:* $" . number_format($diff, 2);
$this->sendMessage($chatId, $text);
}
/**
* Mostrar gastos del mes
*/
private function showExpenses(User $user, string $chatId): void
{
$month = $user->getCurrentMonth();
if (!$month) {
$this->sendMessage($chatId, "No tienes ningún mes abierto actualmente.");
return;
}
$totalExpenses = $month->expenses()->sum('amount');
$expensesList = $month->expenses()->latest()->limit(5)->get();
$text = "📝 *Gastos del Mes*\n\n" .
"• *Total:* $" . number_format($totalExpenses, 2) . "\n\n";
if ($expensesList->count() > 0) {
$text .= "Últimos gastos:\n";
foreach ($expensesList as $expense) {
$text .= "{$expense->description}: \$" . number_format($expense->amount, 2) . "\n";
}
}
$this->sendMessage($chatId, $text);
}
/**
* Mostrar resumen de comisiones
*/
private function showSummary(User $user, string $chatId): void
{
$month = $user->getCurrentMonth();
if (!$month) {
$this->sendMessage($chatId, "No tienes ningún mes abierto actualmente.");
return;
}
$data = CommissionCalculator::calculateForMonth($user, $month);
$text = "💵 *Resumen de Comisiones*\n\n" .
"• *Mes:* {$data['month_name']}\n" .
"• *Ventas Sistema:* \$" . number_format($data['total_system_sales'], 2) . "\n" .
"• *Comisión ({$data['commission_percentage']}%):* \$" . number_format($data['commission_amount'], 2) . "\n" .
"• *Salario:* \$" . number_format($data['monthly_salary'], 2) . "\n" .
"• *Gastos:* \$" . number_format($data['total_expenses'], 2) . "\n" .
"• *Total a Recibir:* \$" . number_format($data['total_earning'], 2);
$this->sendMessage($chatId, $text);
}
/**
* Generar código de verificación
*/
public static function generateVerificationCode(): string
{
return str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
}
/**
* Configurar webhook
*/
public function setWebhook(): bool
{
if (!$this->botToken || !$this->webhookUrl) {
Log::warning('Cannot set webhook: missing configuration');
return false;
}
try {
$response = Http::post("https://api.telegram.org/bot{$this->botToken}/setWebhook", [
'url' => $this->webhookUrl
]);
return $response->json('ok', false);
} catch (\Exception $e) {
Log::error('Telegram set webhook error', ['error' => $e->getMessage()]);
return false;
}
}
/**
* Obtener información del webhook
*/
public function getWebhookInfo(): array
{
if (!$this->botToken) {
return ['ok' => false, 'error' => 'Bot token not configured'];
}
try {
$response = Http::get("https://api.telegram.org/bot{$this->botToken}/getWebhookInfo");
return $response->json();
} catch (\Exception $e) {
Log::error('Telegram get webhook info error', ['error' => $e->getMessage()]);
return ['ok' => false, 'error' => $e->getMessage()];
}
}
/**
* Borrar webhook
*/
public function deleteWebhook(): bool
{
if (!$this->botToken) {
return false;
}
try {
$response = Http::post("https://api.telegram.org/bot{$this->botToken}/deleteWebhook");
return $response->json('ok', false);
} catch (\Exception $e) {
Log::error('Telegram delete webhook error', ['error' => $e->getMessage()]);
return false;
}
}
}