Skip to main content

Lógica de Notificação Pré-Vencimento (1 Dia Antes)

Visão Geral

A notificação InvoicePreDueReminderNotification envia lembretes 1 dia antes do vencimento efetivo de faturas, com tratamento inteligente de finais de semana e feriados.

Conceitos Fundamentais

1. Dia Útil vs Dia Não Útil
  • Dia Útil: Segunda a sexta-feira, exceto feriados
  • Dia Não Útil: Sábados, domingos e feriados (tabela gk2_hollidays)
2. Vencimento Original vs Vencimento Efetivo
  • Vencimento Original: Data de vencimento registrada na fatura
  • Vencimento Efetivo: Primeiro dia útil após o vencimento original (se cair em dia não útil)

Exemplo:
Vencimento Original: Domingo, 28/09/2025
Vencimento Efetivo: Segunda, 29/09/2025 (próximo dia útil)

Regras de Envio

A lógica possui duas regras que se aplicam dependendo do contexto:

Regra 1: Bloco de Dias Não Úteis (Sexta-feira e vésperas)

Quando aplicar:

  • Hoje é dia útil
  • Amanhã é dia não útil (sábado, domingo ou feriado)

Como funciona:

  1. Percorre todos os dias não úteis consecutivos a partir de amanhã
  2. Para cada dia no bloco, verifica se alguma fatura vence naquele dia
  3. Notifica hoje todas as faturas cujo vencimento original cai dentro desse bloco
Exemplo 1 - Fim de semana normal:

Hoje: Sexta, 26/09/2025 (dia útil)
Amanhã: Sábado, 27/09/2025 (não útil) ← gatilho da regra
Bloco: [Sábado 27, Domingo 28]
Faturas notificadas hoje (sexta):
- Fatura vence Sábado 27/09 ✅
- Fatura vence Domingo 28/09 ✅
- Fatura vence Segunda 29/09 ❌ (não está no bloco)

Exemplo 2 - Feriado prolongado:

Hoje: Quinta, 25/09/2025 (dia útil)
Amanhã: Sexta, 26/09/2025 (feriado) ← gatilho da regra
Bloco: [Sexta 26 (feriado), Sábado 27, Domingo 28]
Faturas notificadas hoje (quinta):
- Fatura vence Sexta 26/09 ✅
- Fatura vence Sábado 27/09 ✅
- Fatura vence Domingo 28/09 ✅
- Fatura vence Segunda 29/09 ❌

Regra 2: Dia Anterior Simples (Dias normais)

Quando aplicar:

  • Hoje é dia útil
  • Amanhã também é dia útil

Como funciona:

  1. Calcula o vencimento efetivo da fatura (normaliza para dia útil)
  2. Subtrai 1 dia do vencimento efetivo
  3. Se hoje == (vencimento efetivo - 1 dia), notifica

Exemplo 1 - Fatura vence em dia útil:

Hoje: Terça, 30/09/2025
Venc. Original: Quarta, 01/10/2025
Venc. Efetivo: Quarta, 01/10/2025 (já é dia útil)
Dia Anterior: Terça, 30/09/2025
Resultado: NOTIFICA ✅ (hoje == dia anterior)

Exemplo 2 - Fatura vence em domingo (mas amanhã é útil):

Hoje: Segunda, 29/09/2025
Venc. Original: Domingo, 05/10/2025 (próximo domingo)
Venc. Efetivo: Segunda, 06/10/2025 (normalizado)
Dia Anterior: Domingo, 05/10/2025
Resultado: NÃO NOTIFICA ❌ (hoje != dia anterior)

Fluxo de Decisão

    ┌─────────────────────────────┐
    │ Hoje é dia útil?            │
    └──────────┬──────────────────┘
               │ Não
               ├──────────> NÃO ENVIA
               │
               │ Sim
               ▼
    ┌─────────────────────────────┐
    │ Amanhã é dia não útil?      │
    └──────────┬──────────────────┘
               │
          ┌────┴────┐
          │         │
         Sim       Não
          │         │
          ▼         ▼
    ┌─────────┐  ┌──────────────────────┐
    │ REGRA 1 │  │ REGRA 2              │
    │ Bloco   │  │ Simples 1 dia antes  │
    └─────────┘  └──────────────────────┘
    

Implementação Técnica

Estrutura de Arquivos
    Helpers/
    ├── InvoiceNotificationScheduler.php
    │   └── Lógica de dias úteis/feriados
    │
    └── InvoicePreDueReminderScheduler.php
        └── Lógica de decisão de envio (Regra 1 + Regra 2)

    InvoicePreDueReminderNotification.php
    └── Busca faturas Unpaid e usa scheduler para decidir
    

Classe: InvoicePreDueReminderScheduler

Método Principal:
    public function shouldNotifyOneDayBeforeEffective(
        DateTime $today,
        DateTime $originalDueDate
    ): bool
    

Pseudocódigo:

    SE hoje NÃO é dia útil:
        RETORNA false
        
    amanhã = hoje + 1 dia

    SE amanhã NÃO é dia útil:
        // REGRA 1: Bloco
        cursor = amanhã
        ENQUANTO cursor não for dia útil:
            SE originalDueDate == cursor:
                RETORNA true
            cursor = cursor + 1 dia
        RETORNA false
        
    SENÃO:
        // REGRA 2: Simples
        efetivo = normalizeToBusinessDay(originalDueDate)
        diaAnterior = efetivo - 1 dia
        RETORNA (hoje == diaAnterior)
    

