R-009 — A filiação seguinte só é auto-aprovada com carteira definitiva

TLDR: Membership::FutureApprove auto-aprova a filiação seguinte apenas para quem tem users.issued_definitive_card = true. Sem a flag, a filiação seguinte não é auto-aprovada: ou ela assume a aprovação manual do admin — quando a vigente já concluiu o fluxo, conforme R-011 — ou fica intacta esperando análise de documento. O ramo automático envia membership_renewal_approved_email; o manual não envia e-mail próprio.

Given / When / Then

Dado um usuário com a filiação vigente sendo aprovada e uma filiação seguinte paga, pendente e not_issued Quando Membership::FutureApprove é executado Então a filiação seguinte é auto-aprovada (card_status: auto_issued, admin_approved_* e card_issued_* do usuário “Automático”) se o usuário tiver carteira definitiva; sem a flag ela não é auto-aprovada — e o membership_renewal_approved_email sai apenas no ramo automático

Tabela de decisão

issued_definitive_card Vigente já aprovada e com carteira emitida Ação na filiação seguinte card_status admin_approved_at E-mail
true qualquer automatic_approve! auto_issued preenchido (“Automático”) membership_renewal_approved_email
false sim, e há approver manual_approve!(approver) processing preenchido (o admin) o de aprovação, apontando para ela (R-011)
false não, ou sem approver nenhuma intacto intacto nenhum próprio
qualquer qualquer Guard bate: sem filiação seguinte, seguinte igual à recebida, já aprovada, ou carteira fora de not_issued intacto intacto nenhum

Restrições

  • O guard de entrada é preservado integralmente: next_membership && next_membership != current_membership && next_membership.admin_approved_at.nil? && next_membership.not_issued?. A comparação com current_membership existe porque User#next_membership devolve a própria vigente quando não há filiação posterior.
  • Os dois ramos anexam a foto do perfil na carteira: manual_approve! e automatic_approve! compartilham attach_profile_picture_to_card. Ver R-004.
  • manual_approve! aprova de fato: anexa a foto do perfil na carteira, e grava card_status: processing, documentation_status: ok, admin_approved_at e admin_approved_by. A semântica anterior era de reset (not_issued/pending, aprovação zerada) e foi invertida em 2026-09-10 — ver R-011. Continua diferente de UserProfile#manual_approve!, que mantém a semântica de reset.
  • manual_approve!(nil) é no-op: sem responsável, a filiação não é aprovada.
  • O ramo manual não auto-aprova ninguém: antes desta regra, o use case auto-aprovava a filiação seguinte de qualquer usuário, o que entregava carteira sem análise de documento a quem nunca teve carteira definitiva.
  • O ramo automático envia membership_renewal_approved_email para a filiação seguinte. O envio foi removido em 2026-09-08 e restaurado em 2026-09-09 — ver o adendo da spec.
  • Dois envios na moderação, com conteúdos distintos. Quando o chamador é AdminUserProfilesService#admin_approve_user_profile e o ramo é o automático, o membro recebe dois e-mails: para existir filiação seguinte distinta o usuário tem duas ou mais filiações, logo is_renewal? é true e o chamador também envia o e-mail da filiação vigente. Os dois diferem apenas pela vigência no corpo (valid_since/valid_until) — o nome e o register_number são compartilhados pelas duas filiações, e o assunto é o mesmo; ver o adendo de 2026-09-09. No ramo manual sai um e-mail só, apontando para a filiação aprovada. Já quando o chamador é AdminMembershipsService#admin_issue_card — que não envia e-mail nenhum — o do ramo automático é o único aviso. Ver R-007.
  • AdminMembershipsService#admin_issue_card não passa approver, então nunca alcança o ramo manual: a flag é gravada no próprio método, logo antes da chamada.
  • Como a flag ainda é false no momento da aprovação de documentos, quem não é auto-aprovado é re-avaliado depois, na emissão da carteira — ver R-007.

Código

app/models/membership/future_approve.rb

```ruby attributes :user, :current_membership, :approver

def call! next_membership = user.next_membership return Success() unless next_membership && next_membership != current_membership && next_membership.admin_approved_at.nil? && next_membership.not_issued?

unless user.issued_definitive_card? if approver && current_membership_approved_and_issued? next_membership.manual_approve!(approver)

  return Success(result: { approved_membership: next_membership })
end

return Success()   end

next_membership.automatic_approve!

Success() end ```

Teste vinculado

test/models/membership/future_approve_test.rb: - “auto-approves the next membership when the user has a definitive card” - “sends the renewal approved email when the user has a definitive card” - “sends no email when the user has no definitive card” - “leaves the next membership untouched when the current one has not finished its flow” - “approves the next membership when the current one is already approved and issued” - “does not approve the next membership when no approver is given” - “does not touch the next membership when it is already approved” - “does not touch the next membership when its card is not not_issued” - “does nothing when there is no next membership”

test/services/admin_user_profiles_service_test.rb: - “admin_approve_user_profile auto-approves the next membership (B) when pending and not_issued” - “admin_approve_user_profile does not auto-approve B when the user has no definitive card” - “admin_approve_user_profile sends two emails when B is auto-approved” - “admin_approve_user_profile sends one email when B is not auto-approved for lack of definitive card”

test/models/membership_test.rb: - “manual_approve! approves the membership and sends the card to the emission queue” - “manual_approve! attaches the profile picture to the card” - “manual_approve! does nothing when there is no approver”

Relacionados