Skip to content

Notificar o proponente após a confirmação do pagamento #578

Description

@pauloregis-sanoliver

Contexto

  • No upload de relatórios de pagamentos em resources/js/Pages/Notices/NoticesListPage.vue (linha 264), processado por InstallmentImportService, as parcelas dos projetos têm seus dados bancários e status atualizados
  • Quando uma parcela atinge o status "Pago" (exibido em PaymentTab.vue), o proponente/agente responsável pelo projeto deve ser notificado por e-mail sobre a efetivação do pagamento
  • Atualmente não existe uma estrutura desacoplada e genérica no banco de dados para auditar e registrar o histórico de todos os disparos de e-mails direcionados aos agentes
  • É necessário criar uma tabela de auditoria de e-mails que seja útil também para futuras notificações do sistema
  • Esta funcionalidade é crítica para transparência, compliance e comunicação adequada com os agentes culturais sobre o status de seus pagamentos

Objetivo

Como desenvolvedor backend
Quero implementar envio de e-mail automático na confirmação de pagamento de parcela e criar tabela de auditoria de e-mails
Para notificar os agentes sobre pagamentos efetuados e manter um histórico auditável de todas as comunicações por e-mail do sistema

Escopo

  • Criar migration para tabela agent_email_logs

  • Criar model AgentEmailLog com relacionamentos:

    • belongsTo Agent (agent_id)
    • belongsTo Project (project_id, nullable)
    • MorphTo para relacionamento polimórfico (related_type, related_id)
  • Configurar campos da tabela agent_email_logs:

    • agent_id (foreign key -> agents, not null)
    • project_id (nullable, foreign key -> projects)
    • related_type (varchar, nullable, polimorfismo)
    • related_id (bigint, nullable, polimorfismo)
    • recipient_email (varchar, not null)
    • recipient_name (varchar, nullable)
    • mail_class (varchar, not null)
    • event_type (varchar, not null, ex: installment_paid)
    • subject (varchar, not null)
    • status (varchar, default: 'queued', opções: queued, sent, failed)
    • error_message (text, nullable)
    • sent_at (timestamp, nullable)
    • timestamps padrão do Laravel
  • Adicionar índices nas colunas:

    • agent_id
    • project_id
    • related_type e related_id (índice composto)
    • status
    • event_type
  • Criar Mailable InstallmentPaidMail

  • Criar view de e-mail Blade com layout padronizado contendo:

    • Número do processo
    • Título do projeto
    • Número da parcela paga
    • Data de pagamento
    • Valor pago
    • Dados bancários (opcional)
  • Criar evento InstallmentPaidEvent

  • Criar Listener/Job SendInstallmentPaidEmail com ShouldQueue

  • Implementar gatilho no InstallmentImportService:

    • Após persistir alteração de status para "Pago" (STATUS_PAID_REGULAR)
    • Emitir evento InstallmentPaidEvent
    • Tratar para disparar notificação apenas na transição de status
    • Evitar disparos duplicados se planilha for reimportada
  • Implementar lógica para buscar e-mail do agente:

    • Via Project -> Agent -> latestSnapshot->email
    • Implementar fallback caso e-mail não seja encontrado
  • Implementar registro em agent_email_logs:

    • Criar registro com status 'queued' antes de enviar
    • Atualizar para 'sent' após envio bem-sucedido
    • Atualizar para 'failed' com error_message em caso de falha
  • Configurar fila (queue) para processamento assíncrono

  • Criar testes unitários para:

    • Model AgentEmailLog e relacionamentos
    • Evento InstallmentPaidEvent
    • Listener SendInstallmentPaidEmail
    • Mailable InstallmentPaidMail
  • Criar testes de feature para:

    • Disparo do evento na importação
    • Gravação do log de e-mail
    • Envio do e-mail
    • Prevenção de e-mails duplicados na reimportação
  • Documentar no README como testar o envio de e-mails

