R-006 — Suspensão vale só para a filiação suspensa
TLDR: Suspender uma filiação marca aquela filiação e mais nada. O perfil do usuário não herda a suspensão, e filiações posteriores do mesmo usuário seguem o fluxo normal.
user_profiles.documentation_statusfala só de documentação:pending,analysis,ok.
Given / When / Then
Dado um usuário com uma filiação suspensa (por exemplo, por chargeback) e uma filiação posterior paga e aprovada
Quando o apolo_membership é consultado para esse usuário
Então a resposta reflete a filiação posterior — apolo_access_status: true, suspended: false — e profile.status reflete apenas a documentação do perfil, nunca suspended
Tabela de decisão
| Cenário | suspended no payload |
apolo_access_status |
profile.status |
|---|---|---|---|
| Filiação anterior suspensa + posterior paga e aprovada | false |
true |
ok |
| Única filiação paga é a suspensa | true |
false |
status real da documentação |
| Duas filiações vigentes, uma suspensa e outra não | false (da não suspensa) |
true |
status real da documentação |
| Filiação suspensa + documentação não aprovada | true |
false |
pending |
Restrições
- A suspensão vive em
memberships.suspended/suspended_at, escrita porMembership#suspend!a partir do PAD. É a única fonte da verdade. UserProfile#calculate_documentation_statusnão consulta filiações suspensas. Derivar isso no nível do usuário fazia uma filiação suspensa antiga contaminar todas as posteriores, e — como o resultado é gravado porbefore_save :update_cached_fieldse peloafter_commitdeMembership— a marca era reescrita a cada save, tornando impossível aprovar a documentação pelo admin.- O valor
suspendedcontinua no enumdocumentation_statusdeUserProfile, junto comUserProfile#suspended?e a chave de localeuser_profile_documentation_statuses.SUSPENDED. Nada escreve esse valor hoje, mas linhas antigas ainda o carregam: não houve backfill, e removê-lo do enum faria o reader devolvernile quebrar o admin. - Os consumidores externos leem suspensão pelo campo
suspendeddo payload, por filiação — nunca porprofile.status. profile.statusé gate de PRO no trg-club:Subscriptions::Pro::ValidateEligibility#documentation_approved?exige== "ok"eExpireWhenIneligibledesativa a assinatura quando o resultado é negativo. Foi por esse caminho que o bug tirou os benefícios de quem tinha filiação nova válida. Qualquer mudança nesse campo precisa considerar o trg-club.Membership.activejá filtrasuspended: false, entãoUser#active_membershipsnão precisa — e não deve — checar o perfil.
Código
app/models/user_profile.rb
```ruby def calculate_documentation_status return :ok if admin_approved_at return :ok if personal_info_status && attachments_status && admin_approved_at return :analysis if user.current_onboarding&.in_analysis?
:pending end ```
app/models/user.rb
ruby
def active_memberships
memberships.active.order(created_at: :asc)
end
Teste vinculado
test/models/user_profile_test.rb — filiação suspensa não torna o perfil suspenso; filiação anterior suspensa com perfil aprovado resolve :ok
test/models/user_test.rb — active_memberships devolve a filiação vigente quando há uma anterior suspensa, e continua vazio quando a própria filiação está suspensa
test/serializers/membership_apolo_serializer_test.rb — payload com filiação anterior suspensa sai com suspended: false, apolo_access_status: true e profile.status == "ok"
Histórico
- 2026-09-01: a derivação foi removida. Uma cliente suspensa por chargeback em dezembro/2025 comprou nova filiação em julho/2026, teve a documentação aprovada e continuou bloqueada, porque
has_any_suspended_membership?considerava qualquer filiação suspensa — vencida ou arquivada, de qualquer época. Ver spec.