R-020 — Trial da campanha é travado quando há usuários cadastrados
TLDR: A partir do primeiro
UserTrialativo vinculado à campanha,Campaign.trialnão pode mais ser trocado nem esvaziado.Campaign.clean()recusa a mudança e o admin exibe o campo como leitura, com a contagem de usuários e o motivo.
Given / When / Then
Dado uma campanha com trial definido e ao menos um UserTrial ativo com campaign apontando para ela
Quando alguém altera Campaign.trial para outro trial (ou para vazio) e chama full_clean()
Então é levantado ValidationError no campo trial informando quantos usuários já se cadastraram
Dado a mesma campanha
Quando um administrador abre dash.*/admin/campaigns/campaign/<id>/change/
Então trial aparece como texto de leitura e a seção “Informações gerais” exibe o aviso com a contagem de usuários
Dado uma campanha sem trial definido, mesmo com UserTrial vinculados
Quando o trial é definido pela primeira vez
Então a alteração é permitida — a primeira definição não é uma troca
Dado uma campanha cujo único UserTrial foi soft-deletado
Quando o trial é trocado
Então a alteração é permitida — a contagem considera apenas registros ativos
Restrições
UserTrialgravatrialecampaigncomo colunas independentes:UserTrialService.create_user_trialcopia o trial vigente e deriva a janela detrial.duration_days. Trocar o trial da campanha depois não propaga nada- Propagar também não seria correto:
started_at/expires_atdoUserTrialsão registro histórico e imutáveis (R-018) - Os demais campos da campanha (
name,status,start_date,end_date) seguem editáveis com usuários cadastrados - Para oferecer outro trial ao mesmo público, crie uma nova campanha
- A validação vive em
Campaign.clean(), chamado peloModelFormdo admin — não roda emsave()/create()diretos por ORM, shell ou outros services. Hoje nenhum código escreveCampaign.trialfora do admin - A regra não cobre
Trialapagado:Campaign.trialusaon_delete=SET_NULLe esse caminho não passa porclean()
Teste vinculado
tests/campaigns/test_campaign_model.py — test_clean_blocks_trial_swap_when_campaign_has_user_trials, test_clean_blocks_clearing_trial_when_campaign_has_user_trials, test_clean_allows_first_trial_assignment_even_with_user_trials, test_clean_allows_trial_swap_when_user_trial_is_soft_deleted
tests/campaigns/test_admin.py — test_trial_is_readonly_when_campaign_has_user_trials, test_fieldset_warns_with_user_trials_count