Fora de Escopo

  • Interface gráfica para visualização de logs de e-mail (será feito em outra issue)
  • Reenvio manual de e-mails falhos
  • Template customizável de e-mails por tipo de evento
  • Internacionalização do e-mail (i18n)
  • Notificações por outros canais (SMS, WhatsApp, push)
  • Sistema de preferências de notificação do agente

Critérios de Aceitação

  • Criação da Tabela AgentEmailLog
    Dado que executo as migrations no banco de dados
    Quando a migration create_agent_email_logs_table é processada
    Então a tabela deve ser criada com todos os campos especificados e índices pertinentes

  • Model AgentEmailLog com Relacionamentos
    Dado que o model AgentEmailLog foi criado
    Quando acesso os relacionamentos
    Então devo poder acessar agent, project e related (polimórfico) corretamente

  • Detecção de Status Pago na Importação
    Dado que uma planilha de pagamentos é importada
    Quando uma parcela atinge o status "Pago" (STATUS_PAID_REGULAR)
    Então o sistema deve identificar a transição de status e enfileirar a notificação por e-mail

  • Disparo de Evento InstallmentPaidEvent
    Dado que uma parcela foi marcada como paga
    Quando o status é persistido no banco
    Então o evento InstallmentPaidEvent deve ser emitido

  • Listener em Fila Assíncrona
    Dado que o evento foi emitido
    Quando o Listener SendInstallmentPaidEmail é processado
    Então a execução deve ser assíncrona via fila (ShouldQueue)

  • Conteúdo do E-mail
    Dado que o e-mail foi gerado
    Quando visualizo o conteúdo
    Então deve conter: número do processo, título do projeto, número da parcela, data de pagamento e valor pago

  • Registro de Auditoria - Sucesso
    Dado que um e-mail foi enviado com sucesso
    Quando verifico a tabela agent_email_logs
    Então deve existir um registro com status 'sent' e sent_at preenchido

  • Registro de Auditoria - Falha
    Dado que ocorreu um erro no envio do e-mail
    Quando verifico a tabela agent_email_logs
    Então deve existir um registro com status 'failed' e error_message preenchido

  • Prevenção de E-mails Duplicados
    Dado que reimporto a mesma planilha com parcela já paga
    Quando o processo é executado
    Então não devem ser gerados e-mails duplicados para a mesma parcela

  • Busca de E-mail do Agente
    Dado que preciso enviar notificação para um agente
    Quando o sistema busca o e-mail
    Então deve usar Project -> Agent -> latestSnapshot->email com fallback adequado

  • Performance em Lote
    Dado que uma planilha com múltiplos pagamentos é importada
    Quando o processo é executado
    Então o envio de e-mails deve ser processado via fila sem bloquear a importação

  • Testes Unitários
    Dado que executo os testes PHPUnit
    Quando os testes de AgentEmailLog, Evento, Listener e Mailable são executados
    Então todos devem passar com cobertura > 80%

  • Testes de Feature
    Dado que executo os testes de feature
    Quando os testes de disparo, gravação de log e envio são executados
    Então todos devem passar validando o fluxo completo

Observações

Estrutura da Migration:

Schema::create('agent_email_logs', function (Blueprint $table) {
    $table->id();
    $table->foreignId('agent_id')->constrained('agents')->onDelete('cascade');
    $table->foreignId('project_id')->nullable()->constrained('projects')->onDelete('set null');
    
    // Polimorfismo
    $table->string('related_type')->nullable();
    $table->unsignedBigInteger('related_id')->nullable();
    $table->index(['related_type', 'related_id']);
    
    // Destinatário
    $table->string('recipient_email');
    $table->string('recipient_name')->nullable();
    
    // Informações do e-mail
    $table->string('mail_class');
    $table->string('event_type');
    $table->string('subject');
    
    // Status do envio
    $table->string('status')->default('queued'); // queued, sent, failed
    $table->text('error_message')->nullable();
    $table->timestamp('sent_at')->nullable();
    
    $table->timestamps();
    
    // Índices para performance
    $table->index('agent_id');
    $table->index('project_id');
    $table->index('status');
    $table->index('event_type');
});

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions