Bitconn WhatsApp Scheduler
Permite agendar envios de mensagens WhatsApp usando templates aprovados.
Funcionalidades
Seção intitulada “Funcionalidades”- Criação de agendamentos com data/hora definida
- Seleção de template e conta WhatsApp
- Cron de processamento automático dos envios
- Visão de lista para agentes com filtros e agrupamentos
Dependências
Seção intitulada “Dependências”whatsapp, crm, survey
Documentação
Seção intitulada “Documentação”Módulo para agendamento e envio automatizado de mensagens WhatsApp via templates aprovados no Meta Business.
Depende do módulo Enterprise whatsapp e do módulo crm.
- Instalação
- Como funciona o agendamento
- Precisão de envio e limitações do Cron
- Métodos principais
- Ciclo de vida de um agendamento
- Criar agendamento pela interface
- Criar agendamento por Regra de Automação
- Criar agendamento por código Python
- Estrutura de arquivos
Instalação
Seção intitulada “Instalação”- Instale as dependências Python no virtualenv:
Terminal window pip install phonenumbers - Certifique-se que os módulos
whatsappecrmestão instalados no Odoo. - Instale o módulo
bitconn_whatsapppela interface ou via linha de comando:Terminal window ./odoo-bin -c <seu.conf> -i bitconn_whatsapp
Como funciona o agendamento
Seção intitulada “Como funciona o agendamento”O módulo usa um cron job que executa a cada 5 minutos e processa todos os registros do modelo bitconn.whatsapp.schedule que estejam:
state = 'scheduled'scheduled_date <= agora
Para cada registro encontrado, o cron chama _send_whatsapp(), que usa o whatsapp.composer do módulo Enterprise para efetuar o envio via API do Meta (WhatsApp Cloud API).
[Cron a cada 5min] │ ▼_process_scheduled_messages() │ ├─ busca: state=scheduled AND scheduled_date <= now │ └─ para cada registro: _send_whatsapp() │ ├─ cria whatsapp.composer ├─ chama _send_whatsapp_template() ├─ registra whatsapp.message gerada ├─ atualiza state → 'sent' └─ posta nota no chatter do lead (se vinculado)Precisão de envio e limitações do Cron
Seção intitulada “Precisão de envio e limitações do Cron”⚠️ Importante: O cron do Odoo não garante envio no segundo exato. O desvio máximo de atraso é o intervalo do cron (padrão: 5 minutos).
| Intervalo do cron | Atraso máximo |
|---|---|
| 5 minutos (padrão) | até 5 min |
| 1 minuto | até 1 min |
| 30 segundos* | até 30 seg |
* O Odoo suporta interval_type = 'seconds' mas intervalos muito curtos aumentam carga no servidor.
Ajustando a precisão
Seção intitulada “Ajustando a precisão”Para aumentar a precisão, altere o intervalo do cron em:
Configurações → Técnico → Automação → Ações Agendadas → “Bitconn WhatsApp: Processar Envios Agendados”
Ou diretamente no XML de dados (data/ir_cron_data.xml):
<field name="interval_number">1</field><field name="interval_type">minutes</field>Envios em lote vs. alta carga
Seção intitulada “Envios em lote vs. alta carga”Se houver muitos agendamentos simultâneos, os envios serão processados sequencialmente dentro do mesmo tick do cron. Para alto volume, considere processar em lotes com limit:
# Sobrescreva _process_scheduled_messages para processar em lotes de 50def _process_scheduled_messages(self): now = fields.Datetime.now() schedules = self.search([ ('state', '=', 'scheduled'), ('scheduled_date', '<=', now), ], limit=50) for schedule in schedules: schedule._send_whatsapp()Métodos principais
Seção intitulada “Métodos principais”action_schedule(self)
Seção intitulada “action_schedule(self)”Tipo: método de botão (UI)
Modelo: bitconn.whatsapp.schedule
Transição draft → scheduled. Valida que o registro está em rascunho e registra nota interna no chatter do lead vinculado (se houver).
schedule.action_schedule()action_cancel(self)
Seção intitulada “action_cancel(self)”Tipo: método de botão (UI)
Modelo: bitconn.whatsapp.schedule
Cancela um agendamento que ainda não foi enviado. Impede cancelamento de registros sent.
action_reset_draft(self)
Seção intitulada “action_reset_draft(self)”Tipo: método de botão (UI)
Modelo: bitconn.whatsapp.schedule
Redefine agendamentos cancelled ou failed de volta para draft, limpando o erro e a mensagem vinculada.
_process_scheduled_messages(self)
Seção intitulada “_process_scheduled_messages(self)”Tipo: método privado — chamado pelo Cron
Modelo: bitconn.whatsapp.schedule
Ponto de entrada do cron. Busca todos os agendamentos pendentes e delega o envio para _send_whatsapp().
# Chamada pelo cron:# model._process_scheduled_messages()
# Pode ser chamado manualmente via shell para testes:env['bitconn.whatsapp.schedule']._process_scheduled_messages()_send_whatsapp(self)
Seção intitulada “_send_whatsapp(self)”Tipo: método privado — chamado por _process_scheduled_messages
Modelo: bitconn.whatsapp.schedule
Executa o envio de um único agendamento:
- Cria um
whatsapp.composercom a conta, template e número - Chama
_send_whatsapp_template()(API Meta via módulo Enterprise) - Vincula o
whatsapp.messagegerado ao agendamento - Atualiza
state → 'sent'oustate → 'failed'em caso de erro - Posta nota no chatter do lead vinculado
action_open_whatsapp_schedule_wizard(self)
Seção intitulada “action_open_whatsapp_schedule_wizard(self)”Tipo: método de botão (UI)
Modelo: crm.lead
Abre o wizard de criação de agendamento pré-preenchido com os dados do lead (nome, contato, telefone). Disponível no formulário do lead via botão “Agendar WhatsApp”.
action_view_whatsapp_schedules(self)
Seção intitulada “action_view_whatsapp_schedules(self)”Tipo: método de botão (UI)
Modelo: crm.lead
Abre a lista de agendamentos filtrada pelo lead. Acessível pelo smart button com contador no formulário do lead.
Ciclo de vida de um agendamento
Seção intitulada “Ciclo de vida de um agendamento”draft │ ├─[action_schedule]──► scheduled ──[cron _process_scheduled_messages]──► sent │ │ │ [action_cancel] │ │ │ ▼ │ cancelled ──[action_reset_draft]──► draft │ └─────────────────────────────────────────────────────────────► failed ──[action_reset_draft]──► draftCriar agendamento pela interface
Seção intitulada “Criar agendamento pela interface”- Acesse WhatsApp → Agendamentos → Novo
- Preencha: descrição, número, conta WhatsApp, template e data/hora
- Clique em “Agendar Envio”
- O cron processará automaticamente no próximo tick após a data agendada
Ou diretamente do CRM:
- Abra um Lead/Oportunidade
- Clique no botão “Agendar WhatsApp” no header do formulário
- O wizard abrirá pré-preenchido com os dados do lead
- Selecione o template, conta e data/hora
- Clique em “Confirmar Agendamento”
Criar agendamento por Regra de Automação
Seção intitulada “Criar agendamento por Regra de Automação”É possível criar agendamentos automaticamente com Regras de Automação (base_automation) do Odoo, sem escrever código.
Exemplo: agendar WhatsApp quando um lead muda para a etapa “Proposta”
Seção intitulada “Exemplo: agendar WhatsApp quando um lead muda para a etapa “Proposta””Configurações → Técnico → Automação → Regras de Automação → Novo
| Campo | Valor |
|---|---|
| Nome | Agendar WhatsApp na Proposta |
| Modelo | Lead/Oportunidade (crm.lead) |
| Gatilho | Ao atualizar um registro |
| Campos monitorados | stage_id |
| Ação | Executar código Python |
Código Python da ação:
# Busca a conta WhatsApp e o template desejadoswa_account = env['whatsapp.account'].search([], limit=1)template = env['whatsapp.template'].search([ ('name', 'ilike', 'proposta'), ('wa_account_id', '=', wa_account.id), ('status', '=', 'approved'),], limit=1)
if wa_account and template: for lead in records: phone = lead.partner_id.phone or lead.phone or lead.mobile if not phone: continue schedule = env['bitconn.whatsapp.schedule'].create({ 'name': f'WhatsApp Proposta - {lead.name}', 'lead_id': lead.id, 'partner_id': lead.partner_id.id if lead.partner_id else False, 'mobile_number': phone, 'whatsapp_account_id': wa_account.id, 'template_id': template.id, # Enviar 1 hora após a mudança de etapa 'scheduled_date': datetime.datetime.now() + datetime.timedelta(hours=1), 'state': 'scheduled', })Nota:
datetimejá está disponível no contexto das regras de automação do Odoo.
Exemplo: agendar WhatsApp de follow-up 3 dias após criação do lead
Seção intitulada “Exemplo: agendar WhatsApp de follow-up 3 dias após criação do lead”| Campo | Valor |
|---|---|
| Gatilho | Baseado em data/tempo |
| Data | Data de Criação |
| Atraso | +3 dias |
| Ação | Executar código Python |
wa_account = env['whatsapp.account'].search([], limit=1)template = env['whatsapp.template'].search([ ('name', 'ilike', 'follow'), ('wa_account_id', '=', wa_account.id), ('status', '=', 'approved'),], limit=1)
if wa_account and template: for lead in records: phone = lead.partner_id.phone or lead.phone or lead.mobile if not phone: continue # Cria já agendado para envio imediato (o cron irá processar no próximo tick) env['bitconn.whatsapp.schedule'].create({ 'name': f'Follow-up D+3 - {lead.name}', 'lead_id': lead.id, 'partner_id': lead.partner_id.id if lead.partner_id else False, 'mobile_number': phone, 'whatsapp_account_id': wa_account.id, 'template_id': template.id, 'scheduled_date': datetime.datetime.now(), 'state': 'scheduled', })Criar agendamento por código Python
Seção intitulada “Criar agendamento por código Python”Use este padrão em qualquer método de modelo, wizard ou script de migração:
def meu_metodo(self): wa_account = self.env['whatsapp.account'].browse(ACCOUNT_ID) template = self.env['whatsapp.template'].browse(TEMPLATE_ID)
schedule = self.env['bitconn.whatsapp.schedule'].create({ 'name': 'Descrição do agendamento', 'lead_id': self.id, # opcional 'partner_id': self.partner_id.id, # opcional 'mobile_number': '+5511999999999', 'whatsapp_account_id': wa_account.id, 'template_id': template.id, 'scheduled_date': fields.Datetime.now() + timedelta(hours=2), 'state': 'scheduled', # já agendado, pronto para o cron }) return scheduleForçar envio imediato (sem esperar o cron)
Seção intitulada “Forçar envio imediato (sem esperar o cron)”schedule = self.env['bitconn.whatsapp.schedule'].create({...})schedule._send_whatsapp()Use com cautela em contextos de UI — pode deixar a interface lenta se o envio demorar. Prefira o cron para produção.
Estrutura de arquivos
Seção intitulada “Estrutura de arquivos”bitconn_whatsapp/├── __init__.py├── __manifest__.py├── data/│ └── ir_cron_data.xml # Definição do cron (a cada 5 min)├── models/│ ├── __init__.py│ ├── whatsapp_schedule.py # Modelo principal + lógica de envio│ └── crm_lead.py # Extensão do crm.lead (smart button + wizard action)├── wizards/│ ├── __init__.py│ └── whatsapp_schedule_wizard.py # Wizard de agendamento a partir do lead├── security/│ └── ir.model.access.csv # Permissões de acesso└── views/ ├── whatsapp_schedule_views.xml # Form, list, search do agendamento ├── whatsapp_schedule_wizard_views.xml # Form do wizard ├── crm_lead_views.xml # Extensão do formulário do lead └── whatsapp_schedule_menus.xml # Menu WhatsApp → Agendamentos