-- ============================================================ -- SEED DE TESTE — AgenciaPsi -- ============================================================ -- Cria 10 terapeutas com pacientes, agendamentos, sessões, -- cancelamentos, remarcações, faltas, grupos, financeiro, etc. -- -- IMPORTANTE: -- 1) Os usuários (auth.users) devem ser criados via Supabase Auth -- ou via auth.users INSERT direto (requer service_role). -- Este script assume que os 10 users já existem no auth.users. -- -- 2) Execute este script com a service_role key no SQL Editor -- do Supabase (ou via psql com permissão). -- -- 3) Todos os UUIDs são fixos e determinísticos para facilitar -- depuração. Prefixo: -- Terapeutas: aaaaaaaa-0001..0010 -- Tenants: bbbbbbbb-0001..0010 -- Pacientes: cccccccc-0001..0050 -- Eventos: dddddddd-0001..0200 -- Financeiro: eeeeeeee-0001..0200 -- Grupos: ffffffff-0001..0020 -- Recorrência: 11111111-0001..0010 -- -- ============================================================ -- ──────────────────────────────────────────────────────────── -- 0. LIMPAR DADOS DE TESTE (idempotente) -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _tenant_ids uuid[] := ARRAY[ 'bbbbbbbb-0000-0000-0000-000000000001'::uuid, 'bbbbbbbb-0000-0000-0000-000000000002'::uuid, 'bbbbbbbb-0000-0000-0000-000000000003'::uuid, 'bbbbbbbb-0000-0000-0000-000000000004'::uuid, 'bbbbbbbb-0000-0000-0000-000000000005'::uuid, 'bbbbbbbb-0000-0000-0000-000000000006'::uuid, 'bbbbbbbb-0000-0000-0000-000000000007'::uuid, 'bbbbbbbb-0000-0000-0000-000000000008'::uuid, 'bbbbbbbb-0000-0000-0000-000000000009'::uuid, 'bbbbbbbb-0000-0000-0000-000000000010'::uuid ]; BEGIN -- Financeiro DELETE FROM public.financial_records WHERE tenant_id = ANY(_tenant_ids); -- Eventos DELETE FROM public.agenda_eventos WHERE tenant_id = ANY(_tenant_ids); -- Recorrências DELETE FROM public.recurrence_rules WHERE tenant_id = ANY(_tenant_ids); -- Grupos DELETE FROM public.patient_group_patient WHERE tenant_id = ANY(_tenant_ids); DELETE FROM public.patient_groups WHERE tenant_id = ANY(_tenant_ids); -- Pacientes DELETE FROM public.patients WHERE tenant_id = ANY(_tenant_ids); -- Notificações DELETE FROM public.notification_channels WHERE tenant_id = ANY(_tenant_ids); DELETE FROM public.notification_templates WHERE tenant_id = ANY(_tenant_ids); DELETE FROM public.notification_logs WHERE tenant_id = ANY(_tenant_ids); DELETE FROM public.notification_schedules WHERE tenant_id = ANY(_tenant_ids); -- Regras semanais DELETE FROM public.agenda_regras_semanais WHERE tenant_id = ANY(_tenant_ids); -- Serviços DELETE FROM public.services WHERE tenant_id = ANY(_tenant_ids); -- Tenant members DELETE FROM public.tenant_members WHERE tenant_id = ANY(_tenant_ids); -- Company profiles DELETE FROM public.company_profiles WHERE tenant_id = ANY(_tenant_ids); -- Tenants DELETE FROM public.tenants WHERE id = ANY(_tenant_ids); -- Profiles DELETE FROM public.profiles WHERE id IN ( 'aaaaaaaa-0000-0000-0000-000000000001'::uuid, 'aaaaaaaa-0000-0000-0000-000000000002'::uuid, 'aaaaaaaa-0000-0000-0000-000000000003'::uuid, 'aaaaaaaa-0000-0000-0000-000000000004'::uuid, 'aaaaaaaa-0000-0000-0000-000000000005'::uuid, 'aaaaaaaa-0000-0000-0000-000000000006'::uuid, 'aaaaaaaa-0000-0000-0000-000000000007'::uuid, 'aaaaaaaa-0000-0000-0000-000000000008'::uuid, 'aaaaaaaa-0000-0000-0000-000000000009'::uuid, 'aaaaaaaa-0000-0000-0000-000000000010'::uuid ); -- Auth users (requer service_role) DELETE FROM auth.users WHERE id IN ( 'aaaaaaaa-0000-0000-0000-000000000001'::uuid, 'aaaaaaaa-0000-0000-0000-000000000002'::uuid, 'aaaaaaaa-0000-0000-0000-000000000003'::uuid, 'aaaaaaaa-0000-0000-0000-000000000004'::uuid, 'aaaaaaaa-0000-0000-0000-000000000005'::uuid, 'aaaaaaaa-0000-0000-0000-000000000006'::uuid, 'aaaaaaaa-0000-0000-0000-000000000007'::uuid, 'aaaaaaaa-0000-0000-0000-000000000008'::uuid, 'aaaaaaaa-0000-0000-0000-000000000009'::uuid, 'aaaaaaaa-0000-0000-0000-000000000010'::uuid ); END $$; -- ──────────────────────────────────────────────────────────── -- 1. USUÁRIOS (auth.users) — 10 terapeutas -- ──────────────────────────────────────────────────────────── -- Desabilitar triggers que chamam funções inexistentes ALTER TABLE auth.users DISABLE TRIGGER ALL; -- Senha: Test@1234 (hash bcrypt) INSERT INTO auth.users ( id, instance_id, email, encrypted_password, email_confirmed_at, aud, role, raw_app_meta_data, raw_user_meta_data, created_at, updated_at ) VALUES ('aaaaaaaa-0000-0000-0000-000000000001', '00000000-0000-0000-0000-000000000000', 'terapeuta01@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Ana Beatriz"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000002', '00000000-0000-0000-0000-000000000000', 'terapeuta02@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Carlos Eduardo"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000003', '00000000-0000-0000-0000-000000000000', 'terapeuta03@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Fernanda Lima"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000004', '00000000-0000-0000-0000-000000000000', 'terapeuta04@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Gabriel Santos"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000005', '00000000-0000-0000-0000-000000000000', 'terapeuta05@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Juliana Alves"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000006', '00000000-0000-0000-0000-000000000000', 'terapeuta06@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Lucas Oliveira"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000007', '00000000-0000-0000-0000-000000000000', 'terapeuta07@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Mariana Costa"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000008', '00000000-0000-0000-0000-000000000000', 'terapeuta08@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Pedro Henrique"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000009', '00000000-0000-0000-0000-000000000000', 'terapeuta09@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dra. Renata Souza"}', now(), now()), ('aaaaaaaa-0000-0000-0000-000000000010', '00000000-0000-0000-0000-000000000000', 'terapeuta10@teste.agenciapsi.com', '$2a$10$PwGnTf1HMjHGZSM0YDi6ku7U7ZZZcXOiI4XOoFSqLJ3szGBTniCeG', now(), 'authenticated', 'authenticated', '{"provider":"email","providers":["email"]}', '{"full_name":"Dr. Thiago Nunes"}', now(), now()) ON CONFLICT (id) DO NOTHING; -- Identities (necessárias para login via email) INSERT INTO auth.identities (id, user_id, identity_data, provider, provider_id, last_sign_in_at, created_at, updated_at) SELECT id, id, jsonb_build_object('sub', id::text, 'email', email), 'email', id::text, now(), now(), now() FROM auth.users WHERE id IN ( 'aaaaaaaa-0000-0000-0000-000000000001','aaaaaaaa-0000-0000-0000-000000000002', 'aaaaaaaa-0000-0000-0000-000000000003','aaaaaaaa-0000-0000-0000-000000000004', 'aaaaaaaa-0000-0000-0000-000000000005','aaaaaaaa-0000-0000-0000-000000000006', 'aaaaaaaa-0000-0000-0000-000000000007','aaaaaaaa-0000-0000-0000-000000000008', 'aaaaaaaa-0000-0000-0000-000000000009','aaaaaaaa-0000-0000-0000-000000000010' ) ON CONFLICT DO NOTHING; -- Reabilitar triggers ALTER TABLE auth.users ENABLE TRIGGER ALL; -- ──────────────────────────────────────────────────────────── -- 2. PROFILES -- ──────────────────────────────────────────────────────────── INSERT INTO public.profiles (id, full_name, role, phone, bio, account_type) VALUES ('aaaaaaaa-0000-0000-0000-000000000001', 'Dra. Ana Beatriz', 'tenant_member', '(11) 91234-0001', 'Psicóloga clínica — TCC e EMDR', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000002', 'Dr. Carlos Eduardo', 'tenant_member', '(11) 91234-0002', 'Psicólogo — Psicanálise', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000003', 'Dra. Fernanda Lima', 'tenant_member', '(16) 91234-0003', 'Psicóloga infantil — Ludoterapia', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000004', 'Dr. Gabriel Santos', 'tenant_member', '(16) 91234-0004', 'Psicólogo — Gestalt-terapia', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000005', 'Dra. Juliana Alves', 'tenant_member', '(21) 91234-0005', 'Psicóloga — Neuropsicologia', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000006', 'Dr. Lucas Oliveira', 'tenant_member', '(21) 91234-0006', 'Psicólogo — Terapia Sistêmica', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000007', 'Dra. Mariana Costa', 'tenant_member', '(31) 91234-0007', 'Psicóloga — Humanismo', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000008', 'Dr. Pedro Henrique', 'tenant_member', '(31) 91234-0008', 'Psicólogo — Análise do Comportamento', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000009', 'Dra. Renata Souza', 'tenant_member', '(41) 91234-0009', 'Psicóloga — Psicossomática', 'therapist'), ('aaaaaaaa-0000-0000-0000-000000000010', 'Dr. Thiago Nunes', 'tenant_member', '(41) 91234-0010', 'Psicólogo — Terapia Cognitiva', 'therapist') ON CONFLICT (id) DO UPDATE SET full_name = EXCLUDED.full_name, role = EXCLUDED.role; -- ──────────────────────────────────────────────────────────── -- 3. TENANTS + MEMBERS -- ──────────────────────────────────────────────────────────── INSERT INTO public.tenants (id, name, kind) VALUES ('bbbbbbbb-0000-0000-0000-000000000001', 'Consultório Dra. Ana Beatriz', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000002', 'Consultório Dr. Carlos Eduardo', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000003', 'Consultório Dra. Fernanda Lima', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000004', 'Consultório Dr. Gabriel Santos', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000005', 'Consultório Dra. Juliana Alves', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000006', 'Consultório Dr. Lucas Oliveira', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000007', 'Consultório Dra. Mariana Costa', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000008', 'Consultório Dr. Pedro Henrique', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000009', 'Consultório Dra. Renata Souza', 'therapist'), ('bbbbbbbb-0000-0000-0000-000000000010', 'Consultório Dr. Thiago Nunes', 'therapist') ON CONFLICT (id) DO NOTHING; INSERT INTO public.tenant_members (tenant_id, user_id, role, status) SELECT ('bbbbbbbb-0000-0000-0000-00000000000' || i)::uuid, ('aaaaaaaa-0000-0000-0000-00000000000' || i)::uuid, 'tenant_admin', 'active' FROM generate_series(1, 9) AS s(i) UNION ALL SELECT 'bbbbbbbb-0000-0000-0000-000000000010'::uuid, 'aaaaaaaa-0000-0000-0000-000000000010'::uuid, 'tenant_admin', 'active' ON CONFLICT DO NOTHING; -- ──────────────────────────────────────────────────────────── -- 4. SERVIÇOS (1 serviço padrão por terapeuta) -- ──────────────────────────────────────────────────────────── INSERT INTO public.services (id, owner_id, tenant_id, name, price, duration_min, active) SELECT ('99999999-0000-0000-0000-00000000000' || i)::uuid, ('aaaaaaaa-0000-0000-0000-00000000000' || i)::uuid, ('bbbbbbbb-0000-0000-0000-00000000000' || i)::uuid, 'Sessão Individual', (150 + i * 10)::numeric, 50, true FROM generate_series(1, 9) AS s(i) UNION ALL SELECT '99999999-0000-0000-0000-000000000010'::uuid, 'aaaaaaaa-0000-0000-0000-000000000010'::uuid, 'bbbbbbbb-0000-0000-0000-000000000010'::uuid, 'Sessão Individual', 250::numeric, 50, true ON CONFLICT DO NOTHING; -- ──────────────────────────────────────────────────────────── -- 5. PACIENTES — 5 por terapeuta = 50 pacientes -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _nomes text[] := ARRAY[ 'Maria Silva','João Pereira','Camila Rocha','Rafael Dias','Larissa Melo', 'Bruno Costa','Amanda Ferreira','Felipe Souza','Isabela Nunes','Diego Almeida', 'Patrícia Lima','Rodrigo Santos','Letícia Araujo','Gustavo Ribeiro','Bianca Carvalho', 'Matheus Gomes','Natália Barbosa','André Vieira','Carolina Martins','Lucas Teixeira', 'Aline Pinto','Henrique Moura','Vanessa Cardoso','Marcos Fernandes','Tatiana Lopes', 'Thiago Nascimento','Juliana Duarte','Eduardo Correia','Fernanda Monteiro','Paulo Campos', 'Simone Reis','Ricardo Azevedo','Debora Mendes','Alexandre Freitas','Sandra Oliveira', 'Daniel Cunha','Priscila Moreira','Roberto Andrade','Cláudia Batista','Leandro Rezende', 'Adriana Sousa','Vinicius Castro','Luciana Pereira','Fabio Miranda','Elaine Barros', 'Renato Faria','Cristina Machado','Marcelo Prado','Gabriela Assis','Sergio Nogueira' ]; _phones text[] := ARRAY[ '(11) 98765-1001','(11) 98765-1002','(11) 98765-1003','(11) 98765-1004','(11) 98765-1005', '(11) 98765-1006','(11) 98765-1007','(11) 98765-1008','(11) 98765-1009','(11) 98765-1010', '(16) 98765-1011','(16) 98765-1012','(16) 98765-1013','(16) 98765-1014','(16) 98765-1015', '(16) 98765-1016','(16) 98765-1017','(16) 98765-1018','(16) 98765-1019','(16) 98765-1020', '(21) 98765-1021','(21) 98765-1022','(21) 98765-1023','(21) 98765-1024','(21) 98765-1025', '(21) 98765-1026','(21) 98765-1027','(21) 98765-1028','(21) 98765-1029','(21) 98765-1030', '(31) 98765-1031','(31) 98765-1032','(31) 98765-1033','(31) 98765-1034','(31) 98765-1035', '(31) 98765-1036','(31) 98765-1037','(31) 98765-1038','(31) 98765-1039','(31) 98765-1040', '(41) 98765-1041','(41) 98765-1042','(41) 98765-1043','(41) 98765-1044','(41) 98765-1045', '(41) 98765-1046','(41) 98765-1047','(41) 98765-1048','(41) 98765-1049','(41) 98765-1050' ]; _statuses text[] := ARRAY['Ativo','Ativo','Ativo','Ativo','Inativo']; _t int; _p int; _idx int; _pid uuid; _oid uuid; _tid uuid; _mid uuid; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; -- Buscar o id do tenant_member para este user/tenant SELECT id INTO _mid FROM public.tenant_members WHERE tenant_id = _tid AND user_id = _oid LIMIT 1; FOR _p IN 1..5 LOOP _idx := (_t - 1) * 5 + _p; _pid := ('cccccccc-0000-0000-0000-' || lpad(_idx::text, 12, '0'))::uuid; INSERT INTO public.patients ( id, nome_completo, email_principal, telefone, status, owner_id, tenant_id, responsible_member_id, data_nascimento, genero, cidade, estado ) VALUES ( _pid, _nomes[_idx], 'paciente' || _idx || '@teste.agenciapsi.com', _phones[_idx], _statuses[_p], _oid, _tid, _mid, '1985-01-01'::date + (_idx * 120 || ' days')::interval, CASE WHEN _idx % 2 = 0 THEN 'Feminino' ELSE 'Masculino' END, CASE WHEN _t <= 2 THEN 'são Paulo' WHEN _t <= 4 THEN 'são Carlos' WHEN _t <= 6 THEN 'Rio de Janeiro' WHEN _t <= 8 THEN 'Belo Horizonte' ELSE 'Curitiba' END, CASE WHEN _t <= 2 THEN 'SP' WHEN _t <= 4 THEN 'SP' WHEN _t <= 6 THEN 'RJ' WHEN _t <= 8 THEN 'MG' ELSE 'PR' END ) ON CONFLICT (id) DO NOTHING; END LOOP; END LOOP; END $$; -- ──────────────────────────────────────────────────────────── -- 6. GRUPOS DE PACIENTES — 2 por terapeuta -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _t int; _oid uuid; _tid uuid; _g1 uuid; _g2 uuid; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; _g1 := ('ffffffff-0000-0000-0000-' || lpad(((_t-1)*2+1)::text, 12, '0'))::uuid; _g2 := ('ffffffff-0000-0000-0000-' || lpad(((_t-1)*2+2)::text, 12, '0'))::uuid; INSERT INTO public.patient_groups (id, owner_id, tenant_id, nome, cor, is_active) VALUES (_g1, _oid, _tid, 'Adultos', '#6366f1', true), (_g2, _oid, _tid, 'Crianças', '#f59e0b', true) ON CONFLICT (id) DO NOTHING; -- Adicionar 3 pacientes ao grupo Adultos, 2 ao grupo Crianças INSERT INTO public.patient_group_patient (patient_id, patient_group_id, tenant_id) SELECT ('cccccccc-0000-0000-0000-' || lpad(((_t-1)*5 + p)::text, 12, '0'))::uuid, CASE WHEN p <= 3 THEN _g1 ELSE _g2 END, _tid FROM generate_series(1, 5) AS s(p) ON CONFLICT DO NOTHING; END LOOP; END $$; -- ──────────────────────────────────────────────────────────── -- 7. AGENDA — Eventos do último mês + próxima semana -- Tipos: realizado, faltou, cancelado, agendado, remarcar -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _t int; _p int; _d int; _idx int; _oid uuid; _tid uuid; _pid uuid; _eid uuid; _status text; _statuses text[] := ARRAY['realizado','realizado','realizado','faltou','cancelado','realizado','agendado','remarcar','realizado','realizado', 'realizado','realizado','faltou','realizado','cancelado','agendado','agendado','realizado','realizado','realizado']; _dia date; _hora time; _horas time[] := ARRAY['08:00','09:00','10:00','11:00','14:00']; _evt_counter int := 0; _modalidade text; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; -- 4 semanas de sessões (seg-sex), 1 sessão por paciente por semana FOR _d IN 0..27 LOOP _dia := (current_date - interval '28 days' + (_d || ' days')::interval)::date; -- Pular finais de semana IF extract(dow FROM _dia) IN (0, 6) THEN CONTINUE; END IF; FOR _p IN 1..5 LOOP -- Cada paciente tem sessão 1x/semana (dias alternados) IF (_d % 5) != (_p - 1) THEN CONTINUE; END IF; _evt_counter := _evt_counter + 1; _idx := (_t - 1) * 5 + _p; _pid := ('cccccccc-0000-0000-0000-' || lpad(_idx::text, 12, '0'))::uuid; _eid := ('dddddddd-0000-0000-0000-' || lpad(_evt_counter::text, 12, '0'))::uuid; _hora := _horas[_p]; _status := _statuses[(_evt_counter - 1) % 20 + 1]; _modalidade := CASE WHEN _p <= 3 THEN 'presencial' ELSE 'online' END; -- Eventos futuros devem ser 'agendado' IF _dia > current_date THEN _status := 'agendado'; END IF; INSERT INTO public.agenda_eventos ( id, owner_id, tenant_id, tipo, status, patient_id, terapeuta_id, inicio_em, fim_em, titulo, modalidade ) VALUES ( _eid, _oid, _tid, 'sessao'::tipo_evento_agenda, _status::status_evento_agenda, _pid, _oid, (_dia || ' ' || _hora)::timestamptz, (_dia || ' ' || _hora)::timestamptz + interval '50 minutes', 'Sessão — ' || (SELECT nome_completo FROM public.patients WHERE id = _pid), _modalidade ) ON CONFLICT (id) DO NOTHING; END LOOP; END LOOP; END LOOP; RAISE NOTICE 'Total de eventos criados: %', _evt_counter; END $$; -- ──────────────────────────────────────────────────────────── -- 8. FINANCEIRO — 1 lançamento por evento realizado -- ──────────────────────────────────────────────────────────── INSERT INTO public.financial_records ( id, owner_id, tenant_id, type, amount, final_amount, description, category, payment_method, status, paid_at, due_date, agenda_evento_id, patient_id ) SELECT gen_random_uuid(), ae.owner_id, ae.tenant_id, 'receita', v.amt, v.amt, CASE WHEN ae.status = 'realizado' THEN 'Sessão realizada' WHEN ae.status = 'faltou' THEN 'Falta — cobrança parcial' ELSE 'Sessão cancelada' END, 'Sessão', CASE WHEN random() > 0.5 THEN 'pix' ELSE 'cartao_credito' END, CASE WHEN ae.status = 'realizado' THEN 'paid' WHEN ae.status = 'faltou' THEN 'pending' ELSE 'cancelled' END, CASE WHEN ae.status = 'realizado' THEN ae.inicio_em ELSE NULL END, ae.inicio_em::date, ae.id, ae.patient_id FROM public.agenda_eventos ae CROSS JOIN LATERAL ( SELECT CASE WHEN ae.status = 'realizado' THEN (150 + (random() * 100)::int)::numeric WHEN ae.status = 'faltou' THEN (75 + (random() * 50)::int)::numeric ELSE 0 END AS amt ) v WHERE ae.tenant_id IN ( SELECT id FROM public.tenants WHERE id::text LIKE 'bbbbbbbb%' ) AND ae.status IN ('realizado', 'faltou', 'cancelado'); -- ──────────────────────────────────────────────────────────── -- 9. REGRAS SEMANAIS — horários de atendimento -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _t int; _d int; _oid uuid; _tid uuid; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; -- Segunda a sexta, 8h-12h e 14h-18h FOR _d IN 1..5 LOOP INSERT INTO public.agenda_regras_semanais (owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, modalidade, ativo) VALUES (_oid, _tid, _d, '08:00', '12:00', 'ambos', true), (_oid, _tid, _d, '14:00', '18:00', 'ambos', true) ON CONFLICT DO NOTHING; END LOOP; END LOOP; END $$; -- ──────────────────────────────────────────────────────────── -- 10. RECORRÊNCIAS — 1 por terapeuta (paciente 1) -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _t int; _oid uuid; _tid uuid; _pid uuid; _rid uuid; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; _pid := ('cccccccc-0000-0000-0000-' || lpad(((_t-1)*5 + 1)::text, 12, '0'))::uuid; _rid := ('11111111-0000-0000-0000-' || lpad(_t::text, 12, '0'))::uuid; INSERT INTO public.recurrence_rules ( id, tenant_id, owner_id, patient_id, type, weekdays, start_time, end_time, start_date, open_ended, modalidade, status ) VALUES ( _rid, _tid, _oid, _pid, 'weekly', ARRAY[(_t % 5) + 1]::smallint[], '09:00', '09:50', current_date - interval '30 days', true, 'presencial', 'ativo' ) ON CONFLICT (id) DO NOTHING; END LOOP; END $$; -- ──────────────────────────────────────────────────────────── -- 11. NOTIFICATION SCHEDULES — 1 set por terapeuta -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _t int; _oid uuid; _tid uuid; BEGIN FOR _t IN 1..10 LOOP IF _t < 10 THEN _oid := ('aaaaaaaa-0000-0000-0000-00000000000' || _t)::uuid; _tid := ('bbbbbbbb-0000-0000-0000-00000000000' || _t)::uuid; ELSE _oid := 'aaaaaaaa-0000-0000-0000-000000000010'::uuid; _tid := 'bbbbbbbb-0000-0000-0000-000000000010'::uuid; END IF; INSERT INTO public.notification_schedules ( tenant_id, owner_id, schedule_key, event_type, trigger_type, offset_minutes, whatsapp_enabled, email_enabled, is_active ) VALUES (_tid, _oid, 'lembrete_24h', 'lembrete_sessao', 'before_event', 1440, true, true, true), (_tid, _oid, 'lembrete_2h', 'lembrete_sessao', 'before_event', 120, true, false, true), (_tid, _oid, 'confirmacao', 'confirmacao_sessao', 'immediate', 0, true, true, true), (_tid, _oid, 'cancelamento', 'cancelamento_sessao', 'immediate', 0, true, true, true) ON CONFLICT DO NOTHING; END LOOP; END $$; -- ════════════════════════════════════════════════════════════ -- 12. DADOS PARA terapeuta@agenciapsi.com.br -- ════════════════════════════════════════════════════════════ -- 20 pacientes, 10+ grupos, 10+ eventos de cada status, -- 10+ lançamentos, 10+ regras semanais, 10+ recorrências, -- 10+ notificações -- ──────────────────────────────────────────────────────────── -- 12a. LIMPEZA dos dados de teste deste usuário DO $$ DECLARE _oid uuid; _tid uuid; BEGIN SELECT id INTO _oid FROM auth.users WHERE email = 'terapeuta@agenciapsi.com.br'; IF _oid IS NULL THEN RAISE NOTICE 'Usuário terapeuta@agenciapsi.com.br não encontrado — pulando limpeza'; RETURN; END IF; SELECT t.id INTO _tid FROM public.tenants t JOIN public.tenant_members tm ON tm.tenant_id = t.id WHERE tm.user_id = _oid LIMIT 1; IF _tid IS NULL THEN RAISE NOTICE 'Tenant não encontrado para terapeuta@agenciapsi.com.br — pulando limpeza'; RETURN; END IF; -- Limpar apenas dados de seed (pacientes com email @seed.teste) DELETE FROM public.financial_records WHERE tenant_id = _tid AND description LIKE '%[SEED]%'; DELETE FROM public.agenda_eventos WHERE tenant_id = _tid AND titulo LIKE '%[SEED]%'; DELETE FROM public.recurrence_rules WHERE tenant_id = _tid AND observacoes = '[SEED]'; DELETE FROM public.patient_group_patient WHERE tenant_id = _tid AND patient_id IN ( SELECT id FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com' ); DELETE FROM public.patient_groups WHERE tenant_id = _tid AND nome LIKE '%[SEED]%'; DELETE FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com'; DELETE FROM public.agenda_regras_semanais WHERE tenant_id = _tid AND owner_id = _oid; DELETE FROM public.notification_schedules WHERE tenant_id = _tid AND owner_id = _oid; RAISE NOTICE 'Limpeza concluída para terapeuta@agenciapsi.com.br (tenant: %)', _tid; END $$; -- 12b. INSERIR DADOS DO $$ DECLARE _oid uuid; _tid uuid; _mid uuid; _pid uuid; _eid uuid; _gid uuid; _i int; _d int; _dia date; _hora time; _status text; _evt_counter int := 0; _nomes text[] := ARRAY[ 'Amanda Rodrigues','Bruno Ferreira','Camila Teixeira','Diego Nascimento','Elisa Cardoso', 'Felipe Moura','Giovana Ribeiro','Hugo Martins','Isabela Correia','João Vitor Almeida', 'Karen Oliveira','Leonardo Duarte','Marina Santos','Nicolas Costa','Olívia Mendes', 'Paulo Ricardo','Quésia Lima','Rafael Araújo','Sofia Carvalho','Tomás Barbosa' ]; _phones text[] := ARRAY[ '(16) 99001-0001','(16) 99001-0002','(16) 99001-0003','(16) 99001-0004','(16) 99001-0005', '(16) 99001-0006','(16) 99001-0007','(16) 99001-0008','(16) 99001-0009','(16) 99001-0010', '(16) 99001-0011','(16) 99001-0012','(16) 99001-0013','(16) 99001-0014','(16) 99001-0015', '(16) 99001-0016','(16) 99001-0017','(16) 99001-0018','(16) 99001-0019','(16) 99001-0020' ]; _cidades text[] := ARRAY[ 'são Carlos','são Carlos','Araraquara','Araraquara','Ribeirão Preto', 'Ribeirão Preto','são Carlos','são Carlos','Araraquara','Araraquara', 'são Carlos','são Carlos','Ribeirão Preto','Ribeirão Preto','são Carlos', 'são Carlos','Araraquara','Araraquara','Ribeirão Preto','são Carlos' ]; _generos text[] := ARRAY[ 'Feminino','Masculino','Feminino','Masculino','Feminino', 'Masculino','Feminino','Masculino','Feminino','Masculino', 'Feminino','Masculino','Feminino','Masculino','Feminino', 'Masculino','Feminino','Masculino','Feminino','Masculino' ]; _grupo_nomes text[] := ARRAY[ 'Adultos [SEED]','Adolescentes [SEED]','Crianças [SEED]','Casais [SEED]','Idosos [SEED]', 'TCC [SEED]','Psicanálise [SEED]','Gestalt [SEED]','EMDR [SEED]','Grupo Familiar [SEED]' ]; _grupo_cores text[] := ARRAY[ '#6366f1','#f59e0b','#10b981','#ef4444','#8b5cf6', '#3b82f6','#ec4899','#14b8a6','#f97316','#64748b' ]; -- Status cíclicos para eventos passados _statuses text[] := ARRAY[ 'realizado','realizado','realizado','faltou','cancelado', 'realizado','realizado','remarcar','realizado','faltou', 'realizado','realizado','realizado','cancelado','realizado', 'realizado','faltou','realizado','realizado','realizado' ]; _horas time[] := ARRAY['08:00','09:00','10:00','11:00','14:00','15:00','16:00','17:00']; BEGIN -- Buscar user SELECT id INTO _oid FROM auth.users WHERE email = 'terapeuta@agenciapsi.com.br'; IF _oid IS NULL THEN RAISE NOTICE 'Usuário terapeuta@agenciapsi.com.br não encontrado — abortando seed'; RETURN; END IF; -- Buscar tenant SELECT t.id INTO _tid FROM public.tenants t JOIN public.tenant_members tm ON tm.tenant_id = t.id WHERE tm.user_id = _oid LIMIT 1; IF _tid IS NULL THEN RAISE NOTICE 'Tenant não encontrado — abortando seed'; RETURN; END IF; -- Buscar member_id SELECT id INTO _mid FROM public.tenant_members WHERE tenant_id = _tid AND user_id = _oid LIMIT 1; RAISE NOTICE 'Seed para: % / tenant: % / member: %', _oid, _tid, _mid; -- ── 20 PACIENTES ────────────────────────────────────────── FOR _i IN 1..20 LOOP _pid := gen_random_uuid(); INSERT INTO public.patients ( id, nome_completo, email_principal, telefone, status, owner_id, tenant_id, responsible_member_id, data_nascimento, genero, cidade, estado ) VALUES ( _pid, _nomes[_i], 'seed.paciente' || _i || '@seed.teste.agenciapsi.com', _phones[_i], CASE WHEN _i <= 16 THEN 'Ativo' WHEN _i <= 18 THEN 'Inativo' ELSE 'Alta' END, _oid, _tid, _mid, ('1980-01-01'::date + (_i * 400 || ' days')::interval)::date, _generos[_i], _cidades[_i], 'SP' ); END LOOP; -- ── 10 GRUPOS ───────────────────────────────────────────── FOR _i IN 1..10 LOOP _gid := gen_random_uuid(); INSERT INTO public.patient_groups (id, owner_id, tenant_id, nome, cor, is_active) VALUES (_gid, _oid, _tid, _grupo_nomes[_i], _grupo_cores[_i], true); -- Adicionar 2 pacientes por grupo INSERT INTO public.patient_group_patient (patient_id, patient_group_id, tenant_id) SELECT p.id, _gid, _tid FROM public.patients p WHERE p.tenant_id = _tid AND p.email_principal LIKE '%@seed.teste.agenciapsi.com' ORDER BY p.nome_completo OFFSET ((_i - 1) * 2) LIMIT 2; END LOOP; -- ── EVENTOS (últimos 42 dias + próxima semana) ──────────── -- Garante pelo menos: 10 realizado, 10 faltou, 10 cancelado, -- 10 agendado, 10 remarcar _evt_counter := 0; FOR _d IN 0..48 LOOP _dia := (current_date - interval '42 days' + (_d || ' days')::interval)::date; IF extract(dow FROM _dia) IN (0, 6) THEN CONTINUE; END IF; FOR _i IN 1..4 LOOP _evt_counter := _evt_counter + 1; _hora := _horas[((_evt_counter - 1) % 8) + 1]; -- Pegar um paciente cíclico SELECT id INTO _pid FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com' ORDER BY nome_completo OFFSET ((_evt_counter - 1) % 20) LIMIT 1; IF _pid IS NULL THEN CONTINUE; END IF; -- Status: passado = cíclico, futuro = agendado IF _dia > current_date THEN _status := 'agendado'; ELSE _status := _statuses[((_evt_counter - 1) % 20) + 1]; END IF; _eid := gen_random_uuid(); BEGIN INSERT INTO public.agenda_eventos ( id, owner_id, tenant_id, tipo, status, patient_id, terapeuta_id, inicio_em, fim_em, titulo, modalidade ) VALUES ( _eid, _oid, _tid, 'sessao'::tipo_evento_agenda, _status::status_evento_agenda, _pid, _oid, (_dia || ' ' || _hora)::timestamptz, (_dia || ' ' || _hora)::timestamptz + interval '50 minutes', '[SEED] Sessão — ' || _nomes[((_evt_counter - 1) % 20) + 1], CASE WHEN _i <= 2 THEN 'presencial' ELSE 'online' END ); EXCEPTION WHEN exclusion_violation THEN -- Horário já ocupado, pular NULL; END; END LOOP; END LOOP; RAISE NOTICE 'Eventos tentados: % (alguns podem ter sido pulados por sobreposição)', _evt_counter; -- ── FINANCEIRO ──────────────────────────────────────────── INSERT INTO public.financial_records ( id, owner_id, tenant_id, type, amount, final_amount, description, category, payment_method, status, paid_at, due_date, agenda_evento_id, patient_id ) SELECT gen_random_uuid(), ae.owner_id, ae.tenant_id, 'receita', v.amt, v.amt, '[SEED] ' || CASE WHEN ae.status = 'realizado'::status_evento_agenda THEN 'Sessão realizada' WHEN ae.status = 'faltou'::status_evento_agenda THEN 'Falta — cobrança parcial' ELSE 'Sessão cancelada' END, 'Sessão', CASE WHEN random() > 0.5 THEN 'pix' ELSE 'cartao_credito' END, CASE WHEN ae.status = 'realizado'::status_evento_agenda THEN 'paid' WHEN ae.status = 'faltou'::status_evento_agenda THEN 'pending' ELSE 'cancelled' END, CASE WHEN ae.status = 'realizado'::status_evento_agenda THEN ae.inicio_em ELSE NULL END, ae.inicio_em::date, ae.id, ae.patient_id FROM public.agenda_eventos ae CROSS JOIN LATERAL ( SELECT CASE WHEN ae.status = 'realizado'::status_evento_agenda THEN (150 + (random() * 100)::int)::numeric WHEN ae.status = 'faltou'::status_evento_agenda THEN (75 + (random() * 50)::int)::numeric ELSE 0 END AS amt ) v WHERE ae.tenant_id = _tid AND ae.titulo LIKE '[SEED]%' AND ae.status IN ('realizado'::status_evento_agenda, 'faltou'::status_evento_agenda, 'cancelado'::status_evento_agenda); -- ── REGRAS SEMANAIS (10 — manhã e tarde, seg-sex) ──────── INSERT INTO public.agenda_regras_semanais (owner_id, tenant_id, dia_semana, hora_inicio, hora_fim, modalidade, ativo) VALUES (_oid, _tid, 1, '08:00', '12:00', 'ambos', true), (_oid, _tid, 1, '14:00', '18:00', 'ambos', true), (_oid, _tid, 2, '08:00', '12:00', 'ambos', true), (_oid, _tid, 2, '14:00', '18:00', 'ambos', true), (_oid, _tid, 3, '08:00', '12:00', 'ambos', true), (_oid, _tid, 3, '14:00', '18:00', 'ambos', true), (_oid, _tid, 4, '08:00', '12:00', 'ambos', true), (_oid, _tid, 4, '14:00', '18:00', 'ambos', true), (_oid, _tid, 5, '08:00', '12:00', 'ambos', true), (_oid, _tid, 5, '14:00', '18:00', 'ambos', true) ON CONFLICT DO NOTHING; -- ── RECORRÊNCIAS (10 pacientes com sessão semanal) ──────── FOR _i IN 1..10 LOOP SELECT id INTO _pid FROM public.patients WHERE tenant_id = _tid AND email_principal LIKE '%@seed.teste.agenciapsi.com' ORDER BY nome_completo OFFSET (_i - 1) LIMIT 1; IF _pid IS NULL THEN CONTINUE; END IF; INSERT INTO public.recurrence_rules ( id, tenant_id, owner_id, patient_id, type, weekdays, start_time, end_time, start_date, open_ended, modalidade, status, observacoes ) VALUES ( gen_random_uuid(), _tid, _oid, _pid, 'weekly', ARRAY[_i % 5]::int[], ('08:00'::time + ((_i - 1) * 60 || ' minutes')::interval), ('08:50'::time + ((_i - 1) * 60 || ' minutes')::interval), current_date - interval '30 days', true, CASE WHEN _i <= 5 THEN 'presencial' ELSE 'online' END, 'ativo', '[SEED]' ); END LOOP; -- ── NOTIFICATION SCHEDULES (10) ─────────────────────────── INSERT INTO public.notification_schedules ( tenant_id, owner_id, schedule_key, event_type, trigger_type, offset_minutes, whatsapp_enabled, email_enabled, is_active ) VALUES (_tid, _oid, 'lembrete_24h', 'lembrete_sessao', 'before_event', 1440, true, true, true), (_tid, _oid, 'lembrete_2h', 'lembrete_sessao', 'before_event', 120, true, false, true), (_tid, _oid, 'lembrete_30min', 'lembrete_sessao', 'before_event', 30, true, false, true), (_tid, _oid, 'confirmacao', 'confirmacao_sessao', 'immediate', 0, true, true, true), (_tid, _oid, 'cancelamento', 'cancelamento_sessao', 'immediate', 0, true, true, true), (_tid, _oid, 'lembrete_48h', 'lembrete_sessao', 'before_event', 2880, false, true, true), (_tid, _oid, 'lembrete_1h', 'lembrete_sessao', 'before_event', 60, true, false, true), (_tid, _oid, 'confirmacao_email', 'confirmacao_sessao', 'immediate', 0, false, true, true), (_tid, _oid, 'cancel_email', 'cancelamento_sessao', 'immediate', 0, false, true, true), (_tid, _oid, 'lembrete_1semana', 'lembrete_sessao', 'before_event', 10080,false, true, false) ON CONFLICT DO NOTHING; RAISE NOTICE '══════════════════════════════════════════'; RAISE NOTICE ' SEED terapeuta@agenciapsi.com.br COMPLETO'; RAISE NOTICE ' Pacientes: 20'; RAISE NOTICE ' Grupos: 10'; RAISE NOTICE ' Eventos: %', _evt_counter; RAISE NOTICE ' Regras semanais: 10'; RAISE NOTICE ' Recorrências: 10'; RAISE NOTICE ' Notificações: 10'; RAISE NOTICE '══════════════════════════════════════════'; END $$; -- ──────────────────────────────────────────────────────────── -- 13. RESUMO -- ──────────────────────────────────────────────────────────── DO $$ DECLARE _users int; _tenants int; _patients int; _events int; _records int; _groups int; _recurrences int; BEGIN SELECT count(*) INTO _users FROM auth.users WHERE id::text LIKE 'aaaaaaaa%'; SELECT count(*) INTO _tenants FROM public.tenants WHERE id::text LIKE 'bbbbbbbb%'; SELECT count(*) INTO _patients FROM public.patients WHERE tenant_id::text LIKE 'bbbbbbbb%'; SELECT count(*) INTO _events FROM public.agenda_eventos WHERE tenant_id::text LIKE 'bbbbbbbb%'; SELECT count(*) INTO _records FROM public.financial_records WHERE tenant_id::text LIKE 'bbbbbbbb%'; SELECT count(*) INTO _groups FROM public.patient_groups WHERE tenant_id::text LIKE 'bbbbbbbb%'; SELECT count(*) INTO _recurrences FROM public.recurrence_rules WHERE tenant_id::text LIKE 'bbbbbbbb%'; RAISE NOTICE '══════════════════════════════════════════'; RAISE NOTICE ' SEED COMPLETO — RESUMO'; RAISE NOTICE '══════════════════════════════════════════'; RAISE NOTICE ' Terapeutas: %', _users; RAISE NOTICE ' Tenants: %', _tenants; RAISE NOTICE ' Pacientes: %', _patients; RAISE NOTICE ' Eventos agenda: %', _events; RAISE NOTICE ' Lançamentos fin.: %', _records; RAISE NOTICE ' Grupos: %', _groups; RAISE NOTICE ' Recorrências: %', _recurrences; RAISE NOTICE '══════════════════════════════════════════'; RAISE NOTICE ' Login: terapeuta01@teste.agenciapsi.com'; RAISE NOTICE ' Senha: Test@1234'; RAISE NOTICE '══════════════════════════════════════════'; END $$;