Classe: InvoicePreDueReminderNotification

Método getPayload():
    1. Verifica se hoje é dia útil (se não, retorna [])
    2. Busca faturas com status 'Unpaid'
    3. Filtra por métodos de pagamento elegíveis (PIX/Boleto)
    4. Para cada fatura:
       - Usa scheduler.shouldNotifyOneDayBeforeEffective()
       - Se true, adiciona ao payload
    5. Retorna array de payloads para envio
    

Casos de Uso Detalhados

Caso 1: Sexta-feira antes do fim de semana

Contexto:

  • Hoje: Sexta, 26/09/2025
  • Fatura A: vence Sábado, 27/09/2025
  • Fatura B: vence Domingo, 28/09/2025
  • Fatura C: vence Segunda, 29/09/2025

Processamento:

    Sexta (hoje):
      Amanhã = Sábado (não útil) ← REGRA 1
      Bloco = [Sábado, Domingo]
      
      Fatura A (vence Sábado): 
        Sábado está no bloco? SIM → NOTIFICA ✅
        
      Fatura B (vence Domingo):
        Domingo está no bloco? SIM → NOTIFICA ✅
        
      Fatura C (vence Segunda):
        Segunda está no bloco? NÃO → NÃO NOTIFICA ❌

    Segunda (próxima rodada):
      Amanhã = Terça (útil) ← REGRA 2
      
      Fatura C (vence Segunda):
        Efetivo = Segunda
        Dia anterior = Domingo
        Hoje (Segunda) == Domingo? NÃO → NÃO NOTIFICA ❌
        (Obs: não notifica porque o vencimento efetivo já passou)
    
Caso 2: Quinta antes de feriado prolongado

Contexto:

  • Hoje: Quinta, 10/09/2026
  • Sexta, 11/09: Feriado
  • Fatura D: vence Sexta, 11/09/2026 (feriado)
  • Fatura E: vence Segunda, 14/09/2026

Processamento:

    Quinta (hoje):
      Amanhã = Sexta (feriado, não útil) ← REGRA 1
      Bloco = [Sexta (feriado), Sábado, Domingo]
      
      Fatura D (vence Sexta feriado):
        Sexta está no bloco? SIM → NOTIFICA ✅
        
      Fatura E (vence Segunda):
        Segunda está no bloco? NÃO → NÃO NOTIFICA ❌

    Segunda, 14/09:
      Amanhã = Terça (útil) ← REGRA 2
      
      Fatura E (vence Segunda):
        Efetivo = Segunda, 14/09
        Dia anterior = Domingo, 13/09
        Hoje (Segunda) == Domingo? NÃO → NÃO NOTIFICA ❌
    
Caso 3: Terça normal

Contexto:

  • Hoje: Terça, 30/09/2025
  • Fatura F: vence Quarta, 01/10/2025

Processamento:

    Terça (hoje):
      Amanhã = Quarta (útil) ← REGRA 2
      
      Fatura F (vence Quarta):
        Efetivo = Quarta, 01/10
        Dia anterior = Terça, 30/09
        Hoje (Terça) == Terça? SIM → NOTIFICA ✅
    

Testes

Arquivo de Teste
    modules/addons/lknhooknotification/src/Notifications/Custom/tests_pre_due_scheduler_instancias2.php
    

Como executar:

    php modules/addons/lknhooknotification/src/Notifications/Custom/tests_pre_due_scheduler_instancias2.php
    

Configuração

Ativação da Notificação
  1. Acesse: Addons → Hook Notification → Notifications
  2. Localize: InvoicePreDueReminderNotification
  3. Clique em + Setup template
  4. Configure o template com os parâmetros disponíveis
Parâmetros Disponíveis no Template
  • {invoice_id} - ID da fatura
  • {client_first_name} - Primeiro nome do cliente
  • {order_details_action} - Payload completo para botão de pagamento (PIX/Boleto)
  • {invoice_pdf_url} - URL do PDF da fatura
  • {greetings} - Saudação contextual (bom dia/tarde/noite)
Requisitos
  • Métodos de pagamento suportados:
    • lknbbpix (PIX)
    • mmhospedagem_API_BS2 (Boleto)
  • Faturas com status: Unpaid
  • Faturas com total > 0
  • Execução: Hook DailyCronJob
  • : 1 dia DEPOIS do vencimento efetivo
  • Status: Overdue (vencida)
  • Objetivo: Cobrar faturas atrasadas

Observações Importantes

  • Não envia em finais de semana/feriados: A notificação só roda em dias úteis
  • Vencimento efetivo: Sempre considera o arrasto para o próximo dia útil
  • Sem compensação na Regra 2: Se o "dia anterior" cair em não útil, não envia
  • Compensação na Regra 1: Antecipa para o último dia útil antes do bloco
  • Cache: O factory do addon descobre automaticamente novas notificações
  • Helpers não são notificações: Schedulers na pasta Helpers/ não aparecem como notificações