0% acharam este documento útil (0 voto)
7 visualizações35 páginas

Gerenciamento de Bots com Flask e Telegram

Enviado por

BRUNO PLAY EDITS
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato TXT, PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
7 visualizações35 páginas

Gerenciamento de Bots com Flask e Telegram

Enviado por

BRUNO PLAY EDITS
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato TXT, PDF, TXT ou leia on-line no Scribd

import logging

import json
import qrcode
import io
import os
import time
import threading
import traceback
from datetime import datetime, timedelta
from flask import Flask, jsonify, request, session, redirect
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from [Link] import Application, CommandHandler, CallbackQueryHandler,
ContextTypes
import requests

# ==================== CONFIGURAÇÃO FLASK ====================


app = Flask(__name__)
app.secret_key = 'hsahjdjasdjasjdajs12ui23' # Chave para sessões

# ==================== VARIÁVEIS GLOBAIS ====================


logger = None
data_manager = None
bot_manager = None

# ==================== GERENCIADOR DE DADOS ====================


class DataManager:
"""Gerencia salvamento e carregamento de dados do dashboard"""

def __init__(self, username='anorm4l'):


[Link] = username
self.data_file = f'users/{username}/dashboard_data.json'
self.load_data()

def load_data(self):
"""Carrega dados salvos com recuperação automática"""
try:
if [Link](self.data_file):
with open(self.data_file, 'r', encoding='utf-8') as f:
self.stats_data = [Link](f)
else:
print(f"⚠️ Arquivo {self.data_file} não encontrado, criando
novo...")
self.stats_data = {
"total_approved": 0,
"total_revenue": 0.0,
"total_pending": 0,
"tax_rate": 0.50, # Taxa por venda (R$ 0,50)
"total_tax": 0.0, # Taxa total calculada
"last_update": [Link]().isoformat()
}

except Exception as e:
print(f"❌ Erro ao carregar dados: {e}")
self.stats_data = {"total_approved": 0, "total_revenue": 0.0,
"total_pending": 0}

def save_stats(self, stats):


"""Salva estatísticas"""
try:
# Atualizar dados
current_approved = self.stats_data.get("total_approved", 0)
current_revenue = self.stats_data.get("total_revenue", 0.0)

new_approved = [Link]("approved", 0)
new_revenue = [Link]("revenue", 0.0)
new_pending = [Link]("pending", 0)

# Calcular taxa total automaticamente


tax_rate = self.stats_data.get("tax_rate", 0.50)
total_approved = current_approved + new_approved
total_tax = total_approved * tax_rate

self.stats_data.update({
"total_approved": total_approved,
"total_revenue": current_revenue + new_revenue,
"total_pending": self.stats_data.get("total_pending", 0) +
new_pending,
"total_tax": total_tax,
"last_update": [Link]().isoformat()
})

# Salvar dados principais


with open(self.data_file, 'w', encoding='utf-8') as f:
[Link](self.stats_data, f, indent=2, ensure_ascii=False)

print(f"✅ Dados salvos com sucesso: {new_approved} aprovados, R$


{new_revenue:.2f} receita")

except Exception as e:
print(f"❌ Erro ao salvar estatísticas: {e}")

def get_stats(self):
"""Retorna estatísticas salvas"""
return self.stats_data

# ==================== GERENCIADOR DE BOTS ====================


class BotManager:
"""Gerencia múltiplos bots simultaneamente"""

def __init__(self, username=None):


[Link] = {}
[Link] = username
self.bot_configs = self.load_bot_configs()
[Link] = setup_logging()

def load_bot_configs(self):
"""Carrega configurações de todos os bots do usuário específico"""
try:
if [Link]:
# Carregar configurações específicas do usuário
bots_file = f'users/{[Link]}/bots_config.json'
if [Link](bots_file):
with open(bots_file, 'r', encoding='utf-8') as f:
configs = [Link](f)

return configs
else:
print(f"⚠️ Arquivo de configuração de bots não encontrado para
usuário {[Link]}")

# Fallback para configuração global


if [Link]('bots_config.json'):
with open('bots_config.json', 'r', encoding='utf-8') as f:
return [Link](f)
else:
# Configuração padrão com um bot
default_config = {
"bots": {
"bot_1": {
"name": "Bot Principal",
"enabled": True,
"config_file": "[Link]",
"products_file": "[Link]",
"telegram_token": "SEU_TOKEN_AQUI",
"pushinpay_token": "SEU_TOKEN_PUSHINPAY_AQUI"
}
}
}
self.save_bot_configs(default_config)
return default_config
except Exception as e:
print(f"❌ Erro ao carregar configurações dos bots: {e}")
return {"bots": {}}

def save_bot_configs(self, configs):


"""Salva configurações dos bots no arquivo específico do usuário"""
try:
if [Link]:
# Salvar no arquivo específico do usuário
bots_file = f'users/{[Link]}/bots_config.json'
# Criar diretório se não existir
[Link]([Link](bots_file), exist_ok=True)
with open(bots_file, 'w', encoding='utf-8') as f:
[Link](configs, f, indent=2, ensure_ascii=False)
print(f"✅ Configurações de bots salvas para usuário
{[Link]}")
else:
# Fallback para arquivo global
with open('bots_config.json', 'w', encoding='utf-8') as f:
[Link](configs, f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"❌ Erro ao salvar configurações dos bots: {e}")

def add_bot(self, bot_id, bot_config):


"""Adiciona um novo bot"""
try:
self.bot_configs["bots"][bot_id] = bot_config
self.save_bot_configs(self.bot_configs)

# Iniciar o novo bot


self.start_bot(bot_id)

print(f"✅ Bot {bot_id} adicionado e iniciado")


return True
except Exception as e:
print(f"❌ Erro ao adicionar bot {bot_id}: {e}")
return False

def remove_bot(self, bot_id):


"""Remove um bot"""
try:
if bot_id in [Link]:
# Parar o bot
self.stop_bot(bot_id)

# Remover da configuração
if bot_id in self.bot_configs["bots"]:
del self.bot_configs["bots"][bot_id]
self.save_bot_configs(self.bot_configs)

print(f"✅ Bot {bot_id} removido")


return True
except Exception as e:
print(f"❌ Erro ao remover bot {bot_id}: {e}")
return False

def start_bot(self, bot_id, username=None):


"""Inicia um bot específico"""
try:
if bot_id in [Link]:
print(f"⚠️ Bot {bot_id} já está rodando")
return False

bot_config = self.bot_configs["bots"].get(bot_id)
if not bot_config:
print(f"❌ Bot {bot_id} não encontrado na configuração")
return False

if not bot_config.get("enabled", False):


print(f"⚠️ Bot {bot_id} não está habilitado")
return False

# Verificar se já existe uma instância deste bot rodando em outro


processo
telegram_token = bot_config.get('telegram_token')
if telegram_token:
# Verificar se o token já está sendo usado globalmente
global token_manager
if not token_manager.is_token_available(telegram_token):
print(f"❌ Token do Telegram já está sendo usado globalmente")
return False

# Verificar se o token já está sendo usado por outro bot deste


usuário
for existing_bot_id, existing_bot in [Link]():
if (existing_bot_id != bot_id and
hasattr(existing_bot, 'bot_config') and
existing_bot.bot_config.get('telegram_token') ==
telegram_token):
print(f"❌ Token do Telegram já está sendo usado pelo bot
{existing_bot_id}")
return False
# Criar e iniciar o bot
bot = TelegramSalesBot(bot_id, bot_config, username)
[Link][bot_id] = bot

# Iniciar em thread separada


def run_bot():
import asyncio
try:
# Criar novo loop de eventos para esta thread
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

# Executar o bot
[Link]()
except Exception as e:
print(f"❌ Erro no bot {bot_id}: {e}")
import traceback
traceback.print_exc()
finally:
# Limpar o loop
try:
[Link]()
except:
pass

bot_thread = [Link](target=run_bot, daemon=True)


bot_thread.start()

return True

except Exception as e:
print(f"❌ Erro ao iniciar bot {bot_id}: {e}")
return False

def stop_bot(self, bot_id):


"""Para um bot específico"""
try:
if bot_id in [Link]:
bot = [Link][bot_id]

# Remover token do gerenciador global


if hasattr(bot, 'bot_config') and
bot.bot_config.get('telegram_token'):
global token_manager

token_manager.unregister_token(bot.bot_config['telegram_token'])
print(f"🔓 Token removido do gerenciador global")

# Aqui você pode implementar a lógica para parar o bot


del [Link][bot_id]
print(f"✅ Bot {bot_id} parado")
return True
return False
except Exception as e:
print(f"❌ Erro ao parar bot {bot_id}: {e}")
return False

def start_all_bots(self):
"""Inicia todos os bots habilitados"""
started_count = 0

# Primeiro, parar todos os bots existentes para evitar conflitos


for bot_id in list([Link]()):
self.stop_bot(bot_id)

# Aguardar um pouco para os bots pararem completamente


import time
[Link](2)

# Iniciar apenas os bots que estão habilitados


for bot_id, bot_config in self.bot_configs["bots"].items():
if bot_config.get("enabled", False):
if self.start_bot(bot_id, [Link]):
started_count += 1

return started_count

def get_bot_status(self, bot_id):


"""Retorna status de um bot específico"""
if bot_id in [Link]:
return {
"status": "running",
"uptime": "ativo",
"messages_sent": 0,
"payments_processed": 0
}
else:
return {
"status": "stopped",
"uptime": "inativo",
"messages_sent": 0,
"payments_processed": 0
}

def get_all_bots_status(self):
"""Retorna status de todos os bots"""
status = {}
for bot_id, bot_config in self.bot_configs["bots"].items():
if bot_id in [Link]:
# Bot está rodando
status[bot_id] = {
"status": "running",
"uptime": "ativo",
"enabled": bot_config.get("enabled", False),
"name": bot_config.get("name", bot_id),
"messages_sent": 0,
"payments_processed": 0
}
else:
# Bot não está rodando
status[bot_id] = {
"status": "stopped",
"uptime": "inativo",
"enabled": bot_config.get("enabled", False),
"name": bot_config.get("name", bot_id),
"messages_sent": 0,
"payments_processed": 0
}
return status

def get_bot_config(self, bot_id):


"""Retorna configuração de um bot específico"""
return self.bot_configs["bots"].get(bot_id, {})

def update_bot_config(self, bot_id, new_config):


"""Atualiza configuração de um bot"""
try:
if bot_id in self.bot_configs["bots"]:
self.bot_configs["bots"][bot_id].update(new_config)
self.save_bot_configs(self.bot_configs)

# Reiniciar o bot se estiver rodando


if bot_id in [Link]:
self.stop_bot(bot_id)
self.start_bot(bot_id)

print(f"✅ Configuração do bot {bot_id} atualizada")


return True
return False
except Exception as e:
print(f"❌ Erro ao atualizar configuração do bot {bot_id}: {e}")
return False

# ==================== CARREGAMENTO DE CONFIGURAÇÕES ====================


class ConfigManager:
"""Gerenciador de configurações do bot"""

def __init__(self, username=None):


[Link] = username
[Link] = self.load_config()
[Link] = self.load_products()

def load_config(self):
"""Carrega configurações do arquivo [Link]"""
try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link](f)
except FileNotFoundError:
print("❌ Arquivo [Link] não encontrado!")
return {}
except [Link]:
print("❌ Erro ao decodificar [Link]!")
return {}

def load_products(self):
"""Carrega produtos do arquivo [Link] específico do usuário"""
try:
if [Link]:
# Carregar produtos específicos do usuário
products_file = f'users/{[Link]}/[Link]'
if [Link](products_file):
with open(products_file, 'r', encoding='utf-8') as f:
return [Link](f)
print(f"✅ Produtos carregados do usuário {[Link]}")
else:
print(f"⚠️ Arquivo de produtos do usuário {[Link]} não
encontrado, usando produtos globais")

# Fallback para produtos globais


with open('[Link]', 'r', encoding='utf-8') as f:
return [Link](f)
except FileNotFoundError:
print("❌ Arquivo [Link] não encontrado!")
return {"products": []}
except [Link]:
print("❌ Erro ao decodificar [Link]!")
return {"products": []}

def get_active_products(self):
"""Retorna apenas produtos ativos"""
return [p for p in [Link]("products", []) if [Link]("active",
True)]

def get_product_by_id(self, product_id):


"""Busca produto pelo ID"""
for product in [Link]("products", []):
if [Link]("id") == product_id:
return product
return None

def reload_configs(self):
"""Recarrega todas as configurações"""
try:
[Link] = self.load_config()
[Link] = self.load_products()

# Log das informações recarregadas


products_count = len([Link]("products", []))
active_products = len([p for p in [Link]("products", []) if
[Link]("active", True)])

print(f"🔄 Configurações recarregadas para usuário {[Link]}:")


print(f" - Total de produtos: {products_count}")
print(f" - Produtos ativos: {active_products}")

except Exception as e:
print(f"❌ Erro ao recarregar configurações: {e}")

def get_messages(self):
"""Retorna as mensagens do [Link]"""
return [Link]("bot", {}).get("messages", {})

# ==================== CONFIGURAÇÃO DE LOG ====================


def setup_logging():
"""Configura o sistema de logging"""
[Link](
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=[Link]
)

return [Link](__name__)

# ==================== GERENCIADOR DE PAGAMENTOS ====================


class PaymentManager:
"""Gerencia pagamentos pendentes e aprovados"""
def __init__(self):
self.pending_payments = {}
self.approved_payments = set()
[Link] = [Link](self.__class__.__name__)

def add_pending_payment(self, payment_id, payment_data):


"""Adiciona pagamento pendente"""
self.pending_payments[payment_id] = payment_data
[Link](f"Pagamento pendente adicionado: {payment_id}")

def remove_pending_payment(self, payment_id):


"""Remove pagamento pendente"""
if payment_id in self.pending_payments:
del self.pending_payments[payment_id]
[Link](f"Pagamento pendente removido: {payment_id}")

def approve_payment(self, payment_id):


"""Marca pagamento como aprovado"""
self.approved_payments.add(payment_id)
self.remove_pending_payment(payment_id)
[Link](f"Pagamento aprovado: {payment_id}")

def is_payment_approved(self, payment_id):


"""Verifica se pagamento foi aprovado"""
return payment_id in self.approved_payments

def get_pending_payment(self, payment_id):


"""Retorna dados do pagamento pendente"""
return self.pending_payments.get(payment_id)

# ==================== FUNÇÕES DE AUTENTICAÇÃO ====================


def load_users():
"""Carrega usuários do arquivo [Link]"""
try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link](f)
except Exception as e:
print(f"❌ Erro ao carregar usuários: {e}")
return {"users": {}}

def authenticate_user(username, password):


"""Autentica usuário"""
users = load_users()
if username in users['users']:
user = users['users'][username]
if user['password'] == password and user['active']:
return user
return None

def require_auth(f):
"""Decorator para requerer autenticação"""
def decorated_function(*args, **kwargs):
if 'username' not in session:
return jsonify({"error": "Usuário não autenticado"}), 401
return f(*args, **kwargs)
decorated_function.__name__ = f.__name__
return decorated_function

# ==================== ROTAS FLASK ====================


@[Link]('/')
def index():
"""Página inicial - redirecionamento automático"""
if 'username' in session:
# Usuário logado, redirecionar para dashboard
return redirect('/[Link]')
else:
# Usuário não logado, redirecionar para login
return redirect('/[Link]')

@[Link]('/[Link]')
def login_page():
"""Página de login - redireciona se já logado"""
if 'username' in session:
# Usuário já logado, redirecionar para dashboard
return redirect('/[Link]')

try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link]()
except FileNotFoundError:
return "Página de login não encontrada", 404

@[Link]('/[Link]')
def dashboard_page():
"""Página do dashboard - requer autenticação"""
if 'username' not in session:
# Usuário não logado, redirecionar para login
return redirect('/[Link]')

try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link]()
except FileNotFoundError:
return "Dashboard não encontrado", 404

@[Link]('/api/login', methods=['POST'])
def api_login():
"""API para autenticação de usuário"""
try:
data = request.get_json()
username = [Link]('username')
password = [Link]('password')

if not username or not password:


return jsonify({"success": False, "message": "Usuário e senha são
obrigatórios"}), 400

user = authenticate_user(username, password)


if user:
# Criar sessão
session['username'] = username
session['display_name'] = user['display_name']
print(f"✅ Usuário {username} logado com sucesso")
return jsonify({
"success": True,
"message": "Login realizado com sucesso",
"user": {
"username": user['username'],
"display_name": user['display_name']
}
})
else:
return jsonify({"success": False, "message": "Usuário ou senha
incorretos"}), 401

except Exception as e:
print(f"❌ Erro no login: {e}")
return jsonify({"success": False, "message": "Erro interno do servidor"}),
500

@[Link]('/api/logout', methods=['POST'])
def api_logout():
"""API para logout do usuário"""
try:
[Link]()
return jsonify({"success": True, "message": "Logout realizado com
sucesso"})
except Exception as e:
print(f"❌ Erro no logout: {e}")
return jsonify({"success": False, "message": "Erro interno do servidor"}),
500

@[Link]('/api/dashboard')
@require_auth
def api_dashboard():
"""API otimizada para dados do dashboard"""
try:
username = session['username']

# Criar DataManager específico para o usuário


user_data_manager = DataManager(username)

# Obter dados salvos (histórico acumulado)


saved_data = user_data_manager.get_stats()

# Calcular dados atuais dos bots (apenas para referência)


current_pending = 0
current_approved = 0

# Criar BotManager específico para o usuário


user_bot_manager = BotManager(username)

# Iniciar automaticamente todos os bots habilitados apenas uma vez


if not user_bot_manager.bots and not
token_manager.has_user_started_bots(username):
user_bot_manager.start_all_bots()
elif user_bot_manager.bots:
print(f"✅ Bots já estão rodando para usuário {username}")
else:
print(f"✅ Bots já foram iniciados para usuário {username} em outra
sessão")
if user_bot_manager.bots:
for bot_id, bot in user_bot_manager.[Link]():
if hasattr(bot, 'payment_manager'):
current_pending += len(bot.payment_manager.pending_payments)
current_approved += len(bot.payment_manager.approved_payments)

# Usar dados salvos como fonte principal


response_data = {
"approved": saved_data.get("total_approved", 0), # Total histórico de
pagamentos aprovados
"pending": current_pending, # Pagamentos
pendentes atuais
"revenue": saved_data.get("total_revenue", 0.0), # Receita total
acumulada
"total_approved": saved_data.get("total_approved", 0), # Total de
vendas aprovadas
"total_revenue": saved_data.get("total_revenue", 0.0), # Receita total
acumulada
"total_tax": saved_data.get("total_tax", 0.0), # Taxa total
acumulada
"tax_rate": saved_data.get("tax_rate", 0.50) # Taxa por venda
}

return jsonify(response_data)

except Exception as e:
print(f"Erro na API dashboard: {e}")
return jsonify({"error": str(e)}), 500

@[Link]('/api/config/save', methods=['POST'])
@require_auth
def api_save_global_config():
"""API para salvar configurações globais"""
try:
data = request.get_json()
username = session['username']

# Salvar configurações globais


config_file = f'users/{username}/global_config.json'

# Criar diretório se não existir


[Link]([Link](config_file), exist_ok=True)

with open(config_file, 'w', encoding='utf-8') as f:


[Link](data, f, indent=2, ensure_ascii=False)

print(f"✅ Configurações globais salvas para {username}")


return jsonify({"success": True, "message": "Configurações salvas com
sucesso"})

except Exception as e:
print(f"❌ Erro ao salvar configurações globais: {e}")
return jsonify({"error": "Erro interno do servidor"}), 500
@[Link]('/api/bots/save', methods=['POST'])
@require_auth
def api_save_bots_config():
"""API para salvar configurações de todos os bots"""
try:
data = request.get_json()
username = session['username']

# Salvar configurações de bots


bots_file = f'users/{username}/bots_config.json'

# Criar diretório se não existir


[Link]([Link](bots_file), exist_ok=True)

with open(bots_file, 'w', encoding='utf-8') as f:


[Link](data, f, indent=2, ensure_ascii=False)

print(f"✅ Configurações de bots salvas para {username}")


return jsonify({"success": True, "message": "Configurações de bots salvas
com sucesso"})

except Exception as e:
print(f"❌ Erro ao salvar configurações de bots: {e}")
return jsonify({"error": "Erro interno do servidor"}), 500

@[Link]('/api/products')
@require_auth
def api_products():
"""API para obter produtos"""
try:
username = session['username']
products_file = f'users/{username}/[Link]'

with open(products_file, 'r', encoding='utf-8') as f:


products = [Link](f)
return jsonify(products)
except Exception as e:
if logger:
[Link](f"Erro ao carregar produtos: {e}")
else:
print(f"Erro ao carregar produtos: {e}")
return jsonify({"error": "Erro ao carregar produtos"}), 500

@[Link]('/api/products/<product_id>', methods=['PUT'])
@require_auth
def api_update_product(product_id):
"""API para atualizar um produto específico"""
try:
data = request.get_json()
username = session['username']

# Carregar produtos do usuário específico


products_file = f'users/{username}/[Link]'

if not [Link](products_file):
return jsonify({"error": "Arquivo de produtos não encontrado"}), 404

with open(products_file, 'r', encoding='utf-8') as f:


products = [Link](f)
# Encontrar e atualizar o produto
product_found = False
for product in products['products']:
if product['id'] == product_id:
# Atualizar campos do produto
[Link](data)
product_found = True
break

if not product_found:
return jsonify({"error": "Produto não encontrado"}), 404

# Salvar produtos atualizados


with open(products_file, 'w', encoding='utf-8') as f:
[Link](products, f, indent=2, ensure_ascii=False)

if logger:
[Link](f"Produto {product_id} atualizado com sucesso")
else:
print(f"✅ Produto {product_id} atualizado com sucesso")

return jsonify({"success": True, "message": "Produto atualizado com


sucesso"})

except Exception as e:
if logger:
[Link](f"Erro ao atualizar produto {product_id}: {e}")
else:
print(f"❌ Erro ao atualizar produto {product_id}: {e}")

return jsonify({"error": "Erro ao atualizar produto"}), 500

@[Link]('/api/products/<product_id>/status', methods=['PUT'])
@require_auth
def api_toggle_product_status(product_id):
"""API para alterar status do produto (ativo/inativo)"""
try:
data = request.get_json()
new_status = [Link]('active', False)
username = session['username']

# Carregar produtos do usuário específico


# Carregar produtos do usuário específico
products_file = f'users/{username}/[Link]'

if not [Link](products_file):
return jsonify({"error": "Arquivo de produtos não encontrado"}), 404

with open(products_file, 'r', encoding='utf-8') as f:


products = [Link](f)

# Encontrar e atualizar status do produto


product_found = False
for product in products['products']:
if product['id'] == product_id:
product['active'] = new_status
product_found = True
break
if not product_found:
return jsonify({"error": "Produto não encontrado"}), 404

# Salvar produtos atualizados


with open(products_file, 'w', encoding='utf-8') as f:
[Link](products, f, indent=2, ensure_ascii=False)

if logger:
[Link](f"Status do produto {product_id} alterado para:
{new_status}")
else:
print(f"✅ Status do produto {product_id} alterado para: {new_status}")

return jsonify({"success": True, "active": new_status})

except Exception as e:
if logger:
[Link](f"Erro ao alterar status do produto {product_id}: {e}")
else:
print(f"❌ Erro ao alterar status do produto {product_id}: {e}")

return jsonify({"error": "Erro ao alterar status"}), 500

@[Link]('/api/products/save', methods=['POST'])
@require_auth
def api_save_products():
"""API para salvar todos os produtos"""
try:
data = request.get_json()
username = session['username']

print(f"💾 Salvando produtos para usuário {username}...")


print(f"📦 Produtos recebidos: {len([Link]('products', []))} produtos")

# Salvar produtos no arquivo específico do usuário


products_file = f'users/{username}/[Link]'

# Criar diretório se não existir


[Link]([Link](products_file), exist_ok=True)

with open(products_file, 'w', encoding='utf-8') as f:


[Link](data, f, indent=2, ensure_ascii=False)

print(f"✅ Produtos salvos em {products_file}")


print(f"📊 Conteúdo salvo: {data}")

return jsonify({
"success": True,
"message": f"Produtos salvos com sucesso para {username}",
"products_count": len([Link]('products', [])),
"file_path": products_file
})

except Exception as e:
error_msg = f"Erro ao salvar produtos: {e}"
print(f"❌ {error_msg}")
return jsonify({"error": error_msg}), 500
@[Link]('/api/bot/update-products', methods=['POST'])
def api_update_bot_products():
"""API para atualizar produtos no bot"""
try:
data = request.get_json()

print("🔄 Atualizando produtos nos bots...")


print(f"📦 Produtos recebidos: {len([Link]('products', []))} produtos")

# Recarregar configurações dos bots do usuário


username = [Link]('username')
if username:
user_bot_manager = BotManager(username)
print("🔄 Recarregando configurações dos bots...")

# Atualizar produtos em todos os bots ativos


updated_bots = 0
for bot_id in user_bot_manager.bots:
try:
bot = user_bot_manager.bots[bot_id]

# Forçar recarga completa das configurações


bot.config_manager.reload_configs()

# Limpar cache interno de produtos se existir


if hasattr(bot, 'products_cache'):
delattr(bot, 'products_cache')

# Verificar se os produtos foram atualizados


current_products = bot.config_manager.get_active_products()
print(f"✅ Bot {bot_id} atualizado - {len(current_products)}
produtos ativos")
updated_bots += 1

except Exception as e:
print(f"⚠️ Erro ao atualizar bot {bot_id}: {e}")
else:
print("⚠️ Usuário não autenticado")

if logger:
[Link]("Produtos dos bots atualizados")
else:
print(f"✅ {updated_bots} bots atualizados com novos produtos!")

return jsonify({
"success": True,
"message": f"{updated_bots} bots atualizados com novos produtos",
"bots_updated": updated_bots
})

except Exception as e:
error_msg = f"Erro ao atualizar bots: {e}"
if logger:
[Link](error_msg)
else:
print(f"❌ {error_msg}")

return jsonify({"error": error_msg}), 500


@[Link]('/api/bot/force-reload', methods=['POST'])
@require_auth
def api_force_reload_bots():
"""API para forçar recarga completa de todos os bots do usuário"""
try:
username = session['username']
print(f"🔄 FORÇANDO recarga completa dos bots do usuário {username}...")

user_bot_manager = BotManager(username)

# Parar todos os bots


for bot_id in list(user_bot_manager.[Link]()):
try:
print(f"🛑 Parando bot {bot_id}...")
user_bot_manager.stop_bot(bot_id)
except Exception as e:
print(f"⚠️ Erro ao parar bot {bot_id}: {e}")

# Aguardar um pouco
import time
[Link](2)

# Reiniciar todos os bots


for bot_id in user_bot_manager.bot_configs:
try:
print(f"🚀 Reiniciando bot {bot_id}...")
user_bot_manager.start_bot(bot_id, username)
except Exception as e:
print(f"⚠️ Erro ao reiniciar bot {bot_id}: {e}")

print("✅ Recarga completa forçada em todos os bots!")


return jsonify({
"success": True,
"message": "Recarga completa forçada em todos os bots",
"bots_reloaded": len(user_bot_manager.bot_configs)
})

except Exception as e:
error_msg = f"Erro ao forçar recarga: {e}"
print(f"❌ {error_msg}")
return jsonify({"error": error_msg}), 500

@[Link]('/api/bots')
@require_auth
def api_bots():
"""API para obter lista de bots do usuário"""
try:
username = session['username']
user_bot_manager = BotManager(username)

# Iniciar automaticamente bots se necessário (apenas uma vez)


if not user_bot_manager.bots and not
token_manager.has_user_started_bots(username):
user_bot_manager.start_all_bots()
elif user_bot_manager.bots:
print(f"✅ Bots já estão rodando para usuário {username}")
else:
print(f"✅ Bots já foram iniciados para usuário {username} em outra
sessão")
bots_data = {
"bots": user_bot_manager.get_all_bots_status(),
"configs": user_bot_manager.bot_configs
}
return jsonify(bots_data)
except Exception as e:
print(f"Erro ao obter bots: {e}")
return jsonify({"error": "Erro ao obter bots"}), 500

@[Link]('/api/bots', methods=['POST'])
@require_auth
def api_add_bot():
"""API para adicionar novo bot"""
try:
data = request.get_json()
bot_id = [Link]('bot_id')
bot_config = [Link]('config')

if not bot_id or not bot_config:


return jsonify({"error": "bot_id e config são obrigatórios"}), 400

username = session['username']
user_bot_manager = BotManager(username)

if user_bot_manager.add_bot(bot_id, bot_config):
return jsonify({"success": True, "message": f"Bot {bot_id} adicionado
com sucesso"})
else:
return jsonify({"error": f"Erro ao adicionar bot {bot_id}"}), 500

except Exception as e:
print(f"Erro ao adicionar bot: {e}")
return jsonify({"error": "Erro ao adicionar bot"}), 500

@[Link]('/api/bots/<bot_id>', methods=['DELETE'])
@require_auth
def api_remove_bot(bot_id):
"""API para remover bot"""
try:
username = session['username']
user_bot_manager = BotManager(username)

if user_bot_manager.remove_bot(bot_id):
return jsonify({"success": True, "message": f"Bot {bot_id} removido com
sucesso"})
else:
return jsonify({"error": f"Erro ao remover bot {bot_id}"}), 500

except Exception as e:
print(f"Erro ao remover bot: {e}")
return jsonify({"error": "Erro ao remover bot"}), 500

@[Link]('/api/bots/<bot_id>', methods=['PUT'])
@require_auth
def api_update_bot(bot_id):
"""API para atualizar configuração de bot"""
try:
data = request.get_json()
username = session['username']
user_bot_manager = BotManager(username)

if user_bot_manager.update_bot_config(bot_id, data):
return jsonify({"success": True, "message": f"Bot {bot_id} atualizado
com sucesso"})
else:
return jsonify({"error": f"Erro ao atualizar bot {bot_id}"}), 500

except Exception as e:
print(f"Erro ao atualizar bot: {e}")
return jsonify({"error": "Erro ao atualizar bot"}), 500

@[Link]('/api/bots/<bot_id>/start', methods=['POST'])
@require_auth
def api_start_bot(bot_id):
"""API para iniciar bot específico"""
try:
username = session['username']
user_bot_manager = BotManager(username)

if user_bot_manager.start_bot(bot_id, username):
return jsonify({"success": True, "message": f"Bot {bot_id} iniciado com
sucesso"})
else:
return jsonify({"error": f"Erro ao iniciar bot {bot_id}"}), 500

except Exception as e:
print(f"Erro ao iniciar bot: {e}")
return jsonify({"error": "Erro ao iniciar bot"}), 500

@[Link]('/api/bots/<bot_id>/stop', methods=['POST'])
@require_auth
def api_stop_bot(bot_id):
"""API para parar bot específico"""
try:
username = session['username']
user_bot_manager = BotManager(username)

if user_bot_manager.stop_bot(bot_id):
return jsonify({"success": True, "message": f"Bot {bot_id} parado com
sucesso"})
else:
return jsonify({"error": f"Erro ao parar bot {bot_id}"}), 500

except Exception as e:
print(f"Erro ao parar bot: {e}")
return jsonify({"error": "Erro ao parar bot"}), 500

@[Link]('/api/global-token', methods=['POST'])
@require_auth
def api_set_global_token():
"""Define token PushInPay global para todos os bots do usuário"""
try:
data = request.get_json()
pushinpay_token = [Link]('pushinpay_token')
username = session['username']
if not pushinpay_token:
return jsonify({"status": "error", "message": "Token PushInPay é
obrigatório"}), 400

# Aplicar token aos bots existentes do usuário


user_bot_manager = BotManager(username)

updated_bots = []
for bot_id in user_bot_manager.bot_configs["bots"]:
bot_config = user_bot_manager.bot_configs["bots"][bot_id]
bot_config["pushinpay_token"] = pushinpay_token
updated_bots.append(bot_id)

# Salvar configurações
user_bot_manager.save_bot_configs(user_bot_manager.bot_configs)

# Reiniciar bots ativos para aplicar novo token


for bot_id in updated_bots:
if bot_id in user_bot_manager.bots:
user_bot_manager.stop_bot(bot_id)
user_bot_manager.start_bot(bot_id, username)

[Link](f"Token PushInPay global aplicado a {len(updated_bots)} bots do


usuário {username}")
return jsonify({
"status": "success",
"message": f"Token aplicado a {len(updated_bots)} bots",
"updated_bots": updated_bots
})

except Exception as e:
[Link](f"Erro ao definir token global: {e}")
return jsonify({"status": "error", "message": str(e)}), 500

# ==================== CLASSE PRINCIPAL DO BOT ====================


class TelegramSalesBot:
"""Bot de vendas do Telegram otimizado"""

def __init__(self, bot_id, bot_config, username=None):


self.bot_id = bot_id
self.bot_config = bot_config
[Link] = username
self.config_manager = ConfigManager(username)
self.data_manager = DataManager(username) if username else DataManager()
[Link] = setup_logging()
self.payment_manager = PaymentManager()

# Log para debug


[Link](f"Bot {bot_id} inicializado com configurações:")
[Link](f" - Telegram Token: {bot_config.get('telegram_token',
'NÃO CONFIGURADO')}")
[Link](f" - PushInPay Token: '{bot_config.get('pushinpay_token',
'NÃO CONFIGURADO')}'")
[Link](f" - Username: {username}")

# Verificar configurações essenciais


if not self.validate_config():
raise ValueError(f"Configurações inválidas para bot {bot_id}!")
# Para python-telegram-bot 20.x
[Link] = [Link]().token(
bot_config["telegram_token"]
).build()

self.setup_handlers()

# Registrar token no gerenciador global


if bot_config.get('telegram_token'):
global token_manager
success, message =
token_manager.register_token(bot_config['telegram_token'], username or 'unknown',
bot_id)
if success:
[Link](f"✅ Token registrado globalmente: {message}")
else:
[Link](f"⚠️ Token não registrado: {message}")

# Log final de inicialização


[Link](f"✅ Bot {bot_id} inicializado com sucesso para usuário
{username}")

def validate_config(self):
"""Valida configurações essenciais"""
required_keys = ["telegram_token"]

for key in required_keys:


if not self.bot_config.get(key):
[Link](f"Configuração obrigatória não encontrada para
bot {self.bot_id}: {key}")
return False

# Token PushInPay é opcional


if not self.bot_config.get("pushinpay_token"):
[Link](f"Token PushInPay não configurado para bot
{self.bot_id} - pagamentos não funcionarão")

return True

def setup_handlers(self):
"""Configura os handlers do bot"""
# Para python-telegram-bot 20.x
[Link].add_handler(CommandHandler("start", self.start_command))
[Link].add_handler(CommandHandler("status", self.status_command))
[Link].add_handler(CommandHandler("reload", self.reload_command))
[Link].add_handler(CommandHandler("testapi", self.test_api_command))
[Link].add_handler(CommandHandler("dashboard", self.dashboard_command))
[Link].add_handler(CallbackQueryHandler(self.handle_callback_query))

async def start_command(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para comando /start"""
try:
user_id = update.effective_user.id
chat_id = update.effective_chat.id

[Link](f"Comando /start recebido do usuário {user_id}")

# Recarregar configurações e produtos antes de processar


self.config_manager.reload_configs()
[Link]("✅ Configurações e produtos recarregados")

# Enviar mídia se configurada


await self.send_media_if_configured(chat_id, context)

# Criar mensagem de boas-vindas


message_text = self.bot_config.get("messages", {}).get("welcome", "🔥
**OFERTA ESPECIAL** 🔥")

# Criar botões dos produtos (com dados atualizados)


keyboard = self.create_product_keyboard()

if not keyboard:
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("config_error", "Erro de configuração")
await [Link].send_message(
chat_id=chat_id,
text=error_msg
)
return

reply_markup = InlineKeyboardMarkup(keyboard)

# Enviar mensagem com produtos


await [Link].send_message(
chat_id=chat_id,
text=message_text,
reply_markup=reply_markup,
parse_mode='Markdown'
)

except Exception as e:
[Link](f"Erro no comando start: {e}")
await self.send_error_message(update, context, "general_error")

async def status_command(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para comando /status"""
try:
user_id = update.effective_user.id
user_payments = []

for payment_id, payment_data in


self.payment_manager.pending_payments.items():
if payment_data.get("user_id") == user_id:
user_payments.append({
"id": payment_id[:8].upper(),
"product": payment_data.get("product", {}).get("name",
"Produto"),
"created_at": payment_data.get("created_at",
[Link]())
})

if not user_payments:
message_text = "📊 Você não possui pagamentos pendentes."
else:
message_text = "📊 **SEUS PAGAMENTOS PENDENTES:**\n\n"
for payment in user_payments:
time_diff = [Link]() - payment["created_at"]
minutes_ago = int(time_diff.total_seconds() / 60)
message_text += f"🔸 **{payment['id']}** - {payment['product']}\
n"
message_text += f" ⏰ Criado há {minutes_ago} minutos\n\n"

await [Link].send_message(
chat_id=update.effective_chat.id,
text=message_text,
parse_mode='Markdown'
)

except Exception as e:
[Link](f"Erro no comando status: {e}")
await self.send_error_message(update, context, "general_error")

async def reload_command(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para comando /reload - força recarga de configurações"""
try:
# Recarregar configurações
self.config_manager.reload_configs()

# Obter informações atualizadas


products_count = len(self.config_manager.[Link]("products", []))
active_products = len([p for p in
self.config_manager.[Link]("products", []) if [Link]("active", True)])

message = f"🔄 **CONFIGURAÇÕES RECARREGADAS!**\n\n"


message += f"📦 **Produtos:** {products_count} total, {active_products}
ativos\n"
message += f"✅ **Status:** Atualizado com sucesso\n\n"
message += f"💡 Use `/start` para ver os produtos atualizados!"

await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)

[Link](f"Configurações recarregadas via comando -


{active_products} produtos ativos")

except Exception as e:
[Link](f"Erro no comando reload: {e}")
await self.send_error_message(update, context, "general_error")

async def test_api_command(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para comando /testapi - testa conectividade com PushInPay"""
try:
await [Link].send_message(
chat_id=update.effective_chat.id,
text="🔍 Testando conectividade com a API oficial da PushInPay..."
)

# URL oficial da API PushInPay


test_url = "[Link]
token = self.bot_config['pushinpay_token']

# Testar a API da PushInPay


try:
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
"Content-Type": "application/json"
}

# Teste com payload mínimo para verificar conectividade


test_payload = {
"value": 100, # R$ 1,00 em centavos
"webhook_url": "",
"split_rules": []
}

response = [Link](test_url, json=test_payload,


headers=headers, timeout=10)

if response.status_code == 200 or response.status_code == 201:


try:
data = [Link]()
result = f"✅ API funcionando! Transação de teste criada:
{[Link]('id', 'N/A')[:8]}..."
status = [Link]('status', 'N/A')
result += f"\n📊 Status: {status}"
except:
result = f"✅ API funcionando! (resposta válida)"
elif response.status_code == 400:
result = f"⚠️ API acessível, mas payload inválido (400)"
elif response.status_code == 401:
result = f"🔑 Token inválido ou expirado (401)"
elif response.status_code == 403:
result = f"🚫 Acesso negado - verifique permissões (403)"
elif response.status_code == 404:
result = f"❌ Endpoint não encontrado (404)"
else:
result = f"⚠️ HTTP {response.status_code}:
{[Link][:100]}..."

except [Link]:
result = f" Timeout na conexão com a API"
except [Link]:
result = f"🔌 Erro de conexão com a API"
except Exception as e:
result = f"❌ Erro: {str(e)[:100]}..."

# Montar mensagem de resultado


message = "🔍 **TESTE DA API PUSHINPAY OFICIAL**\n\n"
message += f"📡 **Endpoint:** `{test_url}`\n"
message += f"🔑 **Token configurado:** {'✅ Sim' if token and token !=
'SEU_TOKEN_PUSHINPAY_AQUI' else '❌ Não'}\n\n"
message += f"📊 **Resultado:**\n{result}\n\n"
message += "📚 **Documentação:** [PushInPay
API]([Link]
message += "💡 **Dica:** Se o teste falhar, verifique:\n"
message += "• Token válido no [Link]\n"
message += "• Conexão com internet\n"
message += "• Status da API PushInPay"

await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)

except Exception as e:
[Link](f"Erro no comando testapi: {e}")
await [Link].send_message(
chat_id=update.effective_chat.id,
text="❌ Erro ao testar API. Verifique os logs."
)

async def dashboard_command(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para comando /dashboard"""
try:
dashboard_url = "[Link]

message = f"📊 **DASHBOARD DO BOT {self.bot_id.upper()}**\n\n"


message += f"🔗 **URL:** {dashboard_url}\n\n"
message += "📈 **Recursos disponíveis:**\n"
message += "• 📊 Estatísticas em tempo real\n"
message += "• 🔄 Atualização automática\n"
message += "• 📱 Interface responsiva\n"
message += "• 📋 Atividades recentes\n"
message += "• 💻 Informações do sistema\n"
message += "• 📝 Logs em tempo real\n\n"
message += "💡 **Como usar:**\n"
message += "1. Clique no link acima\n"
message += "2. Visualize as estatísticas\n"
message += "3. Monitore o desempenho\n"
message += "4. Controle o bot remotamente"

await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)

except Exception as e:
[Link](f"Erro no comando dashboard: {e}")
await [Link].send_message(
chat_id=update.effective_chat.id,
text="❌ Erro ao gerar link do dashboard."
)

def detect_media_type(self, url):


"""Detecta automaticamente o tipo de mídia baseado na URL"""
if not url:
return None

url_lower = [Link]()

# Extensões de imagem
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
# Extensões de vídeo
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.flv',
'.wmv', '.m4v']

# Verificar extensões na URL


for ext in image_extensions:
if ext in url_lower:
return "photo"

for ext in video_extensions:


if ext in url_lower:
return "video"

# Verificar domínios conhecidos


if any(domain in url_lower for domain in ['[Link]', '[Link]',
'[Link]']):
return "video"

if any(domain in url_lower for domain in ['[Link]', '[Link]',


'[Link]']):
return "photo"

# Verificar parâmetros da URL do Discord


if 'discord' in url_lower and '.mp4' in url_lower:
return "video"

if 'discord' in url_lower and any(ext in url_lower for ext in ['.jpg',


'.png', '.gif', '.webp']):
return "photo"

# Se não conseguir detectar, assume que é foto por padrão


return "photo"

async def send_media_if_configured(self, chat_id, context):


"""Envia mídia se configurada com detecção automática"""
media_config = self.bot_config.get("media", {})

if not media_config.get("enabled", False):


return

media_url = media_config.get("url")

if not media_url:
return

# Detectar tipo automaticamente


media_type = self.detect_media_type(media_url)

try:
if media_type == "photo":
await [Link].send_photo(chat_id=chat_id, photo=media_url)
elif media_type == "video":
await [Link].send_video(chat_id=chat_id, video=media_url)

[Link](f"Mídia enviada: {media_type} - {media_url[:50]}...")

except Exception as e:
[Link](f"Erro ao enviar mídia ({media_type}): {e}")

def create_product_keyboard(self):
"""Cria teclado com produtos ativos"""
keyboard = []
# Sempre buscar produtos atualizados
active_products = self.config_manager.get_active_products()

[Link](f"📦 Criando teclado com {len(active_products)} produtos


ativos")

for product in active_products:


name = [Link]("name", "Produto")
price = [Link]("price", 0)
button_text = f"{name} por R$ {price:.2f}".replace('.', ',')
[Link]([InlineKeyboardButton(
button_text,
callback_data=f"product_{product['id']}"
)])
[Link](f" - {name}: R$ {price:.2f}")

return keyboard

async def handle_callback_query(self, update: Update, context:


ContextTypes.DEFAULT_TYPE):
"""Handler para callback queries"""
try:
query = update.callback_query
await [Link]()

if [Link]("product_"):
await self.handle_product_selection(query, context)
else:
[Link](f"Callback query não reconhecido:
{[Link]}")

except Exception as e:
[Link](f"Erro no callback query: {e}")
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("general_error", "Erro")
await query.edit_message_text(error_msg)

async def handle_product_selection(self, query, context):


"""Handler para seleção de produtos"""
try:
# Recarregar configurações antes de processar
self.config_manager.reload_configs()
[Link]("✅ Configurações recarregadas antes de processar
produto")

# Extrair ID do produto
product_id = [Link]("product_", "")
product = self.config_manager.get_product_by_id(product_id)

if not product:
await query.edit_message_text("❌ Produto não encontrado!")
return

user_id = query.from_user.id
[Link](f"Produto selecionado: {product_id} por usuário
{user_id}")
[Link](f"Detalhes do produto: {product['name']} - R$
{product['price']:.2f}")

# Criar pagamento na PushInPay


payment_data = await self.create_payment(product, user_id)

if payment_data:
await self.send_payment_message(query, context, product,
payment_data)
else:
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("payment_failed", "Erro no pagamento")
await query.edit_message_text(error_msg)

except Exception as e:
[Link](f"Erro na seleção de produto: {e}")
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("general_error", "Erro")
await query.edit_message_text(error_msg)

async def send_payment_message(self, query, context, product, payment_data):


"""Envia mensagem com informações de pagamento"""
try:
# Gerar QR Code
qr_code_image = self.generate_qr_code(payment_data["pix_payload"])

# Criar mensagem de pagamento com ID da compra e payload PIX


payment_template = self.bot_config.get("messages", {}).get("payment",
"💳 **PAGAMENTO VIA PIX**\n\n"
"🆔 **ID da Compra:** {purchase_id}\n"
"📦 **Produto:** {product_name}\n"
"💰 **Valor:** R$ {price}\n\n"
"📱 **Código PIX:**\n"
"`{pix_code}`\n\n"
)

message_text = payment_template.format(
purchase_id=payment_data["payment_id"],
product_name=product["name"],
price=f"{product['price']:.2f}".replace('.', ','),
pix_code=payment_data["pix_payload"]
)

# Enviar QR Code e informações


sent_message = await [Link].send_photo(
chat_id=[Link].chat_id,
photo=qr_code_image,
caption=message_text,
parse_mode='Markdown'
)

# Salvar informações do pagamento pendente


payment_info = {
"user_id": query.from_user.id,
"chat_id": [Link].chat_id,
"message_id": sent_message.message_id,
"product": product,
"payment_id": payment_data["payment_id"],
"created_at": [Link]()
}
self.payment_manager.add_pending_payment(payment_data["payment_id"],
payment_info)

# Iniciar verificação de pagamento


import asyncio
asyncio.create_task(
self.check_payment_status(payment_data["payment_id"], context)
)

except Exception as e:
[Link](f"Erro ao enviar mensagem de pagamento: {e}")
raise

async def create_payment(self, product, user_id):


"""Cria pagamento na PushInPay usando API oficial"""
try:
# URL oficial da API PushInPay
url = "[Link]

token = self.bot_config['pushinpay_token']

# Log para debug


[Link](f"Token PushInPay configurado: '{token}'")

# Verificar se o token está configurado


if not token or token == "SEU_TOKEN_PUSHINPAY_AQUI":
[Link]("Token da PushInPay não configurado
corretamente!")
return None

headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
"Content-Type": "application/json"
}

# Payload conforme documentação oficial


payload = {
"value": int(product["price"] * 100), # Valor em centavos
"webhook_url": "", # URL do webhook (opcional)
"split_rules": [] # Regras de divisão (opcional)
}

[Link](f"Criando pagamento PIX via PushInPay: {url}")


[Link](f"Payload: value={payload['value']} centavos (R$
{product['price']:.2f})")

response = [Link](url, json=payload, headers=headers,


timeout=15)

[Link](f"Status da resposta: {response.status_code}")


[Link](f"Resposta da API: {[Link][:300]}...")

if response.status_code == 200:
try:
data = [Link]()
[Link](f"Pagamento PIX criado com sucesso!")
[Link](f"ID: {[Link]('id', 'N/A')}")
[Link](f"Status: {[Link]('status', 'N/A')}")

return {
"payment_id": [Link]("id"),
"pix_payload": [Link]("qr_code"), # Campo qr_code contém
o código PIX
"qr_code_base64": [Link]("qr_code_base64"),
"status": [Link]("status")
}
except [Link] as e:
[Link](f"Erro ao decodificar JSON da resposta: {e}")
[Link](f"Resposta bruta: {[Link]}")
return None

elif response.status_code == 400:


[Link](f"Erro 400 - Bad Request: {[Link]}")
return None
elif response.status_code == 401:
[Link](f"Erro 401 - Token inválido: {[Link]}")
return None
elif response.status_code == 403:
[Link](f"Erro 403 - Forbidden: {[Link]}")
return None
else:
[Link](f"Erro HTTP {response.status_code}:
{[Link]}")
return None

except Exception as e:
[Link](f"Erro inesperado ao criar pagamento: {e}")
return None

def generate_qr_code(self, pix_payload):


"""Gera QR Code do PIX"""
try:
qr = [Link](
version=1,
error_correction=[Link].ERROR_CORRECT_L,
box_size=10,
border=4,
)
qr.add_data(pix_payload)
[Link](fit=True)

img = qr.make_image(fill_color="black", back_color="white")

# Converter para bytes


img_buffer = [Link]()
[Link](img_buffer, format='PNG')
img_buffer.seek(0)

return img_buffer

except Exception as e:
[Link](f"Erro ao gerar QR Code: {e}")
return None

async def check_payment_status(self, payment_id, context):


"""Verifica status do pagamento periodicamente"""
try:
timeout_minutes = 30 # 30 minutos hardcoded
check_interval = 10 # 10 segundos hardcoded

max_attempts = (timeout_minutes * 60) // check_interval


attempts = 0

while attempts < max_attempts:


payment_info = self.payment_manager.get_pending_payment(payment_id)
if not payment_info:
break

# Verificar na API da PushInPay


status = await self.get_payment_status(payment_id)

if status == "paid":
await self.approve_payment(payment_id, context)
break
elif status == "expired" or status == "cancelled":
await self.cancel_payment(payment_id, context)
break

attempts += 1
await [Link](check_interval)

# Se chegou aqui, o pagamento expirou


if self.payment_manager.get_pending_payment(payment_id):
await self.cancel_payment(payment_id, context)

except Exception as e:
[Link](f"Erro ao verificar status do pagamento: {e}")

async def get_payment_status(self, payment_id):


"""Consulta status do pagamento na PushInPay usando API oficial"""
try:
# URL oficial para consulta de transações
url = f"[Link]

token = self.bot_config['pushinpay_token']

headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
"Content-Type": "application/json"
}

response = [Link](url, headers=headers, timeout=10)

if response.status_code == 200:
try:
data = [Link]()
if data is None:
[Link](f"Pagamento {payment_id} não encontrado
(retorno null)")
return "error"

status = [Link]("status", "created")


[Link](f"Status do pagamento {payment_id}: {status}")
# Mapear status da PushInPay para nosso sistema
if status == "paid":
return "paid"
elif status == "expired":
return "expired"
elif status == "created":
return "pending"
else:
return status

except [Link] as e:
[Link](f"Erro ao decodificar resposta de status:
{e}")
return "error"

elif response.status_code == 404:


[Link](f"Pagamento {payment_id} não encontrado (404)")
return "error"
else:
[Link](f"Erro ao consultar status HTTP
{response.status_code}: {[Link]}")
return "error"

except Exception as e:
[Link](f"Erro inesperado ao consultar status: {e}")
return "error"

async def approve_payment(self, payment_id, context):


"""Aprova pagamento e envia acesso"""
try:
payment_info = self.payment_manager.get_pending_payment(payment_id)
if not payment_info:
return

# Criar mensagem de aprovação


success_template = self.bot_config.get("messages", {}).get("success",
"✅ **PAGAMENTO APROVADO!** ✅\n\n"
"🆔 **ID da Compra:** {purchase_id}\n"
"🎉 **Parabéns! Seu pagamento foi confirmado!**\n\n"
"🔗 **Acesso ao grupo:** {group_link}"
)
group_link = self.bot_config.get("group_link", "")

approval_text = success_template.format(
purchase_id=payment_id,
group_link=group_link
)

await [Link].edit_message_caption(
chat_id=payment_info["chat_id"],
message_id=payment_info["message_id"],
caption=approval_text,
parse_mode='Markdown'
)

self.payment_manager.approve_payment(payment_id)

# Salvar dados após aprovação do pagamento


product_price = payment_info.get("product", {}).get("price", 0.0)
self.data_manager.save_stats({
"approved": 1,
"pending": 0,
"revenue": product_price
})

[Link](f"💾 Dados salvos após aprovação: +1 aprovado, R$ +


{product_price:.2f}")

except Exception as e:
[Link](f"Erro ao aprovar pagamento: {e}")

async def cancel_payment(self, payment_id, context):


"""Cancela pagamento expirado"""
try:
payment_info = self.payment_manager.get_pending_payment(payment_id)
if not payment_info:
return

messages = self.bot_config.get("messages", {})


cancel_text = [Link]("error", {}).get("payment_expired",
"Pagamento expirado")

await [Link].edit_message_caption(
chat_id=payment_info["chat_id"],
message_id=payment_info["message_id"],
caption=cancel_text,
parse_mode='Markdown'
)

self.payment_manager.remove_pending_payment(payment_id)

except Exception as e:
[Link](f"Erro ao cancelar pagamento: {e}")

async def send_error_message(self, update, context, error_type):


"""Envia mensagem de erro"""
try:
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get(error_type, "Erro desconhecido")
await [Link].send_message(
chat_id=update.effective_chat.id,
text=error_msg
)
except Exception as e:
[Link](f"Erro ao enviar mensagem de erro: {e}")

def run(self):
"""Executa o bot"""
[Link]("🤖 Bot iniciado! Pressione Ctrl+C para parar.")
try:
# Para python-telegram-bot 20.x - versão simplificada
[Link].run_polling(
drop_pending_updates=True,
close_loop=False
)
except Exception as e:
[Link](f"Erro ao executar bot: {e}")
import traceback
traceback.print_exc()

# ==================== CONTROLE GLOBAL DE TOKENS ====================


class TokenManager:
"""Gerencia tokens do Telegram para evitar conflitos"""

def __init__(self):
self.active_tokens = {} # token -> (username, bot_id)
self.active_users = set() # usuários que já iniciaram bots
[Link] = [Link]()

def register_token(self, token, username, bot_id):


"""Registra um token como ativo"""
with [Link]:
if token in self.active_tokens:
existing_user, existing_bot = self.active_tokens[token]
return False, f"Token já está sendo usado por {existing_user}:
{existing_bot}"

self.active_tokens[token] = (username, bot_id)


self.active_users.add(username)
return True, f"Token registrado para {username}:{bot_id}"

def unregister_token(self, token):


"""Remove registro de um token"""
with [Link]:
if token in self.active_tokens:
username = self.active_tokens[token][0]
del self.active_tokens[token]
# Remover usuário apenas se não tiver mais tokens ativos
if not any(u == username for u, _ in self.active_tokens.values()):
self.active_users.discard(username)
return True
return False

def is_token_available(self, token):


"""Verifica se um token está disponível"""
with [Link]:
return token not in self.active_tokens

def has_user_started_bots(self, username):


"""Verifica se um usuário já iniciou bots"""
with [Link]:
return username in self.active_users

def get_active_tokens_info(self):
"""Retorna informações sobre tokens ativos"""
with [Link]:
return dict(self.active_tokens)

# Instância global do gerenciador de tokens


token_manager = TokenManager()

@[Link]('/api/debug/tokens')
def api_debug_tokens():
"""API para debug - mostra tokens ativos"""
try:
active_tokens = token_manager.get_active_tokens_info()
active_users = list(token_manager.active_users)
debug_info = {
"active_tokens": active_tokens,
"active_users": active_users,
"total_tokens": len(active_tokens),
"total_users": len(active_users)
}

return jsonify(debug_info)
except Exception as e:
return jsonify({"error": str(e)}), 500

# ==================== EXECUÇÃO PRINCIPAL ====================


def main():
"""Função principal"""
try:
global logger, data_manager

# Inicializar sistema de persistência da dashboard


data_manager = DataManager()

# Configurar logger global


logger = setup_logging()

# Inicializar gerenciador de tokens

# Não inicializar bots globalmente - cada usuário terá seu próprio


gerenciador

# Iniciar servidor Flask (principal)


[Link](host='[Link]', port=8080, debug=False, threaded=True)

except KeyboardInterrupt:
pass
except Exception as e:
print(f"❌ Erro fatal: {e}")
traceback.print_exc()

if __name__ == "__main__":
main()

Você também pode gostar