-- ---------------------------------------------------------------------------
-- Cenário mínimo para os testes de caracterização financeira.
--
-- Ids fixos (90001000+) para que as asserções possam referenciá-los sem depender de
-- auto_increment. A faixa alta evita colisão com dados de um dump anonimizado
-- carregado no mesmo banco.
--
-- Valores escolhidos para tornar erros de arredondamento visíveis: 10% de
-- comissão sobre 89,90 dá 8,99, e 50% de royalty sobre 0,1 centavo aparece.
-- ---------------------------------------------------------------------------

-- ---------------------------------------------------------------------------
-- A CODIFICACAO E DECLARADA AQUI, e nao no roteiro que carrega o arquivo.
--
-- O cliente `mysql` do conteiner abre a conexao em latin1. Sem esta linha, cada
-- acento deste arquivo entra no banco DOBRADO: 'credito' com acento vira
-- 'crAdito' com dois bytes de lixo, e ninguem repara -- os snapshots de
-- contrato congelam TIPO, nao valor, e um nome errado continua sendo string.
--
-- Ficou visivel em 03/09/2026, quando a suite de contrato passou a fazer login
-- (D59): o ACL procura a funcionalidade pelo nome exato e o Laminas LANCA
-- excecao para recurso que nao existe. 61 dos 63 nomes nao casavam, e o login
-- devolvia 500 sem dizer por que.
--
-- Ate aquele dia nenhum VALOR deste arquivo tinha acento -- so os comentarios,
-- que o cliente descarta. A linha abaixo nao conserta estrago antigo: ela
-- impede o proximo, de quem acrescentar um nome acentuado sem saber disso.
--
-- Fica no ARQUIVO, e nao no `montar-banco-contrato.sh`, porque o CI carrega
-- este arquivo direto, com outro cliente e outro padrao. Uma correcao no
-- roteiro deixaria os dois bancos diferentes -- que e a pior forma de estar
-- errado.
-- ---------------------------------------------------------------------------
SET NAMES utf8mb4;

-- ---------------------------------------------------------------------------
-- ESTE ARQUIVO CARREGA NOS DOIS BANCOS, desde 04/09/2026 -- e isso custou
-- pouco e vale muito.
--
-- A suite de caracterizacao rodava, no CI, so contra MySQL. Defeito que so
-- aparece no PostgreSQL era invisivel la, e dependia de alguem lembrar de rodar
-- a mao. Aconteceu duas vezes no mesmo dia.
--
-- Faltavam TRES coisas, e nenhuma era grande:
--
--   1. `CONCAT(CURDATE(), ' 08:00:00')` virou `CURRENT_DATE + INTERVAL '8' HOUR`
--      -- a forma padrao, que os dois entendem e devolvem igual (conferido).
--
--   2. 23 valores `0`/`1` em colunas BOOLEANAS viraram `FALSE`/`TRUE`. E o D81
--      dentro das fixtures: o MySQL aceita o numero, o PostgreSQL nao. Os dois
--      aceitam a palavra.
--
--   3. A linha `SET NAMES` acima e do MySQL, e quem carrega no PostgreSQL a
--      pula -- junto com um `SET app.inquilino_id`, que o RLS exige.
--
-- Os dois carregam as MESMAS 17 tabelas com as MESMAS contagens, conferido
-- tabela a tabela.
--
-- QUEM ACRESCENTAR LINHA AQUI: use TRUE/FALSE em coluna booleana, e nada de
-- funcao so do MySQL. `scripts/rodar-caracterizacao-postgres.sh` acusa.
-- ---------------------------------------------------------------------------

-- O cenario do contrato do aplicativo (final deste arquivo) cria filhos das
-- tabelas limpas logo abaixo: uma agenda aponta para um produto, um cupom para
-- um cliente. Sem apaga-los primeiro, `DELETE FROM produtos` falha por chave
-- estrangeira -- e o mysql aborta o ARQUIVO INTEIRO ali, deixando as fixtures
-- pela metade sem que nada acuse. Estes DELETE vem antes por isso.
DELETE FROM sorteios_vendas WHERE id >= 90001150;
DELETE FROM cupons_clientes WHERE id >= 90001150;
DELETE FROM agendas WHERE id >= 90001150;
DELETE FROM clientes_sessoes WHERE id >= 90001000;
DELETE FROM clientes_sessoes WHERE telefone LIKE '+5547320%';
DELETE FROM clientes_creditos WHERE id >= 90001000;
DELETE FROM vendas_pagamentos WHERE venda >= 90001000;
DELETE FROM sorteios_vendas WHERE id >= 90001000;
DELETE FROM sorteios WHERE id >= 90001000;
DELETE FROM cupons_clientes WHERE id >= 90001000;
DELETE FROM cupons WHERE id >= 90001000;
DELETE FROM indicacoes WHERE id >= 90001000;
DELETE FROM agendas WHERE id >= 90001000;
DELETE FROM app_banners WHERE id >= 90001000;
-- Os arquivos da biblioteca antes das categorias: `arquivos.categoria` e NO ACTION.
-- E O REGISTRO DE QUEM ABRIU antes dos arquivos e das unidades (22/10/2026, a fatia
-- 29b, RESPOSTA-253-QUEM-ABRIU): `arquivos_acessos.arquivo` e `.unidade` sao NO
-- ACTION, e o ensaio de arquivos e o navegador gravam linhas no banco de contrato.
DELETE FROM arquivos_acessos WHERE arquivo >= 90001000 OR unidade >= 90001000;
DELETE FROM arquivos WHERE id >= 90001000;
DELETE FROM arquivos_categorias WHERE id >= 90001000;
UPDATE produtos SET area = NULL WHERE area >= 90001000;
-- `usuarios_areas` VEM ANTES, e a razao e de ordem e nao de tabela.
--
-- Ela tem CASCADE para `usuarios` -- entao morre junto com eles -- mas `usuarios`
-- so e apagada MUITO mais abaixo, e a chave para `areas_atuacao` e NO ACTION.
-- Enquanto o cenario so vinculava a area 3 (fora da faixa 9000xxxx) isso nao
-- aparecia; ao vincular a area 90001000 ao gerente, em 12/09/2026, a recarga
-- passou a morrer aqui com *Cannot delete or update a parent row*.
--
-- E o mesmo padrao das outras onze exclusoes deste arquivo, plantado por quem
-- acrescentou UMA linha de vinculo sem olhar a ordem da limpeza.
DELETE FROM usuarios_areas WHERE area >= 90001000;
DELETE FROM areas_atuacao WHERE id >= 90001000;

-- ---------------------------------------------------------------------------
-- AS DEZ QUE FALTAVAM, e o que a ausencia delas custava
--
-- Medido em 12/09/2026: este arquivo INSERE em 42 tabelas e a limpeza acima
-- conhecia 23. Das 19 que sobravam, nove morrem por CASCADE de um pai que a
-- limpeza ja apaga -- conferido em `REFERENTIAL_CONSTRAINTS.DELETE_RULE`, e nao
-- suposto. As DEZ abaixo nao morrem, e cada uma falha de um jeito:
--
--   estados, cidades, bairros, logradouros   nao tem pai apagado. O INSERT
--       repetido bate em *Duplicate entry '90001000' for key 'estados.PRIMARY'*
--       -- foi exatamente onde a primeira recarga parou.
--   saidas_tipos, vipclass                   idem, por caminhos proprios.
--   clientes_debitos                         aponta para vendas, clientes e
--       unidades com NO ACTION: ela nao quebra no proprio INSERT, ela BLOQUEIA
--       o DELETE de `vendas` logo abaixo.
--   nps_resultados_unidades, unidades_socios bloqueiam o DELETE de `unidades`.
--   pacotes_itens                            bloqueia o DELETE de `produtos`.
--
-- POR QUE ISSO NUNCA APARECEU NO CI, e e a parte que importa: la o banco NASCE
-- vazio a cada execucao, entao um arquivo que so carrega UMA VEZ e
-- indistinguivel de um que carrega sempre. Quem paga e quem tem banco local --
-- e o preco nao e um erro na tela: a carga ABORTA no meio, deixando o cenario
-- pela metade, que e a MESMA falha que o comentario vinte linhas acima ja
-- descrevia. Em 12/09/2026 o `franquiabv_dev` estava assim, e quem acusou foi a
-- guarda do D122: *"O cenario deste banco esta defasado"*.
--
-- A ORDEM E FILHO ANTES DE PAI, e as de `saidas` vem inteiras porque `saidas`
-- morre por cascata de `unidades` -- que so e apagada MAIS ABAIXO, tarde demais
-- para liberar `saidas_tipos`.
-- E UMA DECIMA PRIMEIRA, acrescentada no mesmo dia com as linhas de gorjeta.
--
-- `gorjetas.venda` referencia `vendas` com NO ACTION, entao sem esta linha as
-- gorjetas do cenario BLOQUEARIAM o `DELETE FROM vendas` logo abaixo -- o mesmo
-- defeito que as dez de cima acabaram de corrigir, plantado de novo por quem
-- acrescentasse a tabela sem olhar a limpeza. Fica aqui junto delas de proposito.
DELETE FROM gorjetas WHERE id >= 90001000;
DELETE FROM clientes_debitos WHERE id >= 90001000;
DELETE FROM clientes_pacotes WHERE id >= 90001000;
-- POR `unidade`, E NAO POR `id` -- a unica das onze que precisa disso.
--
-- O INSERT desta tabela, la embaixo, NAO da id explicito: a linha nasce com id
-- de sequencia (2525 no PostgreSQL, medido), muito abaixo da faixa 9000xxxx. Uma
-- limpeza por `id >= 90001000` nao a alcanca, e a SEGUNDA recarga morre em
-- *violates foreign key constraint "fk_nps_resultados_unidades_unidade"* ao
-- tentar apagar a unidade 90001000.
--
-- Conferido nas quinze tabelas desta limpeza: e a unica sem `id` na lista de
-- colunas do proprio INSERT. As outras quatorze dao o id na mao.
DELETE FROM nps_resultados_unidades WHERE unidade >= 90001000;
-- A PESQUISA DE NPS RESPONDIDA (06/10/2026, o D113) aponta para `clientes` e
-- `unidades` sem cascata: sai antes dos dois.
DELETE FROM nps WHERE id >= 90001000;
-- O RASTRO DO WHATSAPP antes das unidades (23/10/2026, a fatia 32, WHATSAPP-RASTRO):
-- `unidades_whatsapp_eventos.unidade` e NO ACTION, e o ensaio do WhatsApp e o navegador
-- podem gravar linhas no banco de contrato.
DELETE FROM unidades_whatsapp_eventos WHERE unidade >= 90001000;
DELETE FROM unidades_socios WHERE id >= 90001000;
DELETE FROM saidas_parcelas_pagamentos WHERE id >= 90001000;
DELETE FROM saidas_parcelas WHERE id >= 90001000;
DELETE FROM saidas WHERE id >= 90001000;
DELETE FROM saidas_tipos WHERE id >= 90001000;
DELETE FROM pacotes_itens WHERE id >= 90001000;
-- OS FILHOS DA VIP CLASS antes do curso (05/11/2026, a fatia 79): nenhum tem cascata para
-- `vipclass`, e `vipclass_checkpoints_usuarios` aponta para `usuarios` sem cascata -- sai antes
-- das pessoas, tambem a conclusao que um ensaio ou o navegador tenha gravado de um curso
-- qualquer por uma pessoa da fixture. O requisito e de `vipclass` para ela mesma: solta-se antes
-- (o MySQL confere a chave linha a linha, e o DELETE de uma vez podia apagar o requisito antes
-- de quem o pede).
DELETE FROM vipclass_checkpoints_usuarios WHERE vipclass >= 90001000 OR usuario >= 90001000;
DELETE FROM vipclass_checkpoints_respostas WHERE id >= 90001000 OR pergunta >= 90001000;
DELETE FROM vipclass_checkpoints_perguntas WHERE vipclass >= 90001000;
DELETE FROM vipclass_materiais WHERE vipclass >= 90001000;
DELETE FROM vipclass_aulas WHERE vipclass >= 90001000;
DELETE FROM vipclass_unidades WHERE vipclass >= 90001000 OR unidade >= 90001000;
DELETE FROM vipclass_grupos WHERE vipclass >= 90001000 OR grupo >= 90001000;
UPDATE vipclass SET requisito = NULL WHERE id >= 90001000;
DELETE FROM vipclass WHERE id >= 90001000;
-- OS ASSISTENTES DA FIXTURE (04/10/2026, a F1 dos Assistentes) saem antes das
-- unidades e dos grupos: os vinculos apontam para os dois SEM cascata. O `OR` pega o
-- vinculo que um ensaio ou o navegador tenha gravado de um assistente qualquer a uma
-- unidade ou a um grupo da fixture.
DELETE FROM assistentes_unidades WHERE assistente >= 90001000 OR unidade >= 90001000;
DELETE FROM assistentes_grupos WHERE assistente >= 90001000 OR grupo >= 90001000;
DELETE FROM assistentes WHERE id >= 90001000;
DELETE FROM logradouros WHERE id >= 90001000;
DELETE FROM bairros WHERE id >= 90001000;
DELETE FROM cidades WHERE id >= 90001000;
DELETE FROM estados WHERE id >= 90001000;
-- ---------------------------------------------------------------------------

DELETE FROM vendas_pagamentos WHERE venda >= 90001000;
DELETE FROM vendas_produtos WHERE venda >= 90001000;
DELETE FROM vendas WHERE id >= 90001000;
DELETE FROM caixas WHERE id >= 90001000;
DELETE FROM produtos WHERE id >= 90001000;
-- A etiqueta da fixture (D241) sai depois dos produtos, que apontam para ela.
DELETE FROM produtos_tags WHERE id >= 90001000;
DELETE FROM clientes WHERE id >= 90001000;
-- O cliente avulso ocupa o id 1, fora da faixa de teste, e referencia a unidade
-- 90001000 — sem removê-lo o DELETE de unidades falha por chave estrangeira. O
-- filtro por nome garante que apenas o registro criado por estas fixtures seja
-- apagado, nunca o cliente 1 real de um dump anonimizado.
DELETE FROM clientes WHERE id = 1 AND nome = 'Cliente Avulso (balcao)';
-- A VIGENCIA DO HORARIO SAI ANTES DOS USUARIOS (F4.1, 02/10/2026). Ela aponta
-- para `usuarios` SEM cascata, de proposito -- o historico nao some calado --,
-- e qualquer escrita de usuario de fixture grava uma linha: salvar o horario no
-- navegador contra o banco de contrato, os ensaios por HTTP, a semente rodada
-- numa copia que tem as fixtures. Sem esta linha, a recarga seguinte morre no
-- `DELETE FROM usuarios` logo abaixo.
DELETE FROM usuarios_horarios WHERE usuario >= 90001000;
DELETE FROM usuarios WHERE id >= 90001000;
DELETE FROM unidades WHERE id >= 90001000;
DELETE FROM grupos WHERE id >= 90001000;
DELETE FROM formas_pagamentos WHERE id >= 90001000;
-- As duas formas de credito ocupam os ids 5 e 6, FORA da faixa de teste, pelo
-- mesmo motivo do cliente avulso logo acima: o codigo compara esses numeros
-- literalmente, entao o cenario nao pode escolher outros. O filtro por nome
-- garante que so a linha criada por estas fixtures seja apagada, e nunca a
-- forma real de um dump anonimizado -- que se chama 'Credito Cliente', sem o
-- sufixo, e pode ter venda de verdade pendurada nela.
DELETE FROM formas_pagamentos
 WHERE id IN (5, 6)
   AND nome IN ('Credito Cliente (teste)', 'Credito Fidelidade (teste)');
DELETE FROM convenios WHERE id >= 90001000;

-- ---------------------------------------------------------------------------
-- As funcionalidades que o ACL pede POR NOME
-- ---------------------------------------------------------------------------
-- O `mysql.sql` e dump de ESTRUTURA: a tabela `funcionalidades` nasce vazia.
-- Isso nao incomodava ninguem enquanto nada logava no cenario de teste.
--
-- Passou a incomodar em 03/09/2026, quando dois endpoints da API passaram a
-- exigir sessao (D59) e a suite de contrato precisou entrar no ERP. O login
-- monta a ACL, e `SessaoAcl::setAcl()` pergunta `isAllowed($grupo, <nome>)`
-- para cada uma destas funcionalidades. O Laminas ACL LANCA EXCECAO para
-- recurso nao registrado -- entao a tabela vazia derrubava o login com HTTP
-- 500, sem dizer por que.
--
-- Marcar o grupo como administrador NAO resolve, medido: o `allow` em bloco
-- nao registra recurso, e a excecao vem do recurso ausente.
--
-- Os nomes sao extraidos do proprio `SessaoAcl`, e sao 63. Nenhum privilegio e
-- concedido aqui: `privilegios_usuarios` fica vazia, e o usuario de teste
-- entra sem poder nenhum -- que e o suficiente para as rotas que so exigem
-- SESSAO, e o minimo para nao dar poder a um usuario de fixture por acidente.
-- ---------------------------------------------------------------------------

DELETE FROM funcionalidades WHERE id >= 90001000;

-- CONDICIONAL, E PELO `nome` -- nao pelo `id`, como os outros nove condicionais
-- deste arquivo. A colisao desta tabela e no NOME.
--
-- ATE 15/09/2026 ESTE BLOCO INSERIA OS 63 INCONDICIONALMENTE, e num banco que ja
-- tinha o catalogo de producao o resultado eram 126 linhas para 63 nomes.
-- `Acl::carregarFuncionalidades()` registra cada linha como recurso PELO NOME, e
-- o Laminas lanca na segunda -- "Resource id '<nome>' already exists in the ACL",
-- vendor/laminas/laminas-permissions-acl/src/Acl.php:254 --, sem try/catch em
-- nenhum ponto do login. Medido: alimentando a biblioteca com os 126 nomes reais
-- do `franquiabv_dev`, ela estoura no 64o recurso. NINGUEM ENTRAVA NO ERP.
--
-- CEDER PELO NOME MANTEM OS IDS 90002xxx onde nao ha producao, que e onde os
-- outros roteiros os procuram: ensaiar-recusas-adm-api.php:222,
-- medir-telas-no-postgres.sh:97 e :128, ci.yml:647. Naqueles bancos a tabela
-- nasce vazia (o `mysql.sql` e dump de estrutura, com ZERO insert), nenhum nome
-- pre-existe, e os 63 entram exatamente como antes.
--
-- CONFERIDO NOS DOIS BANCOS, em banco descartavel: tabela vazia -> as 63 linhas
-- entram na faixa de fixture; tabela com os nomes de producao -> nenhuma linha
-- nova, e nenhum nome repetido.
--
-- O `DELETE` acima alcanca 90002000..90002062, entao na copia de producao a
-- proxima carga deste arquivo APAGA as 63 antigas e nao repoe nenhuma.
--
-- AS QUATRO QUE TROCAM DE NOME NO CORTE CEDEM TAMBEM PELO NOME ANTIGO (04/11/2026,
-- a DE3 de docs/f3-relatorios/spec-datas-da-equipe.md; a resposta 298 (c) do dono,
-- o D701). O 90002023, o 90002025, o 90002034 e o 90002039 levam o nome da tela
-- ("Relatórios da carteira de clientes", "... da cota-parte", "... do profissional
-- parceiro", "... de datas da equipe") e, em `nome_antigo`, o de hoje; as outras 59
-- levam NULL, que nao casa com nada. Num banco vazio (o contrato, o CI) entram as
-- quatro com o nome novo. POR CIMA DA COPIA OU DE UM CLONE DELA (o
-- `scripts/ensaiar-corte.sh` em cada clone, o `scripts/setup-dev.sh` no
-- `franquiabv_dev`), NENHUMA ENTRA, e por isso: cedendo so pelo nome novo, elas
-- entrariam ao lado dos ids 15, 17, 40 e 49 de producao, que tem o antigo; o
-- `SessaoAcl` acharia o nome novo e responderia pela linha DA FIXTURE, sem
-- privilegio nenhum -- os gerentes do clone perderiam a Carteira, a Cota-parte, o
-- Parceiro e as Datas, que os privilegios ligam ao id de producao --, e o `UPDATE`
-- do passo 7 do corte (`scripts/renomear-permissoes-das-telas-novas.sql`) daria ao
-- id de producao o mesmo nome da fixture: dois recursos com o mesmo nome, e o
-- login de todos lancando no `addResource`, o incidente de 15/09 contado acima. O
-- nome novo so chega a copia por aquele `UPDATE`, que para se ele ja existir em
-- outro id. O `scripts/ensaiar-permissoes-com-o-nome-da-tela.php` carrega este
-- arquivo por cima do catalogo antigo e do vazio, nos dois bancos.

INSERT INTO funcionalidades (id, nome)
SELECT v.id, v.nome FROM (
            SELECT 90002000 AS id, 'Agendas visualizar' AS nome, NULL AS nome_antigo
  UNION ALL SELECT 90002001, 'Agendas gerenciar', NULL
  UNION ALL SELECT 90002002, 'Agendas unidades', NULL
  UNION ALL SELECT 90002003, 'Vendas nova', NULL
  UNION ALL SELECT 90002004, 'Vendas caixa', NULL
  UNION ALL SELECT 90002005, 'Vendas realizadas', NULL
  UNION ALL SELECT 90002006, 'Vendas cancelar', NULL
  UNION ALL SELECT 90002007, 'Comandas listar', NULL
  UNION ALL SELECT 90002008, 'Comandas nova', NULL
  UNION ALL SELECT 90002009, 'Comandas fechar', NULL
  UNION ALL SELECT 90002010, 'Comandas cancelar todas', NULL
  UNION ALL SELECT 90002011, 'Visagismo teste estilo', NULL
  UNION ALL SELECT 90002012, 'Visagismo consultor visagista', NULL
  UNION ALL SELECT 90002013, 'Clientes cadastro', NULL
  UNION ALL SELECT 90002014, 'Clientes crédito', NULL
  UNION ALL SELECT 90002015, 'Clientes historico', NULL
  UNION ALL SELECT 90002016, 'Clientes devedores', NULL
  UNION ALL SELECT 90002017, 'Clientes blacklist agendamento app', NULL
  UNION ALL SELECT 90002018, 'Marketing cupons', NULL
  UNION ALL SELECT 90002019, 'Marketing notificacoes', NULL
  UNION ALL SELECT 90002020, 'Marketing sorteios', NULL
  UNION ALL SELECT 90002021, 'Financeiro saídas', NULL
  UNION ALL SELECT 90002022, 'Relatórios de caixa', NULL
  UNION ALL SELECT 90002023, 'Relatórios da carteira de clientes', 'Relatórios de clientes'
  UNION ALL SELECT 90002024, 'Relatórios de franquias', NULL
  UNION ALL SELECT 90002025, 'Relatórios da cota-parte', 'Relatórios de vendas'
  UNION ALL SELECT 90002026, 'Relatórios de vendas canceladas', NULL
  UNION ALL SELECT 90002027, 'Relatórios de produtos', NULL
  UNION ALL SELECT 90002028, 'Relatórios de fluxo de movimento', NULL
  UNION ALL SELECT 90002029, 'Relatórios de evasão', NULL
  UNION ALL SELECT 90002030, 'Relatórios de atendimentos', NULL
  UNION ALL SELECT 90002031, 'Relatórios de fidelização', NULL
  UNION ALL SELECT 90002032, 'Relatórios retiradas de produtos', NULL
  UNION ALL SELECT 90002033, 'Relatórios NPS', NULL
  UNION ALL SELECT 90002034, 'Relatórios do profissional parceiro', 'Relatórios dashboard colaboradores'
  UNION ALL SELECT 90002035, 'Relatórios dashboard colaboradores - plano carreira', NULL
  UNION ALL SELECT 90002036, 'Relatórios dashboard unidades', NULL
  UNION ALL SELECT 90002037, 'Relatórios dashboard faturamentos', NULL
  UNION ALL SELECT 90002038, 'Relatórios de descontos', NULL
  UNION ALL SELECT 90002039, 'Relatórios de datas da equipe', 'Relatórios de aniversariante'
  UNION ALL SELECT 90002040, 'Relatórios de consultor visagista', NULL
  UNION ALL SELECT 90002041, 'Relatórios radar temperatura', NULL
  UNION ALL SELECT 90002042, 'Relatórios programa de indicação', NULL
  UNION ALL SELECT 90002043, 'Configurações usuários', NULL
  UNION ALL SELECT 90002044, 'Configurações convênios', NULL
  UNION ALL SELECT 90002045, 'Configurações unidades', NULL
  UNION ALL SELECT 90002046, 'Configurações produtos/serviços', NULL
  UNION ALL SELECT 90002047, 'Configurações produtos/serviços tags', NULL
  UNION ALL SELECT 90002048, 'Configurações controle de acesso', NULL
  UNION ALL SELECT 90002049, 'Arquivos cadastrar', NULL
  UNION ALL SELECT 90002050, 'Arquivos exibir', NULL
  UNION ALL SELECT 90002051, 'Pesquisa de satisfação', NULL
  UNION ALL SELECT 90002052, 'Yungas', NULL
  UNION ALL SELECT 90002053, 'Configurações app configuraçoes', NULL
  UNION ALL SELECT 90002054, 'Configurações pacotes', NULL
  UNION ALL SELECT 90002055, 'Configurações mensagens', NULL
  UNION ALL SELECT 90002056, 'Configurações whatsapp', NULL
  UNION ALL SELECT 90002057, 'API Integração', NULL
  UNION ALL SELECT 90002058, 'VIP Class - Admin', NULL
  UNION ALL SELECT 90002059, 'VIP Class - Edu', NULL
  UNION ALL SELECT 90002060, 'VIP Class - Relatório', NULL
  UNION ALL SELECT 90002061, 'Assistente IA - Admin', NULL
  UNION ALL SELECT 90002062, 'Assistente IA - Usuários', NULL
) v
 WHERE NOT EXISTS (SELECT 1 FROM funcionalidades f WHERE f.nome = v.nome OR f.nome = v.nome_antigo);

-- O `administrador` VAI EXPLICITO, e nao por omissao.
--
-- Ate 05/09/2026 esta insercao nao o citava, e o valor vinha do padrao da
-- coluna -- que era `NULL` no MySQL e `false` no PostgreSQL, porque o gerador
-- de DDL transformava um no outro (D109). O efeito era visivel na tela: a
-- listagem de usuarios filtra por `gru.administrador = false`, e `NULL = false`
-- nao e verdadeiro, entao o mesmo ERP mostrava dois usuarios num banco e
-- "Nenhum usuario localizado" no outro.
--
-- Cenario que depende de padrao de coluna nao diz o que quer dizer. Este diz.
INSERT INTO grupos (id, nome, administrador, gerente, caixa, colaborador, status) VALUES
    (90001000, 'Colaborador (teste)', FALSE, FALSE, FALSE, TRUE,  TRUE),
    (90001001, 'Gerente (teste)',     FALSE, TRUE,  TRUE,  FALSE, TRUE);

-- O GRUPO 1 EXISTE PORQUE O CODIGO PEDE O NUMERO 1, como a area 3 mais abaixo.
--
-- `selecionarUsuariosComVendas($unidade, null, 1)` filtra `usu.grupo = 1`, e e
-- por ali que passa a rotina de cron da EVASAO. Na copia de producao, 1 e
-- "Colaborador" -- 1.748 usuarios. Sem esta linha, a rotina rodava, gravava
-- `[]` no cache e a tela dizia que nao ha nada; com ela, o cenario tem um
-- colaborador que a rotina enxerga.
--
-- Condicional, como o cliente 1 e a area 3: quando as fixtures entram num banco
-- que ja tem producao, a linha real fica.
INSERT INTO grupos (id, nome, administrador, gerente, caixa, colaborador, status)
SELECT 1, 'Colaborador', FALSE, FALSE, FALSE, TRUE, TRUE
 WHERE NOT EXISTS (SELECT 1 FROM grupos WHERE id = 1);

-- O `nome` DA UNIDADE E MARCA DE RELATORIO, e nao enfeite.
--
-- As listas de selecao do ERP nao usam esta coluna: `popularCombobox()` monta o
-- rotulo concatenando pais, estado, cidade e bairro. Quem imprime `nome` e a
-- LINHA DE DADO -- a coluna "Unidade" dos relatorios de franquia. Ou seja, o
-- texto so aparece na resposta se o relatorio trouxe linha, que e exatamente o
-- que `PRECISA_MOSTRAR` precisa conferir (D113).
--
-- Antes disto a coluna saia em branco nos dois relatorios de franquia, e o
-- unico numero disponivel para marca era "horarios disponiveis", que muda todo
-- ano porque o periodo pedido e relativo ao ano corrente.
-- `relatorio_atendimentos` PRECISA TER DATA, e a razao e uma condicao facil de
-- ler errado.
--
-- `selecionarUnidadesRelatorioFranquias($id, $data)` filtra por
-- `DATE(u.relatorioAtendimentos) < '<hoje>'`, e a rotina de cron que monta o
-- relatorio de atendimentos passa por ali. Com a coluna NULA a comparacao e
-- NULA, a unidade nunca entra, o cache nunca e escrito -- e a tela responde
-- "Dados indisponiveis." com 200, que foi o que a medicao viu por semanas.
--
-- ISTO NAO E DEFEITO DO SISTEMA, e vale dizer porque parece: o construtor de
-- `Unidade` ja grava `now` nessa coluna, entao unidade criada pelo ERP nasce
-- com data. Quem nascia sem era a unidade DESTE arquivo, inserida por SQL
-- direto. Conferido na copia de producao em 06/09/2026: das 35 unidades
-- ativas, as 3 sem data eram estas fixtures.
INSERT INTO unidades (id, nome, tipo, pais, cidade, bairro, endereco, numero,
     royltes_produto_barbearia, royltes_produto_emporio, royltes_servico, royltes_lavavip,
     visivel_app, reducao_potencial, agenda_primeiro_nome,
     fidelizacao_unidade_dias, fidelizacao_unidade_visitas, cashback,
     whatsapp_ativo, hash, relatorio_atendimentos, status, data_criacao) VALUES
    (90001000, 'Unidade Teste Centro', 'PROPRIA', 'Brasil', 'Florianopolis', 'Centro', 'Rua de Teste', '100',
     5, 5, 10, 5,
     TRUE, 0, TRUE,
     90, 3, 0,
     FALSE, 'hash-teste-90001000', '2026-01-02 03:00:00', TRUE, '2026-01-01 00:00:00');

-- `data_nascimento` DO COLABORADOR, em marco.
--
-- O Relatorio de Aniversariantes nao e de clientes: ele lista UNIDADES, SOCIOS
-- e COLABORADORES -- aniversario e tempo de casa. Perdi uma rodada dando
-- aniversario ao cliente, que aquele relatorio nem consulta.
-- A `data_contratacao` ENTROU EM 12/09/2026, e as duas datas nao sao decorativas.
--
-- `UsuarioRepository::relatorioSelecionarAniversariantesContratacao()` -- a metade
-- de "contratacao" do relatorio de aniversariantes -- filtra por
-- `MONTH(usu.dataContratacao)` e ordena por `DAY(...)`. Sem coluna preenchida ele
-- devolvia vazio SEMPRE, e qualquer teste sobre ele seria verde por ausencia de
-- dado.
--
-- As duas datas sao de MARCO, com dias 08 e 25, e isso destrava duas coisas de
-- uma vez:
--
--   o MES filtra      -- pedir marco traz os dois, pedir maio traz nenhum;
--   o DIA ordena      -- 08 antes de 25, que e a unica forma de exercitar o
--                        `Ordenacao::comoMysql('DAY(...)', 'ASC')` que os dois
--                        metodos de usuario usam. Com um registro so por mes, a
--                        ordenacao nao se distingue de nao ordenar.
--
-- E o dia da contratacao do 90001000 (08) e DIFERENTE do dia do nascimento dele
-- (22), de proposito: e isso que separa "leu `dataContratacao`" de "leu
-- `dataNascimento`" -- as duas colunas, os dois metodos irmaos, a mesma forma.
INSERT INTO usuarios (id, unidade, grupo, nome, email, login, sexo, senha, data_nascimento,
     data_contratacao, visivel_agenda, visivel_pdv, ordernacao_app, status, data_criacao) VALUES
    (90001000, 90001000, 90001000, 'Colaborador Teste', 'colab@teste.invalid', 'colab.teste', 'M',
     '$2y$10$abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR', '1988-03-22',
     '2020-03-08', 'sim', TRUE, 1, 1, '2026-01-01 00:00:00'),
    -- `nenhuma`, E NAO `nao` -- e o mesmo vale para o `int` do terceiro.
    --
    -- O dominio real de `visivel_agenda` tem QUATRO valores, medidos na copia em
    -- 12/09/2026: `ext_int` (1.134 usuarios), `nenhuma` (1.053), `int` (228) e
    -- `ext` (13). Os unicos `sim` e `nao` do banco inteiro eram as quatro linhas
    -- DESTE arquivo.
    --
    -- O comentario duzentas linhas abaixo ja tinha achado isso -- *"`visivel_agenda`
    -- valia 'sim', que nao e um dos valores que `getUnidadeColaboradoresServicos()`
    -- aceita"* -- e consertou UM usuario com um UPDATE. Os outros ficaram.
    --
    -- Por que isso importa: um valor fora do dominio faz o colaborador sumir da
    -- agenda pelo motivo ERRADO, e um teste sobre o filtro passaria acreditando que
    -- a regra o excluiu. Com `nenhuma` e `int`, os dois saem e entram por regra.
    -- Nenhum dos dois e visivel na agenda EXTERNA (`ext`/`ext_int`), entao o
    -- contrato congelado do aplicativo nao muda.
    (90001001, 90001000, 90001001, 'Gerente Teste',     'gerente@teste.invalid', 'gerente.teste', 'F',
     '$2y$10$abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR', NULL,
     NULL, 'nenhuma', TRUE, 2, 1, '2026-01-01 00:00:00'),
    -- O terceiro usuario existe para a EVASAO, e por isso esta no grupo 1.
    -- O id NAO E 90001002: esse ja e do `Colaborador Dois` que o
    -- `FidelizacaoTest` cria por SQL direto, e a colisao so aparece quando a
    -- suite roda -- com violacao de chave primaria, longe daqui.
    (90001003, 90001000, 1, 'Barbeiro Evasao Teste', 'evasao@teste.invalid', 'evasao.teste', 'M',
     '$2y$10$abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR', NULL,
     '2021-03-25', 'int', TRUE, 4, 1, '2026-01-01 00:00:00');

-- A ULTIMA VISITA E O E-MAIL EXISTEM PARA O RELATORIO DE CLIENTES PODER
-- RESPONDER, e o motivo merece estar escrito aqui.
--
-- `ClienteRepository::filtrosListagemIndexRelatorio()` filtra por
-- `uni.id = :unidade`, e `uni` e `LEFT JOIN cli.ultimaVisitaUnidade` -- a
-- unidade da ULTIMA VISITA, e nao a unidade de cadastro do cliente. Cliente que
-- nunca visitou nao aparece em relatorio nenhum. Sem estas tres colunas
-- preenchidas, o relatorio de clientes -- as quatro acoes: tela, PDF, TXT e XLS
-- -- saia com ZERO linhas, e a medicao dizia "nenhum relatorio quebrou" sobre
-- uma planilha que so tinha o cabecalho (D113).
--
INSERT INTO clientes (id, unidade, nome, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    -- Atenção: fidelizado_unidade é BOOLEANO (a entidade o mapeia como boolean),
    -- e não uma referência à unidade, apesar do nome e do tipo int na coluna.
    (90001000, 90001000, 'Cliente Teste', TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- UM CLIENTE COM HISTORICO, e ele existe para o relatorio poder responder.
--
-- `ClienteRepository::filtrosListagemIndexRelatorio()` filtra por
-- `uni.id = :unidade`, e `uni` e `LEFT JOIN cli.ultimaVisitaUnidade` -- a
-- unidade da ULTIMA VISITA, e nao a de cadastro. Cliente que nunca visitou nao
-- aparece em relatorio nenhum, e por isso as QUATRO acoes do relatorio de
-- clientes -- tela, PDF, TXT e XLS -- saiam com zero linhas. A medicao dizia
-- "nenhum relatorio quebrou" sobre uma planilha que so tinha o cabecalho (D113).
--
-- POR QUE UM CLIENTE NOVO, e nao historico no 'Cliente Teste' de cima: aquele e
-- o cliente SEM passado do cenario, e tres testes dependem disso. Com
-- `ultima_visita_colaborador` preenchido nele,
-- `FidelizacaoTest::testPrimeiraVisitaNaoFidelizaOColaborador` fica vermelho --
-- a "primeira" visita passa a ser a segunda com o mesmo colaborador, e fideliza.
-- Vermelho correto, e foi o teste fazendo o que foi escrito para fazer.
--
-- O TELEFONE E A MARCA DO MEDIDOR: e o valor que so aparece se uma linha de dado
-- foi impressa -- a coluna Telefone da tabela, e o arquivo do TXT, que so escreve
-- linha para cliente COM telefone. Nome nao serviria: 'Cliente Teste' aparece
-- tambem nas listas de selecao do formulario de filtro, e uma marca assim
-- ficaria verde com a tabela vazia. E-mail tambem nao: a tabela do relatorio nao
-- tem coluna de e-mail.
--
-- E O ULTIMO ACESSO AO APP PRECISA EXISTIR, por um motivo que so apareceu
-- medindo. O medidor manda `ultimo_acesso_app_inicio` e `_fim` no saco unico de
-- parametros, e o filtro correspondente e
-- `AND DATE(cli.ultimoAcessoApp) >= :acessoInicio`. Com a coluna NULA a
-- comparacao da NULO, a linha sai do resultado, e o relatorio volta vazio -- sem
-- erro, sem aviso, e sem nada que distinga "nao ha cliente" de "o medidor se
-- excluiu sozinho".
-- `data_nascimento` EM MARCO, e o mes e escolhido e nao sorteado: o relatorio
-- de aniversariantes filtra por mes, o medidor pergunta por marco, e um mes
-- relativo a hoje faria a marca passar ou falhar conforme o dia da execucao.
INSERT INTO clientes (id, unidade, nome, email, telefone, data_nascimento, ultima_visita, ultima_visita_unidade,
     ultima_visita_colaborador, ultimo_acesso_app, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001010, 90001000, 'Cliente Historico Teste', 'marca.cliente@teste.invalid', '+5547900001000',
     '1990-03-15', '2026-03-10 10:15:00', 90001000, 90001000, '2026-03-10 11:00:00',
     TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- O CLIENTE EVADIDO, e as duas datas precisam ser a MESMA.
--
-- `evasaoPorColaborador()` exige `DATE(cli.ultimaVisita) = DATE(ven.dataCriacao)`
-- -- e isso e a definicao de evasao: a ultima visita do cliente E aquela venda,
-- e depois dela ele nao voltou. Se as duas datas nao baterem, a consulta nao o
-- devolve e o relatorio continua vazio sem dizer por que.
--
-- Oito meses atras, e relativo a hoje: a rotina percorre janelas de 2 a 6 meses
-- para tras, todas relativas ao dia da execucao. Data fixa sairia dessas
-- janelas com o tempo -- silenciosamente, que e o pior jeito.
INSERT INTO clientes (id, unidade, nome, email, telefone, ultima_visita, ultima_visita_unidade,
     ultima_visita_colaborador, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001020, 90001000, 'Cliente Evadido Teste', 'evadido@teste.invalid', '+5547900002000',
     CURRENT_DATE - INTERVAL '8' MONTH, 90001000, 90001003,
     TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- UM CLIENTE COM ACENTO NO NOME, e a coluna `tags` com o acento dentro.
--
-- `tags` e a coluna que a busca do ERP usa (`autoComplite`), e ela e montada
-- em MINUSCULAS pelo proprio sistema -- mas SEM tirar acento. Nos dois bancos a
-- coluna e a mesma; o que muda e o `LIKE`:
--
--   MySQL        collation `utf8mb4_general_ci`: sem acento e sem caixa. Buscar
--                "jose" acha "josé", e "JOSE" acha os dois.
--   PostgreSQL   `LIKE` compara byte a byte: "jose" NAO acha "josé".
--
-- Medido na copia de producao em 06/09/2026: 20.716 dos 242.587 clientes tem
-- acento nas tags -- 8,5% que somem da busca no dia do corte (D119).
--
-- Este cliente existe para que isso fique num teste, e nao so numa anotacao.
INSERT INTO clientes (id, unidade, nome, tags, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001030, 90001000, 'José Acentuado Teste', 'josé acentuado teste',
     TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- O cliente de id 1 é tratado como caso especial pelo código: em
-- VendaPagamentoService::finalizar(), `if ($venda->getCliente()->getId() != 1)`
-- pula fidelidade, pacotes, cupons, sorteios e comissão de indicação. É o
-- cliente avulso ("balcão"). Precisa existir no cenário para caracterizar esse
-- desvio. Ver débito D18.
--
-- O INSERT é condicional para não sobrescrever o registro real caso um dump
-- anonimizado já esteja carregado. A forma `SELECT ... WHERE NOT EXISTS` é
-- deliberada: o `INSERT IGNORE` que estava aqui é exclusivo do MySQL, e o
-- `ON CONFLICT DO NOTHING` equivalente é exclusivo do PostgreSQL. Esta forma
-- é padrão e roda nos dois — que é o que permite um arquivo de cenário só
-- durante a transição, em vez de dois que divergem em silêncio.
INSERT INTO clientes
    (id, unidade, nome, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app)
SELECT 1, 90001000, 'Cliente Avulso (balcao)', TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE
 WHERE NOT EXISTS (SELECT 1 FROM clientes WHERE id = 1);

-- E O CLIENTE 2, o "SEM CADASTRO", pelo mesmo motivo e por um a mais.
--
-- As consultas do ERP escrevem `c.id != 2` no meio do WHERE: e a venda
-- sem cliente identificado. Ele nunca esteve nas fixtures, e enquanto
-- ninguem criava cliente pelo cenario isso nao aparecia.
--
-- APARECEU NA QUARTA FATIA: o ensaio de fluxo cadastrou um cliente pela
-- API, a sequencia do banco novo estava no comeco, e ele nasceu com o id
-- 2 -- virando "SEM CADASTRO" para o sistema inteiro. Os dois ids sao
-- reservados por CONVENCAO, e nao pelo banco: num ambiente novo eles sao
-- entregues a quem chegar primeiro.
INSERT INTO clientes
    (id, unidade, nome, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app)
SELECT 2, 90001000, 'Cliente Sem Cadastro', TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE
 WHERE NOT EXISTS (SELECT 1 FROM clientes WHERE id = 2);

-- Um serviço e um produto: as alíquotas de royalty e as regras de comissão
-- diferem entre os dois, então os dois precisam estar no cenário.
INSERT INTO produtos (id, unidade, tipo, nome, valor_compra, valor_venda,
     visivel_app, insumo, status, data_criacao) VALUES
    (90001000, 90001000, 'ser',     'Corte Teste',   0,     89.90, TRUE, FALSE, TRUE, '2026-01-01 00:00:00'),
    (90001001, 90001000, 'probar',  'Pomada Teste',  20.00, 59.90, TRUE, FALSE, TRUE, '2026-01-01 00:00:00'),
    -- Empório: NÃO entra na base de cálculo da pontuação de fidelidade, que
    -- considera apenas os tipos 'ser' e 'probar'. Existe no cenário para
    -- caracterizar essa exclusão.
    (90001002, 90001000, 'proemp',  'Cerveja Teste', 5.00,  15.00, TRUE, FALSE, TRUE, '2026-01-01 00:00:00'),
    -- Lava VIP é a quinta categoria de faturamento no cálculo de royalties,
    -- ao lado de ser, pac, probar e proemp. Necessária para caracterizar o
    -- cruzamento de campos descrito no débito D22.
    (90001003, 90001000, 'lavavip', 'Lavagem Teste', 0,     40.00, TRUE, FALSE, TRUE, '2026-01-01 00:00:00');

INSERT INTO formas_pagamentos (id, nome, tipo, abreviacao, status) VALUES
    (90001000, 'Dinheiro (teste)', 'din', 'DIN', TRUE),
    (90001001, 'Cartao (teste)',   'cre', 'CRE', TRUE);

-- AS DUAS FORMAS DE CREDITO, com os ids que o codigo compara LITERALMENTE
-- ---------------------------------------------------------------------------
-- `FormaPagamento::CREDITO_CLIENTE` e 5 e `CREDITO_PROGRAMA_FIDELIDADE` e 6 --
-- nao por escolha deste arquivo, e sim porque a regra de negocio ja comparava
-- esses numeros soltos antes de o D18 lhes dar nome. Sao DEZ usos hoje, em
-- quatro arquivos, contados em 10/09/2026: quatro em `VendaPagamentoService`,
-- dois em `VendaService`, dois no `ComandasController` e dois no
-- `FormaPagamentoJson`. Um cenario que
-- as numerasse em 9000xxxx teria as FORMAS e nao teria a REGRA: o
-- `ComandasController` nunca reconheceria as linhas como credito, e tudo
-- passaria como se fosse dinheiro.
--
-- POR QUE PRECISOU EXISTIR: ate 10/09/2026 a guarda de saldo do D160/D166 era
-- INALCANCAVEL no cenario. `POST /adm/api/comandas/:id/pagamentos` com
-- `formaPagamentoId: 5` parava antes dela, no `find()` que nao achava linha
-- nenhuma, e respondia 422 "nao existe". A guarda estava escrita, tinha
-- revisao, e nao tinha prova -- verde por ausencia de dado.
--
-- O NOME LEVA "(teste)" DE PROPOSITO, e nao o nome de producao. E o que
-- permite a limpeza do topo apagar SO a linha que este arquivo criou, do mesmo
-- jeito que faz com o cliente avulso de id 1: num banco com dump anonimizado
-- carregado os ids 5 e 6 JA EXISTEM, com os nomes de verdade e com vendas
-- penduradas, e nenhum dos dois pode ser tocado. O `WHERE NOT EXISTS` abaixo
-- cede a vez a eles -- e por isso o cenario aqui e o de um banco vazio, nunca
-- o de um banco que ja tem a forma real.
--
-- `tipo` e `abreviacao` COPIAM A PRODUCAO ('car' e 'OU', conferidos na tabela
-- em 10/09/2026). Nenhuma regra le esses dois campos -- `FormaPagamentoJson`
-- ate os deixa fora do recurso por isso --, mas a exportacao contabil do
-- `CronJobService:187` monta a string da venda concatenando `abreviacao`, e o
-- consumidor dela e externo. Um cenario que inventasse 'CRE' ali descreveria
-- um arquivo que o contador nunca recebe.
--
-- `ordenacao` tambem copia a producao (7 e 8) porque as listas suspensas do
-- ERP ordenam por ela: com o DEFAULT 1 as duas formas de credito apareceriam
-- ANTES de Dinheiro na tela, e o cenario deixaria de descrever a ordem que o
-- caixa realmente ve.
--
-- UM LIMITE DO `WHERE NOT EXISTS`, no PostgreSQL, que vale escrito: la a tabela
-- e isolada por inquilino (`postgres/schema.sql:1950-1955`, com FORCE ROW LEVEL
-- SECURITY) e a chave primaria e so `id` (:534). O SELECT enxerga pela politica
-- e a chave vale para o banco inteiro -- entao a guarda so protege a linha real
-- enquanto este arquivo for carregado sob o MESMO `app.inquilino_id` que a
-- possui. Sob outro, o INSERT nao a veria, colidiria na chave e abortaria o
-- arquivo. Isso vale igual para os clientes 1 e 2 acima; e propriedade do
-- padrao, e nao deste bloco. Os carregadores todos fixam `app.inquilino_id = 1`.
INSERT INTO formas_pagamentos (id, nome, tipo, abreviacao, ordenacao, status)
SELECT 5, 'Credito Cliente (teste)', 'car', 'OU', 7, TRUE
 WHERE NOT EXISTS (SELECT 1 FROM formas_pagamentos WHERE id = 5);

INSERT INTO formas_pagamentos (id, nome, tipo, abreviacao, ordenacao, status)
SELECT 6, 'Credito Fidelidade (teste)', 'car', 'OU', 8, TRUE
 WHERE NOT EXISTS (SELECT 1 FROM formas_pagamentos WHERE id = 6);

-- O caixa abre na data CORRENTE, e nao numa data fixa, porque a regra de
-- negocio enunciada em 31/08/2026 proibe que um caixa atravesse a virada do
-- dia (D28): `VendaPagamentoService::finalizar()` recusa a venda quando o
-- caixa aberto e de data anterior. Com data fixa, todo teste que finaliza
-- venda cairia -- nao por defeito, mas por cenario impossivel sob a regra.
--
-- Depender do dia em que os testes rodam e o que estas fixtures evitam em
-- todo o resto, e aqui a excecao e deliberada: em producao o caixa e SEMPRE
-- do dia. PHP e MySQL concordam sobre a data desde que o D42 foi corrigido,
-- entao a virada de dia nao os desencontra.
INSERT INTO caixas (id, usuario, valor_inicial, data_criacao, status) VALUES
    (90001000, 90001001, 100.00, CURRENT_DATE + INTERVAL '8' HOUR, TRUE);

-- Convênio de 20% para caracterizar o desconto em serviços. Os dias da semana
-- são habilitados na unidade para que o cenário não dependa do dia em que os
-- testes rodam.
INSERT INTO convenios (id, nome, porcentagem, contrato_vencido, status, data_criacao) VALUES
    (90001000, 'Convenio Teste', 20, FALSE, TRUE, '2026-01-01 00:00:00');

UPDATE unidades
   SET convenio_segunda = TRUE, convenio_terca = TRUE, convenio_quarta = TRUE,
       convenio_quinta = TRUE, convenio_sexta = TRUE, convenio_sabado = TRUE,
       convenio_domingo = TRUE
 WHERE id = 90001000;

-- ===========================================================================
-- Cenário do contrato do aplicativo (D55)
-- ===========================================================================
--
-- Estas linhas existem por um motivo específico: sem elas, nove dos 28 testes
-- de contrato gravavam a resposta de "não achei nada" como se fosse o
-- contrato. O snapshot dizia `{"sucesso": "boolean"}` e passava -- protegendo
-- exatamente nada, num aplicativo que não pode ser atualizado (D5).
--
-- O que estava faltando não era código: era DADO. Os testes pediam
-- `/api/.../1`, e as fixtures criam a unidade 90001000 e o cliente 90001000.
-- O id 1 nunca existiu aqui.
--
-- Regra para quem mexer nisto: se um endpoint de lista passar a devolver lista
-- vazia, o teste agora FALHA em vez de gravar o vazio. Isso é de propósito --
-- ver `ContratoTestCase::assertContrato()`.

-- ---------------------------------------------------------------------------
-- O colaborador precisa ser visível ao aplicativo e ter horário de trabalho
-- ---------------------------------------------------------------------------
-- `visivel_agenda` valia 'sim', que não é um dos valores que
-- `getUnidadeColaboradoresServicos()` aceita ('ext' ou 'ext_int') -- então a
-- unidade voltava sem colaborador nenhum. E `getAgendaAberta()` lê o horário
-- do dia da semana: sem abertura e fechamento, a agenda nunca abre e o
-- endpoint de disponibilidade responde `sucesso: false` em qualquer data.
UPDATE usuarios
   SET visivel_agenda     = 'ext_int',
       ordernacao_app     = 1,
       tempo_atendimento  = 20,
       segunda_abertura   = '08:00:00', segunda_fechamento = '20:00:00',
       terca_abertura     = '08:00:00', terca_fechamento   = '20:00:00',
       quarta_abertura    = '08:00:00', quarta_fechamento  = '20:00:00',
       quinta_abertura    = '08:00:00', quinta_fechamento  = '20:00:00',
       sexta_abertura     = '08:00:00', sexta_fechamento   = '20:00:00',
       sabado_abertura    = '08:00:00', sabado_fechamento  = '20:00:00',
       domingo_abertura   = '08:00:00', domingo_fechamento = '20:00:00'
 WHERE id = 90001000;

-- ---------------------------------------------------------------------------
-- Banners do aplicativo
-- ---------------------------------------------------------------------------
-- Só o app consome este endpoint: nenhuma tela do ERP o exibe, então o
-- snapshot é a única coisa que perceberia uma mudança de formato.
INSERT INTO app_banners (id, descricao, arquivo, status, data_criacao) VALUES
    (90001000, 'Banner de contrato', 'contrato.jpg', TRUE, '2026-01-01 00:00:00');

-- ---------------------------------------------------------------------------
-- A biblioteca de arquivos (22/10/2026, a fatia ARQUIVOS-SERVIDOR; a F1 de
-- docs/f3-telas-restantes/tela-arquivos.md)
-- ---------------------------------------------------------------------------
-- Uma categoria ativa e uma inativa, e quatro arquivos que cobrem o que a
-- `/adm/api/arquivos` separa: dois ativos da mesma subcategoria COM A MESMA
-- descricao (a secao que a mostra uma vez, como os Materiais), um inativo (so o
-- administrador que cadastra o ve) e um ativo de categoria inativa (ninguem o
-- ve pela biblioteca). Ate aqui as duas tabelas tinham 0 linhas nas fixtures.
--
-- NENHUM DESTES NOMES EXISTE NO DISCO, de proposito: os casos em processo usam o
-- armazenamento falso (`Armazenamento::trocar`), e o ensaio do nginx
-- (`scripts/ensaiar-arquivos-adm-api.php`) cria o arquivo do 90001780 em
-- `public/arquivos`, confere e o apaga no `finally`. O nome tem a forma do
-- gerado (`RegraDoArquivo::nomeFisicoValido`), e o original comeca por
-- `arquivo-`, como na copia anonimizada.
INSERT INTO arquivos_categorias (id, nome, status, data_criacao) VALUES
    (90001780, 'Biblioteca de contrato', TRUE, '2026-01-01 00:00:00'),
    (90001781, 'Categoria inativa de contrato', FALSE, '2026-01-01 00:00:00');

INSERT INTO arquivos (id, categoria, subcategoria, descricao, nome, nome_original, nome_personalizado, extensao, hash, link, status, data_criacao) VALUES
    (90001780, 90001780, 'Ferramentas de contrato', 'O texto da subcategoria de contrato', 'fixture-contrato-ativo-1.pdf', 'arquivo-contrato-1.pdf', 'Manual de contrato', '.pdf', 'hash-de-contrato-1', FALSE, TRUE, '2026-01-01 00:00:00'),
    (90001781, 90001780, 'Ferramentas de contrato', 'O texto da subcategoria de contrato', 'fixture-contrato-ativo-2.xlsx', 'arquivo-contrato-2.xlsx', 'Planilha de contrato', '.xlsx', 'hash-de-contrato-2', FALSE, TRUE, '2026-01-01 00:00:00'),
    (90001782, 90001780, NULL, 'Um documento inativo', 'fixture-contrato-inativo.pdf', 'arquivo-contrato-3.pdf', 'Documento inativo de contrato', '.pdf', 'hash-de-contrato-3', FALSE, FALSE, '2026-01-01 00:00:00'),
    (90001783, 90001781, NULL, 'Um documento de categoria inativa', 'fixture-contrato-categoria-inativa.pdf', 'arquivo-contrato-4.pdf', 'Documento da categoria inativa', '.pdf', 'hash-de-contrato-4', FALSE, TRUE, '2026-01-01 00:00:00');

-- ---------------------------------------------------------------------------
-- Agenda: disponibilidade do profissional, e o próximo agendamento do cliente
-- ---------------------------------------------------------------------------
-- Duas linhas com propósitos diferentes:
--   * a de 2026-12-24 ocupa um horário, para que o endpoint de
--     disponibilidade tenha o que descontar da grade;
--   * a de 2030-01-10 está no futuro em relação a qualquer execução plausível,
--     porque `selecionarProximoAgendamentosCliente()` filtra por data >= hoje.
--     Uma data próxima faria o teste apodrecer sozinho.
INSERT INTO agendas (id, colaborador, cliente, produto, hora, data, origem, checkin, checkout, status, data_criacao) VALUES
    (90001000, 90001000, 90001000, 90001000, '09:00', '2026-12-24 09:00:00', 'app', FALSE, FALSE, TRUE, '2026-01-01 00:00:00'),
    (90001001, 90001000, 90001000, 90001000, '10:00', '2030-01-10 10:00:00', 'app', FALSE, FALSE, TRUE, '2026-01-01 00:00:00');

-- O convidado e um cliente proprio, com telefone. Usar o cliente de balcao
-- (id 1) deixaria `convidado_telefone` nulo, e o contrato registra TIPO: o
-- aplicativo passaria a ter congelado `null` num campo que em producao e texto.
INSERT INTO clientes (id, unidade, nome, telefone, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001001, 90001000, 'Cliente Convidado Teste', '+5547900000000', TRUE, FALSE,
     FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- ---------------------------------------------------------------------------
-- Cupom válido do cliente
-- ---------------------------------------------------------------------------
-- `selecionarCuponsAtivosCliente()` exige usado = 0, cupom ativo e validade
-- >= hoje. A validade vai longe pelo mesmo motivo da agenda futura.
--
-- `regra` E `momento` VALEM O QUE O SISTEMA PRODUZ, e ate 09/09/2026 nao
-- valiam: estava `'produto'` e `'venda'`, e nenhum dos dois existe.
--
--   `Arrays::cuponsRegra()` so oferece `consumiu` e `nao_consumiu`;
--   `Arrays::cuponsMomentos()` so oferece `checkin` e `checkout`, e devolve
--   NULL para qualquer outra coisa -- entao a tela mostrava rotulo em branco.
--
--   `gerarCupons()` so e chamado com `'checkout'` (a chamada de `'checkin'`
--   esta comentada em `AgendasController:492`) e so age sobre as duas regras
--   acima. Com `produto`/`venda`, este cupom era ESTRUTURALMENTE INERTE: nunca
--   consultado, nunca selecionado.
--
-- Conferido na copia de producao: 144 cupons, ZERO fora das duas enumeracoes.
-- Os unicos discrepantes eram estas fixtures. Cenario que descreve um estado
-- que o sistema nao alcanca nao descreve o sistema.
--
-- E A CAMPANHA ESTA ENCERRADA (`data_limite` no passado), de proposito.
--
-- Com `regra`/`momento` validos, este cupom passou a ser SELECIONAVEL por
-- `gerarCupons()` -- e tres testes de `CupomTest` ficaram vermelhos na hora,
-- porque ele passou a concorrer com os cupons que aqueles testes criam. Foi a
-- prova de que ele estava inerte por acidente: um cupom no cenario que a
-- geracao nunca via.
--
-- `data_limite` no passado o tira da geracao -- `selecionarCuponsDiposniveis()`
-- exige `dataLimite IS NULL OR dataLimite >= hoje` -- e o mantem para
-- `selecionarCuponsAtivosCliente()`, que olha a validade do cupom JA EMITIDO e
-- nao a da campanha. E o estado real de uma campanha encerrada cujos cupons
-- emitidos continuam valendo, e nao um valor impossivel.
INSERT INTO cupons (id, unidade, regra, produto_regra, produto_oferecido, nome, desconto, validade, momento, data_limite, status, data_criacao) VALUES
    (90001000, 90001000, 'consumiu', 90001000, 90001000, 'Cupom de contrato', 10, 30, 'checkout', '2026-01-31', TRUE, '2026-01-01 00:00:00');

-- O cupom vai para o CONVIDADO (90001001), nao para o cliente principal.
-- `CupomTest::cuponsDoCliente()` conta `cupons_clientes WHERE cliente =
-- 90001000` e afirma quantidades exatas: um cupom de cenario ali dentro faz
-- tres testes financeiros falharem por um motivo que nada tem a ver com a
-- regra que eles verificam. Cenario de contrato e cenario de calculo precisam
-- de clientes distintos.
-- A VENDA QUE GEROU O CUPOM, e ela precisa existir.
--
-- `selecionarCuponsGerados()` -- a consulta da tela de estatisticas, e do
-- recurso `/adm/api/cupons/:id/emitidos` -- faz `JOIN cupcli.venda`, INNER. Sem
-- venda, a linha de `cupons_clientes` some da consulta, e o endereco responde
-- 200 com lista vazia.
--
-- Foi assim que a guarda `PRECISA_TRAZER` do medidor reprovou a decima quarta
-- fatia na CI, em 09/09/2026: *"A MEDICAO FICOU CEGA"*. O endpoint estava
-- inteiro; o cenario e que nao o exercitava.
--
-- E A VENDA E DO MESMO CLIENTE, de proposito. `gerarCupons()` faz
-- `setVenda($venda)` e `setCliente($cliente)` com `$cliente` vindo daquela
-- venda: os dois sempre casam. Apontar para a venda de outra pessoa criaria um
-- estado que o sistema nao produz -- o defeito que o D140 acabou de tirar
-- daqui.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp,
     nps_notificacao, nps_respondido, msg_rel_sem_retorno,
     valor_total, valor_recebido, data_criacao) VALUES
    (90001002, 90001000, 90001001, 90001000, 1, FALSE,
     0, 0, 0, 60.00, 60.00, '2026-02-14 11:00:00');

INSERT INTO cupons_clientes (id, cupom, venda, cliente, validade, usado, status, data_criacao) VALUES
    (90001000, 90001000, 90001002, 90001001, '2030-12-31', FALSE, TRUE, '2026-01-01 00:00:00');

-- ---------------------------------------------------------------------------
-- Sorteio do cliente
-- ---------------------------------------------------------------------------
-- `selecionarSorteiosPorCliente()` chega ao cliente por dentro da venda
-- (sorteios_vendas -> vendas -> cliente), então a venda precisa existir.
--
-- Ela nasce CANCELADA (status = 0) de propósito: os relatórios financeiros a
-- descartam, e a consulta do sorteio não olha o status da venda. Assim o
-- cenário do contrato não mexe em nenhum número que a caracterização confere.
-- A venda nao tem coluna de unidade: ela chega la por caixa -> usuario ->
-- unidade. O caixa 90001000 ja vem das fixtures.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao, nps_respondido, msg_rel_sem_retorno, data_criacao) VALUES
    (90001000, 90001000, 90001000, 90001000, 0, FALSE, 0, 0, 0, '2026-01-01 00:00:00');

-- UMA COMANDA ABERTA (`status = 3`, D51), e ela existe por causa de uma cegueira.
--
-- `GET /adm/api/comandas` lista comandas ABERTAS. A venda acima tem `status = 0`,
-- e por isso a listagem vinha respondendo 200 com `dados: []` desde que o
-- medidor de `/adm/api` foi escrito: rota, sessao e ACL provadas, e o formatador
-- do recurso nunca chamado. Quem descobriu foi a guarda `PRECISA_TRAZER` do
-- proprio medidor, na primeira vez que rodou.
--
-- POR QUE UMA LINHA NOVA, e nao mudar o `status` da de cima: a venda 90001000 e
-- cenario de instantaneo de contrato congelado (D5) e de relatorio. Mexer no
-- status dela mudaria o que dezenas de medidas veem, para consertar uma.
--
-- Ela fica SEM item e SEM pagamento de proposito. O medidor chama os endpoints
-- de escrita com `:id = 90001000` -- a fechada --, e e de la que vem o 409 que
-- prova a guarda. Esta aqui e so para a leitura ter o que ler.
--
-- O CLIENTE E O CONVIDADO (90001001), e nao o principal. `comandaAbrir()` NAO
-- cria uma segunda comanda para quem ja tem uma aberta -- e a correcao do D52,
-- a comanda fantasma --, e a chave desse reaproveitamento e o CLIENTE. Com o
-- cliente 90001000 aqui, `ComandaFantasmaTest::testPrimeiraAberturaCriaComanda`
-- fica vermelho: a "primeira" abertura passa a reaproveitar esta linha. Vermelho
-- correto, alias -- foi o teste fazendo exatamente o que foi escrito para fazer.
-- E A DATA E DE HOJE, pelo mesmo motivo que a do caixa acima.
--
-- `CronJobService::comandasCancelar()` cancela toda comanda aberta ha mais de
-- tres dias. Com data fixa em janeiro, a linha nascia ja vencida: a medicao roda
-- as rotinas de cron ANTES dos endpoints, o cron cancelava esta comanda
-- (`status` 3 -> 0) e a listagem voltava a sair vazia -- agora nao por cenario
-- errado, mas porque o sistema fez o que devia. Comanda aberta so existe
-- enquanto e recente; e essa a natureza da coisa, e a fixture tem de respeita-la.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao, nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, desconto_total, data_criacao) VALUES
    (90001001, 90001000, 90001001, 90001000, 3, FALSE, 0, 0, 0, 0, 0, 0, CURRENT_DATE + INTERVAL '9' HOUR);

-- `data_sorteio` preenchida de proposito: e ela que faz a acao chamar
-- `validarGanhador()` e devolver o campo `ganhador` de verdade. Vazia, o
-- contrato congelaria `data_sorteio: null` e o ramo do ganhador nunca seria
-- exercitado.
--
-- Ja o campo `status` da RESPOSTA sai nulo faca o que fizer: a acao chama
-- `Arrays::marketingSorteiosStatus($sorteio['nome'], false)` -- passa o NOME
-- onde a funcao espera a chave do status. O aplicativo sempre recebeu null
-- ali, e o snapshot registra isso porque e o contrato de verdade. Ver D56.
INSERT INTO sorteios (id, nome, data_inicio, data_fim, data_sorteio, status, data_criacao) VALUES
    (90001000, 'Sorteio de contrato', '2026-01-01', '2030-12-31',
     '2026-06-01 12:00:00', 'finalizado', '2026-01-01 00:00:00');

INSERT INTO sorteios_vendas (id, sorteio, venda, data, ganhador) VALUES
    (90001000, 90001000, 90001000, '2026-01-01 00:00:00', FALSE);

-- ---------------------------------------------------------------------------
-- Indicação feita pelo cliente
-- ---------------------------------------------------------------------------
-- `listarPorClienteIndicador()` busca por quem INDICOU. O convidado é o
-- cliente de balcão (id 1), que já existe e serve como qualquer outro.


-- A indicacao ja virou venda: sem `data_adesao`, `data_venda` e `comissao`
-- preenchidos, os tres entrariam no contrato como `null` -- de novo, tipo
-- errado para o que o aplicativo recebe quando a indicacao rende.
INSERT INTO indicacoes (id, unidade, cliente, convidado, url, data_convite, data_adesao, data_venda, comissao) VALUES
    (90001000, 90001000, 90001000, 90001001, 'https://exemplo/indicacao/contrato',
     '2026-01-01 00:00:00', '2026-01-02 00:00:00', '2026-01-03 00:00:00', 15.5);


-- ---------------------------------------------------------------------------
-- Categoria de serviço, e a unidade completa
-- ---------------------------------------------------------------------------
-- `selecionarServicosApp()` monta a resposta a partir das áreas de atuação e
-- só então busca os produtos de cada uma. Sem nenhuma área, a lista de
-- categorias nasce vazia e o endpoint devolve `sucesso: false` -- que era
-- exatamente o que o snapshot de `servicos-selecionar` guardava.
INSERT INTO areas_atuacao (id, nome, status, data_criacao) VALUES
    (90001000, 'Barbearia Teste', TRUE, '2026-01-01 00:00:00');

UPDATE produtos SET area = 90001000 WHERE id IN (90001000, 90001003);

-- A ETIQUETA DO CENARIO (D241, 27/09/2026). No ERP, area e etiqueta sao
-- obrigatorias no cadastro de servico, e a API passou a exigi-las tambem: sem
-- uma etiqueta ativa, o cadastro de servico pela API nao teria o que escolher.
-- Os servicos da fixture continuam sem etiqueta, como 516 dos ativos da copia.
-- O ID NAO E O DA AREA (90001000): com os dois iguais, trocar etiqueta por area
-- num caso passava verde (revisao adversarial).
INSERT INTO produtos_tags (id, nome, status, data_criacao) VALUES
    (90001700, 'Etiqueta Teste', TRUE, '2026-01-01 00:00:00');

-- A AREA 3 EXISTE PORQUE O CODIGO PEDE O NUMERO 3, e nao uma area qualquer.
--
-- `DashboardColaboradorRepository::dadosRelatorio()` junta a area de atuacao do
-- colaborador e exige `are.area = :area` com `area = 3` FIXO no controlador. Na
-- copia de producao, 3 e "Barbeiro" -- o dashboard e de barbeiros, por decisao
-- de produto. So que um cenario que inventa os proprios ids nunca satisfaz um
-- filtro escrito em cima de um id de producao: a tela respondia 200 com a
-- pagina montada e nenhuma linha, e a medicao chamava isso de verde.
--
-- Mesma familia do `grupo = 1` que a rotina de evasao usa (1 e "Colaborador",
-- 1.748 usuarios). Sao numeros magicos que valem uma linha do banco.
--
-- O INSERT e condicional, como o do cliente 1: quando estas fixtures entram num
-- banco que ja tem os dados de producao, a linha real fica.
INSERT INTO areas_atuacao (id, nome, status, data_criacao)
SELECT 3, 'Barbeiro', TRUE, '2026-01-01 00:00:00'
 WHERE NOT EXISTS (SELECT 1 FROM areas_atuacao WHERE id = 3);

-- A SEGUNDA LINHA E DE OUTRA AREA, e ela existe para o filtro poder ser
-- FALSIFICADO.
--
-- `UsuarioRepository::selecionarColaboradoresUnidadeDashboard()` -- o combo de
-- colaborador de DOIS paineis -- faz `INNER JOIN usu.areasAtuacao are` e exige
-- `are.area = 3`. Com uma linha so no cenario, o JOIN sozinho ja separava quem
-- tem area de quem nao tem, e neutralizar a comparacao `are.area = 3` NAO mudava
-- o resultado: medido em 12/09/2026, a falsificacao passou verde.
--
-- Dando ao gerente a area 90001000 -- que o cenario tambem cria --, passa a haver
-- alguem COM area e SEM a area 3. Agora o filtro e observavel: com ele, o painel
-- lista um; sem ele, dois.
INSERT INTO usuarios_areas (usuario, area) VALUES
    (90001000, 3),
    (90001001, 90001000);

-- E A AREA 3 PRECISA DE UM SERVICO, senao ela quebra o contrato congelado.
--
-- `selecionarServicosApp()` devolve TODAS as areas ativas, cada uma com a sua
-- lista de servicos. Area sem servico entra na resposta com lista vazia -- e
-- `ContratoTestCase::semCarga()` desce pela estrutura inteira e condena o
-- instantaneo se achar QUALQUER lista vazia dentro. Resultado: dois contratos
-- do aplicativo caiam com "a resposta veio vazia", sobre uma resposta que tinha
-- unidade, colaboradores e servicos.
--
-- Ou seja: a area nova nao pode existir sozinha. Ela entra com um servico.
INSERT INTO produtos (id, unidade, area, tipo, nome, valor_compra, valor_venda,
     visivel_app, insumo, status, data_criacao) VALUES
    (90001005, 90001000, 3, 'ser', 'Barba Teste', 0, 45.00, TRUE, FALSE, TRUE, '2026-01-01 00:00:00');

-- Estes quatro campos vinham nulos, e o contrato registra tipo: gravariam
-- `null` onde produção entrega texto. Preenchê-los faz o snapshot descrever o
-- formato que o aplicativo realmente recebe.
UPDATE unidades
   SET estado    = 'SC',
       latitude  = '-26.9187',
       longitude = '-48.6256',
       telefone  = '(47) 3000-0000'
 WHERE id = 90001000;

-- ---------------------------------------------------------------------------
-- Cenário do contrato fiscal — `/api/unidade/vendas`, `vendasV2`, `vendasV3`
-- ---------------------------------------------------------------------------
-- Estes três endpoints devolvem `numero_nf`, `tipo_nf`, `venda_bruta` e
-- `forma_pagamento`: é integração contábil, e o consumidor é externo. A prova
-- disso é que foram versionados TRÊS vezes -- ninguém versiona o que pode
-- atualizar em conjunto.
--
-- São o único ponto da API que autentica: exigem `hash` batendo com o da
-- unidade. Ainda assim não tinham teste de contrato nenhum até 29/08/2026.
--
-- UNIDADE PRÓPRIA, DE PROPÓSITO. A consulta chega à unidade pelo USUÁRIO da
-- venda (`ven.usuario` -> `usu.unidade`), e exige `status = 1` -- venda
-- concluída. Pôr uma venda concluída na unidade 90001000 mudaria os números que
-- a caracterização financeira confere, exatamente como o cupom de contrato
-- quebrou três testes ao morar no cliente errado.
--
-- Cenário de contrato e cenário de cálculo precisam de sujeitos diferentes.

INSERT INTO unidades (id, tipo, pais, cidade, bairro, endereco, numero,
     royltes_produto_barbearia, royltes_produto_emporio, royltes_servico, royltes_lavavip,
     visivel_app, reducao_potencial, agenda_primeiro_nome,
     fidelizacao_unidade_dias, fidelizacao_unidade_visitas, cashback,
     whatsapp_ativo, hash, nome, status, data_criacao) VALUES
    (90001100, 'PROPRIA', 'Brasil', 'Itajai', 'Centro', 'Rua Fiscal', '10',
     5, 5, 10, 5, FALSE, 0, TRUE, 90, 3, 0,
     FALSE, 'hash-teste-90001100', 'Unidade Fiscal Teste', TRUE, '2026-01-01 00:00:00');

INSERT INTO usuarios (id, unidade, grupo, nome, email, login, sexo, senha,
     visivel_agenda, visivel_pdv, ordernacao_app, status, data_criacao) VALUES
    (90001100, 90001100, 90001000, 'Caixa Fiscal Teste', 'fiscal@teste.invalid', 'fiscal.teste', 'M',
     '$2y$10$abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR', 'nao', TRUE, 1, 1, '2026-01-01 00:00:00');

INSERT INTO caixas (id, usuario, valor_inicial, data_criacao, status) VALUES
    (90001100, 90001100, 0.00, CURRENT_DATE + INTERVAL '8' HOUR, TRUE);

-- Cliente proprio, com telefone e CEP PREENCHIDOS. O `vendasV3` e centrado no
-- cliente e devolve os dois; com o cliente 90001000, que os tem vazios, o
-- contrato gravaria `null` onde producao entrega texto -- o mesmo defeito que o
-- D55 encontrou em `unidades-selecionar`.
-- Endereco COMPLETO e `consumo` preenchido: o `vendasV2` devolve bairro,
-- cidade, estado e consumo, e todos saiam como `null` no snapshot enquanto o
-- cliente os tinha vazios. O contrato registra TIPO, entao gravar assim
-- congelaria `null` onde producao entrega texto -- e o consumidor externo
-- passaria a ter congelado um contrato que nunca recebe.
INSERT INTO clientes (id, unidade, nome, telefone, telefone_sem_mascara, cpf, rg, email,
     cep, estado, cidade, bairro, data_nascimento,
     logradouro, numero, consumo, origem, programa_fidelidade,
     cadastro_restricao_agendamento, fidelizado_colaborador, fidelizado_unidade,
     pesquisa_satisfacao_whatsapp, status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001100, 90001100, 'Cliente Fiscal Teste', '+55 (47) 3000-0000', '+5547300000000',
     '000.000.000-00', 'XX-0.000.000', 'fiscal@teste.invalid',
     '88300-000', 'SC', 'Itajai', 'Centro', '1990-05-20', 'Rua Fiscal', '10', 150.00, 'app', TRUE,
     FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- Duas vendas concluídas, com data FIXA: o contrato registra o formato de
-- `data_hora`, e uma data relativa faria o snapshot mudar sozinho a cada dia.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao,
     nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, data_criacao) VALUES
    (90001100, 90001100, 90001100, 90001100, 1, FALSE, 0, 0, 0, 89.90, 89.90, '2026-03-10 10:15:00'),
    (90001101, 90001100, 90001100, 90001100, 1, FALSE, 0, 0, 0, 150.00, 150.00, '2026-03-10 16:40:00');

-- UMA VENDA CONCLUIDA NA UNIDADE 90001000, com item descontado.
--
-- As duas vendas acima sao da unidade 90001100, e por isso nao aparecem em
-- relatorio nenhum da unidade que o medidor pede. `relatorioVendasProduto()`
-- filtra por `usu.unidade = :unidade` -- a unidade do USUARIO que vendeu --, e
-- `listagemIndexRelatorioDescontos()` faz o mesmo por `uni.id`. Sem esta venda,
-- o relatorio de produtos e o de descontos respondiam 200 dizendo "Nenhum
-- registro localizado", e a medicao chamava isso de verde (D113).
--
-- O DESCONTO ESTA NO ITEM E NA VENDA, e as duas coisas sao necessarias: a
-- listagem de descontos e enraizada no ITEM (`pro.valorDesconto > 0`) e ainda
-- exige `ven.descontoTotal > 0` na venda. Com o desconto so num dos dois lugares
-- o relatorio continuaria vazio -- e vazio sem erro, que e o que este cenario
-- existe para impedir.
--
-- A data e a mesma da ultima visita do `Cliente Historico Teste`: e a venda que
-- justifica aquela visita.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao,
     nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, desconto_total, data_criacao) VALUES
    (90001010, 90001000, 90001010, 90001000, 1, FALSE, 0, 0, 0, 79.90, 79.90, 10.00, '2026-03-10 10:15:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto, desconto_motivo) VALUES
    (90001010, 90001000, 90001000, 1, 89.90, 79.90, 79.90, 10, 10.00, 'Marca do relatorio de descontos');

INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001010, 90001000, 79.90);

-- UMA RETIRADA DE PRODUTO, para o relatorio de retiradas ter linha.
--
-- `relatorioRetiradas()` pede `operacao = 'sai'`, `status = true` e a data no
-- periodo, e junta pela unidade do PRODUTO. Nao havia nenhuma linha em
-- `produtos_estoque` no cenario, e o relatorio respondia 200 dizendo "Nenhum
-- registro localizado" desde que passou a ser medido (D113).
-- O ID E EXPLICITO desde 08/09/2026, e nao era: a setima fatia expoe
-- `POST /adm/api/produtos/:id/estoque/:movimentacao/cancelamento`, e o medidor
-- precisa de um numero para pôr na rota. Sem id fixo, ele mediria o 404.
INSERT INTO produtos_estoque (id, operacao, produto, usuario, solicitado_por, quantidade, status, data_criacao) VALUES
    (90001000, 'sai', 90001001, 90001001, 90001000, 2, TRUE, '2026-03-10 12:00:00'),
    -- Uma ENTRADA tambem, porque a lista com um so tipo nao distingue
    -- `efeito` de `quantidade`: com saida sozinha, os dois teriam o mesmo
    -- sinal errado sem ninguem notar.
    (90001001, 'ent', 90001001, 90001001, NULL, 5, TRUE, '2026-03-11 09:00:00'),
    -- E UMA SEGUNDA SAIDA, de OUTRO produto e SEM solicitante. Acrescentada em
    -- 12/09/2026, e ela destrava duas coisas de `relatorioRetiradas()`:
    --
    --   o GROUP BY pro.id   -- com um produto so, "agrupar por produto" e "somar
    --                          tudo" dao o mesmo numero, e o teste nao saberia
    --                          diferenciar os dois;
    --   o LEFT JOIN de      -- dentro do recorte `operacao = 'sai'` todas as
    --   `solicitadoPor`        linhas tinham solicitante, entao o LEFT nunca era
    --                          exercitado como LEFT. Sem ele, esta linha sumiria
    --                          da listagem e ninguem veria.
    --
    -- O produto e o 90001002 (`proemp`) de proposito: e um tipo que movimenta
    -- estoque de verdade, ao contrario dos `ser` -- a regra que o D169 mediu.
    (90001002, 'sai', 90001002, 90001001, NULL, 3, TRUE, '2026-03-10 15:00:00');

-- UM RESULTADO DE NPS, para o relatorio de NPS ter numero.
--
-- O relatorio percorre os doze meses do ANO PEDIDO e so imprime o mes que tem
-- linha. O medidor pergunta pelo ano corrente, entao a fixture tambem tem de
-- ser do ano corrente -- por isso `EXTRACT(YEAR FROM CURRENT_DATE)`, que os
-- dois bancos entendem, e nao um 2026 fixo que envelheceria em janeiro.
--
-- `total_pesquisas_realizadas` e 4321 de proposito: e um numero que nao aparece
-- em nenhum outro canto da pagina, e e por ele que o medidor confere que a
-- tabela trouxe dado. O rotulo da unidade nao serviria -- ele e impresso mesmo
-- quando os doze meses estao vazios, que era exatamente o estado anterior.
INSERT INTO nps_resultados_unidades (unidade, mes, ano, nota_geral, nota_colaboradores,
     nota_recepcao, nota_experiencia, total_pesquisas_realizadas,
     total_promotores, total_passivos, total_detratores, data_criacao) VALUES
    (90001000, 3, EXTRACT(YEAR FROM CURRENT_DATE), 9.1, 9.4, 8.7, 9.0, 4321,
     3000, 900, 421, '2026-03-31 23:59:00');

-- UMA PESQUISA DE NPS RESPONDIDA, para o TXT do NPS ter linha (06/10/2026, D113).
--
-- O "Gerar TXT" do relatorio de NPS e o SEGUNDO passo de um fluxo de sessao: o
-- arquivo sai da lista que o detalhe da unidade (`unidadeDetalhes`) guardou na
-- sessao, e o detalhe le a tabela `nps` -- que nao tinha linha nenhuma no
-- cenario. O medidor de relatorios pedia o TXT direto, recebia 404, e o 404
-- passava como resposta legitima.
--
-- A DATA E FIXA, MARCO DE 2023, e o medidor pede esse mes. Um mes relativo a
-- hoje cruzaria com os casos que contam o NPS DO MES CORRENTE da unidade
-- 90001000 (o `npsContabilizar` soma as respostas ja contabilizadas do mes), e
-- os outros anos ja tem dono: 2020 no `PesquisasNpsNoRelatorioTest`, 2025 no
-- `ProfissionalParceiroTest`. `contabilizado` vai TRUE pelo mesmo motivo: a rotina
-- so pega as que faltam contabilizar, e esta nao entra na conta de ninguem.
--
-- O cliente e o 90001010, que tem telefone: a linha do TXT e o primeiro nome e o
-- telefone, e o telefone e a marca.
INSERT INTO nps (id, unidade, cliente, nota_recepcao, nota_experiencia, nota_media, contabilizado, data) VALUES
    (90001000, 90001000, 90001010, 10, 10, 10, TRUE, '2023-03-15 10:00:00');

-- UM MOVIMENTO DE UNIDADE, para o grafico de fluxo ter numero.
--
-- `rel-fluxo-movimento/gerarGrafico` responde JSON, e respondia com ZERO em
-- todos os sete dias -- 200, sem erro, e sem nada dentro. A consulta pede
-- `dataInicio >= :inicio AND dataFim <= :fim`, com a janela montada a partir do
-- ANO CORRENTE, entao a linha usa `CURRENT_DATE` nas duas pontas: um dia so,
-- que cabe em qualquer janela que inclua hoje.
--
-- Os faturamentos sao repetidos de proposito (1111.11 em todos os dias): o que
-- se confere e que o numero ATRAVESSA a consulta, o calculo da media e a
-- serializacao, e um valor por dia bastaria para confundir qual e qual.
INSERT INTO dashboard_movimentos (unidade, ano, mes, data_inicio, data_fim,
     faturamento_segunda, faturamento_terca, faturamento_quarta, faturamento_quinta,
     faturamento_sexta, faturamento_sabado, faturamento_domingo, data_criacao) VALUES
    (90001000, EXTRACT(YEAR FROM CURRENT_DATE), EXTRACT(MONTH FROM CURRENT_DATE),
     CURRENT_DATE, CURRENT_DATE,
     1111.11, 1111.11, 1111.11, 1111.11, 1111.11, 1111.11, 1111.11, '2026-01-01 00:00:00');

-- UM MES DE DASHBOARD DO COLABORADOR, que alimenta duas telas e um JSON.
--
-- `dashboard_colaboradores` e a origem do Dashboard Colaboradores, do Radar de
-- Temperatura e do JSON `radar-temperatura/selecionarFaturamento` -- que
-- respondia `{"faturamento1":0,"faturamento2":0,"faturamento_per":0}`.
--
-- O periodo e comparado como `ano * 100 + mes`, entao ano e mes vem de
-- `EXTRACT(... FROM CURRENT_DATE)`: a janela pedida e relativa ao ano corrente,
-- e um mes fixo sairia dela com o tempo.
INSERT INTO dashboard_colaboradores (unidade, colaborador, ano, mes, nps, total_vendas,
     total_servicos_realizados, total_produtos_vendidos, total_produtos_vendidos_reais,
     media_servicos_cliente, media_produtos_cliente, media_itens_cliente, media_consumo_cliente,
     total_clientes_novos, total_clientes_antigos, total_clientes_geral,
     total_agendamentos_app, total_agendamentos_web, total_agendamentos_geral,
     agenda_horarios_disponiveis, agenda_ocupacao, fidelizacao, estrela, data_criacao) VALUES
    (90001000, 90001000, EXTRACT(YEAR FROM CURRENT_DATE), EXTRACT(MONTH FROM CURRENT_DATE),
     9, 2222.22, 7, 3, 180.00, 1.4, 0.6, 2.0, 79.90, 2, 5, 7, 4, 3, 7, 40, 17.5, 33.3, 3,
     '2026-01-01 00:00:00');

-- UM MES DE FATURAMENTO DA UNIDADE, para o Dashboard Faturamento ter numero.
--
-- Mesma familia das duas linhas acima, e mesmo cuidado com o tempo: o ano e o
-- mes vem de `EXTRACT(... FROM CURRENT_DATE)`, porque a tela pergunta pelo ano
-- corrente. O ticket medio e 3333.33 para ser um numero que so aparece se a
-- linha foi lida.
INSERT INTO dashboard_faturamento (unidade, ano, mes, total_clientes_novos,
     total_clientes_antigos, total_servicos_realizados, total_servicos_base,
     total_servicos_extra, total_produtos_vendidos, total_produtos_cabelo,
     total_produtos_barba, total_vendas, quantidade_vendas, media_servico_cliente,
     media_produto_cliente, gasto_por_cliente, ticket_medio_por_venda,
     crescimento_mes_porcentagem, crescimento_mes_reais, data_criacao) VALUES
    (90001000, EXTRACT(YEAR FROM CURRENT_DATE), EXTRACT(MONTH FROM CURRENT_DATE),
     2, 5, 7, 5, 2, 3, 2, 1, 9999.90, 3, 1.4, 0.6, 77.77, 3333.33, 12.5, 1110.00,
     '2026-01-01 00:00:00');

-- UM CURSO NA VIP CLASS, pelo mesmo motivo.
--
-- `listagemIndexAdmin()` filtra por `vip.status = :status`, e o relatorio manda
-- 1 por padrao. Sem vinculo de unidade nem de grupo, o `LEFT JOIN` deixa a linha
-- passar para qualquer unidade -- que e como um curso aberto a rede se comporta.
--
-- ATENCAO AO TIPO: `vipclass.status` e INTEIRO nos dois bancos, e nao booleano
-- como quase todo `status` deste schema. Escrever TRUE aqui quebra a carga no
-- PostgreSQL (D81 pelo avesso).
INSERT INTO vipclass (id, nome, descricao, carga_horaria, status, data_criacao) VALUES
    (90001000, 'Curso VIP Teste', 'Curso de teste para o relatorio da VIP Class', 4, 1, '2026-01-01 00:00:00');

-- OS TRES CURSOS DO ALUNO DA VIP CLASS (05/11/2026, a fatia 79, VIPCLASS-ALUNO-SERVIDOR; a F0
-- de `docs/f3-telas-restantes/tela-vipclass.md`). Ate aqui a fixture tinha so o curso vazio de
-- cima, e o recorte do aluno (o D359: a publicacao, a situacao e o pre-requisito) nao tinha onde
-- ser ensaiado. Um de cada forma que a regra (`RegraDoCursoVipClass::paraOAluno`) distingue:
--
--   90079001  aberto: sem unidade nem grupo ligados, vale para todos (o vinculo vazio quer dizer
--             TODOS, e nao nenhum). 2 aulas, 2 perguntas com 3 respostas cada, 1 material.
--   90079002  restrito: so a unidade 90001000 E o grupo 'Colaborador (teste)'. O Colaborador
--             Teste o ve; o Gerente Teste (outro grupo, a mesma unidade), nao.
--   90079003  com pre-requisito: o 90079001. O Gerente Teste o concluiu (a conclusao abaixo) e
--             ve o 90079003 aberto; o Colaborador Teste, que nao o concluiu, ve o cadeado.
--
-- Os ids estao na faixa 90079xxx, varrida em tests, scripts, frontend/src, docs e module: livre.
-- `vipclass.status` e INTEIRO (o aviso de cima); `status` das aulas, das perguntas, das
-- respostas e dos materiais, e a `resposta_correta`, sao BOOLEANOS nos dois bancos (o D97 e o
-- D117 pelo avesso). Nenhum curso inativo aqui: o `VipClassNoRelatorioTest` conta que pedir o
-- inativo nao traz nada; quem precisa do inativo o faz na propria transacao.
--
-- O MATERIAL NAO TEM ARQUIVO: o download dele da 404 neste banco (os testes trocam o
-- `Armazenamento` por um duble). O hash e o da URL-capacidade (`?i=&h=`).
INSERT INTO vipclass (id, requisito, nome, descricao, carga_horaria, capa, certificado, hash, status, data_criacao) VALUES
    (90079001, NULL,     'Curso VIP Aberto (teste)',     'Aberto a rede inteira',             2, 'padrao.jpg', 'padrao.jpg', 'vc79aberto', 1, '2026-01-02 00:00:00'),
    (90079002, NULL,     'Curso VIP Restrito (teste)',   'So a unidade e o grupo do cenario', 1, 'padrao.jpg', 'padrao.jpg', 'vc79restri', 1, '2026-01-03 00:00:00'),
    (90079003, 90079001, 'Curso VIP Com Requisito (teste)', 'Depois do aberto',               3, 'padrao.jpg', 'padrao.jpg', 'vc79requis', 1, '2026-01-04 00:00:00');

INSERT INTO vipclass_unidades (id, vipclass, unidade) VALUES
    (90079001, 90079002, 90001000);
INSERT INTO vipclass_grupos (id, vipclass, grupo) VALUES
    (90079001, 90079002, 90001000);

INSERT INTO vipclass_aulas (id, vipclass, plataforma, descricao, link, hash, ordenacao, status, data_criacao) VALUES
    (90079001, 90079001, 'youtube', 'Aula 1 do aberto',     'https://www.youtube.com/embed/aaaaaaaaaa1', 'va79a1', 1, TRUE, '2026-01-02 00:00:00'),
    (90079002, 90079001, 'youtube', 'Aula 2 do aberto',     'https://www.youtube.com/embed/aaaaaaaaaa2?si=rastreio', 'va79a2', 2, TRUE, '2026-01-02 00:00:00'),
    (90079003, 90079002, 'youtube', 'Aula 1 do restrito',   'https://www.youtube.com/embed/rrrrrrrrrr1', 'va79r1', 1, TRUE, '2026-01-03 00:00:00'),
    (90079004, 90079003, 'youtube', 'Aula 1 do requisito',  'https://www.youtube.com/embed/qqqqqqqqqq1', 'va79q1', 1, TRUE, '2026-01-04 00:00:00');

INSERT INTO vipclass_checkpoints_perguntas (id, vipclass, pergunta, hash, ordenacao, status, data_criacao) VALUES
    (90079001, 90079001, 'Primeira pergunta do aberto', 'vp79a1', 1, TRUE, '2026-01-02 00:00:00'),
    (90079002, 90079001, 'Segunda pergunta do aberto',  'vp79a2', 2, TRUE, '2026-01-02 00:00:00'),
    (90079003, 90079002, 'Pergunta do restrito',        'vp79r1', 1, TRUE, '2026-01-03 00:00:00'),
    (90079004, 90079003, 'Pergunta do requisito',       'vp79q1', 1, TRUE, '2026-01-04 00:00:00');

-- UMA CORRETA POR PERGUNTA, a ultima de cada uma nas do aberto (a ordem das respostas e a do id).
INSERT INTO vipclass_checkpoints_respostas (id, pergunta, resposta, resposta_correta, hash, status, data_criacao) VALUES
    (90079001, 90079001, 'Errada A da primeira', FALSE, 'vr79a1', TRUE, '2026-01-02 00:00:00'),
    (90079002, 90079001, 'Errada B da primeira', FALSE, 'vr79a2', TRUE, '2026-01-02 00:00:00'),
    (90079003, 90079001, 'Certa da primeira',    TRUE,  'vr79a3', TRUE, '2026-01-02 00:00:00'),
    (90079004, 90079002, 'Errada A da segunda',  FALSE, 'vr79a4', TRUE, '2026-01-02 00:00:00'),
    (90079005, 90079002, 'Errada B da segunda',  FALSE, 'vr79a5', TRUE, '2026-01-02 00:00:00'),
    (90079006, 90079002, 'Certa da segunda',     TRUE,  'vr79a6', TRUE, '2026-01-02 00:00:00'),
    (90079007, 90079003, 'Certa do restrito',    TRUE,  'vr79r1', TRUE, '2026-01-03 00:00:00'),
    (90079008, 90079003, 'Errada do restrito',   FALSE, 'vr79r2', TRUE, '2026-01-03 00:00:00'),
    (90079009, 90079004, 'Certa do requisito',   TRUE,  'vr79q1', TRUE, '2026-01-04 00:00:00'),
    (90079010, 90079004, 'Errada do requisito',  FALSE, 'vr79q2', TRUE, '2026-01-04 00:00:00');

INSERT INTO vipclass_materiais (id, vipclass, descricao, arquivo, extensao, nome_original, hash, status, data_criacao) VALUES
    (90079001, 90079001, 'Apostila do aberto', '90079001-90079001.pdf', '.pdf', 'apostila-do-aberto.pdf', 'vm79aberto', TRUE, '2026-01-02 00:00:00');

-- A CONCLUSAO DO GERENTE no aberto: o requisito do 90079003 feito.
INSERT INTO vipclass_checkpoints_usuarios (id, vipclass, usuario, nota, data) VALUES
    (90079001, 90079001, 90001001, 100, '2026-01-05 10:00:00');

-- OS QUATRO ASSISTENTES DA FIXTURE (04/10/2026, a F1 dos Assistentes,
-- `docs/f3-telas-restantes/tela-assistentes.md`). Ate aqui nenhum dos dois bancos
-- tinha assistente de fixture, e o recorte do abrir (o D340) nao tinha onde ser
-- ensaiado. Um de cada forma que a regra distingue:
--
--   90001000  so para o grupo Gerente (teste), em todas as unidades
--   90001001  so para o grupo Colaborador (teste), e so na unidade 90001000
--   90001002  sem vinculo nenhum -- e o vinculo vazio quer dizer TODOS e TODAS
--             (o D343: a documentacao lia o contrario)
--   90001003  inativo, sem vinculo: nao aparece nem abre para ninguem
--
-- O HTML FICA VAZIO, como o `endurecer-base-teste.sql` deixa a base de teste
-- (04/10/2026, a revisao da F1). A primeira versao gravava o molde com um
-- `chatbot-id` falso -- e o molde carrega o script do Zapier: o abrir de um destes
-- no navegador, contra o banco de contrato, levava a conversa para a conta de
-- PRODUCAO. Com o vazio, o abrir mostra a pagina sem a conversa, e o recorte (200
-- ou 404) e o mesmo. Os casos que precisam do molde gravam o seu, com id falso, e
-- leem a resposta do controller em processo, sem executar o script; o
-- `AssistentesPelosControllersTest` confere que nenhum destes vira conversa.
--
-- `status` e INTEIRO nos dois bancos, como o da VIP Class logo acima.
INSERT INTO assistentes (id, nome, descricao, capa, status, iframe, data_criacao) VALUES
    (90001000, 'Assistente do gerente (teste)', 'Para o grupo Gerente (teste)', 'padrao.jpg', 1, '',
     '2026-01-01 00:00:00'),
    (90001001, 'Assistente do colaborador (teste)', 'Para o grupo Colaborador (teste), na unidade 90001000', 'padrao.jpg', 1, '',
     '2026-01-01 00:00:00'),
    (90001002, 'Assistente da rede (teste)', 'Sem vinculo: todos os grupos, todas as unidades', 'padrao.jpg', 1, '',
     '2026-01-01 00:00:00'),
    (90001003, 'Assistente inativo (teste)', 'Inativo: nao aparece nem abre', 'padrao.jpg', 0, '',
     '2026-01-01 00:00:00');

INSERT INTO assistentes_grupos (id, assistente, grupo) VALUES
    (90001000, 90001000, 90001001),
    (90001001, 90001001, 90001000);

INSERT INTO assistentes_unidades (id, assistente, unidade) VALUES
    (90001000, 90001001, 90001000);

-- A VENDA DA EVASAO, na mesma data da ultima visita daquele cliente.
--
-- Ela e do usuario 90001002 (grupo 1) e o item e do mesmo colaborador: a
-- consulta da evasao junta `venpro.colaborador`, e nao o vendedor da venda.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao,
     nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, data_criacao) VALUES
    (90001020, 90001000, 90001020, 90001003, 1, FALSE, 0, 0, 0, 89.90, 89.90,
     CURRENT_DATE - INTERVAL '8' MONTH);

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto) VALUES
    (90001020, 90001003, 90001000, 1, 89.90, 89.90, 89.90, 10, 0);

INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001020, 90001000, 89.90);

-- A segunda venda tem DOIS pagamentos de propósito: `forma_pagamento` é montada
-- concatenando as abreviações -- `(DIN,CRE)` -- e com um pagamento só esse laço
-- nunca seria exercitado.
INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001100, 90001000,  89.90),
    (90001101, 90001000, 100.00),
    (90001101, 90001001,  50.00);

-- Os itens da venda existem porque o `vendasV2` devolve `produtos` -- e sem
-- eles a lista vinha vazia. `ContratoTestCase::assertContrato()` RECUSOU gravar
-- o snapshot nesse estado, que e precisamente o que ele foi escrito para fazer
-- (D55): um contrato com lista vazia nao descreve nada do que ha dentro dela.
-- O `getConsumoCliente` devolve `pontuacoes` a partir de clientes_creditos.
-- Sem esta linha a lista vinha vazia, e o guarda do contrato recusava gravar --
-- corretamente, porque uma lista vazia nao diz o que ha dentro de um item.
INSERT INTO clientes_creditos (id, unidade, cliente, valor, valor_pf, pontuacao, pontuacao_validade, data_criacao) VALUES
    (90001100, 90001100, 90001100, 40.00, 0, 800, '2027-03-10', '2026-03-10 16:40:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto) VALUES
    (90001100, 90001100, 90001000, 1,  89.90,  89.90,  89.90, 10, 0),
    (90001101, 90001100, 90001000, 1,  89.90,  89.90,  89.90, 10, 0),
    (90001101, 90001100, 90001001, 1,  60.10,  60.10,  60.10,  5, 0);

-- ---------------------------------------------------------------------------
-- O cenario da AUTENTICACAO DO CLIENTE (D59) -- `/api/v4`
-- ---------------------------------------------------------------------------
-- FAIXA 90001000-90001199: e das FIXTURES. De 90001200 para cima e dos TESTES,
-- que inserem linhas proprias dentro da transacao revertida.
--
-- A regra nasceu de uma colisao, em 03/09/2026. Este cenario usava 90001200, e
-- `AutorizacaoFiadoTest` cria a venda dele com esse mesmo id -- em outra tabela,
-- ate o dia em que este bloco tambem passou a criar uma venda.
--
-- E SO A EXECUCAO NO FORMATO DO CI ACUSOU. A suite de caracterizacao roda
-- localmente contra o banco de desenvolvimento, onde estas fixtures NAO estao
-- carregadas: a colisao era invisivel aqui e certa la. Ver
-- `scripts/rodar-caracterizacao-como-ci.sh`.
-- ---------------------------------------------------------------------------
-- Telefone PROPRIO, e nao o do cliente 90001100, de proposito: aquele numero
-- ja e a carga congelada de `cliente-selecionar-autenticado`, e acrescentar um
-- irmao nele mudaria aquele snapshot sem que a mudanca fosse sobre contrato.
--
-- Sao dois clientes no MESMO telefone, porque e o caso normal e nao a exececao:
-- 5.670 telefones da base tem mais de um cliente ativo, e o pior caso tem 354
-- (D41). Um teste com um cliente so provaria a metade facil.
--
-- A unidade tem WhatsApp ativo porque o codigo so e enfileirado quando ha por
-- onde entregar. Sem isso o fluxo nao comecaria, e o teste diria "nao
-- autenticou" onde a causa e "nao havia canal".
INSERT INTO unidades (id, tipo, pais, estado, cidade, bairro, endereco, numero,
     royltes_produto_barbearia, royltes_produto_emporio, royltes_servico, royltes_lavavip,
     visivel_app, reducao_potencial, agenda_primeiro_nome,
     fidelizacao_unidade_dias, fidelizacao_unidade_visitas, cashback,
     whatsapp_ativo, whatsapp_instancia, whatsapp_api_key, whatsapp_provedor,
     hash, nome, status, data_criacao) VALUES
    -- `visivel_app` FALSE, e isto NAO e detalhe. Com TRUE esta unidade entra em
    -- `/api/agendas/getUnidades`, e como ela nao tem estado, telefone nem
    -- coordenadas, o snapshot daquela rota passou a congelar `null` onde a
    -- producao entrega texto -- o mesmo defeito que o D55 encontrou. Medido:
    -- quatro campos viraram "null" na primeira gravacao.
    (90001150, 'PROPRIA', 'Brasil', 'SC', 'Itajai', 'Centro', 'Rua da Sessao', '20',
     5, 5, 10, 5, FALSE, 0, TRUE, 90, 3, 0,
     TRUE, 'instancia-de-fixture', 'chave-de-fixture-sem-valor', 'evolution',
     'hash-teste-90001150', 'Unidade Sessao Teste', TRUE, '2026-01-01 00:00:00');

INSERT INTO clientes (id, unidade, nome, telefone, telefone_sem_mascara, cpf, rg, email,
     cep, estado, cidade, bairro, data_nascimento,
     logradouro, numero, consumo, origem, programa_fidelidade,
     cadastro_restricao_agendamento, fidelizado_colaborador, fidelizado_unidade,
     pesquisa_satisfacao_whatsapp, status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001150, 90001150, 'Titular da Linha', '+55 (47) 3200-0000', '+5547320000000',
     '111.111.111-11', 'XX-1.111.111', 'titular@teste.invalid',
     '88300-000', 'SC', 'Itajai', 'Centro', '1990-05-20', 'Rua da Sessao', '20', 100.00, 'app', TRUE,
     FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE),
    (90001151, 90001150, 'Filho na Mesma Linha', '+55 (47) 3200-0000', '+5547320000000',
     '222.222.222-22', 'XX-2.222.222', 'filho@teste.invalid',
     '88300-000', 'SC', 'Itajai', 'Centro', '2010-05-20', 'Rua da Sessao', '20', 0.00, 'app', FALSE,
     FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE),
    -- O ESTRANHO. Ele existe para que o teste possa pedir um id que NAO e do
    -- telefone autenticado -- que e exatamente o ataque que o D59 descreve, com
    -- ids inteiros em sequencia sobre 243 mil clientes.
    (90001152, 90001150, 'De Outra Linha', '+55 (47) 3900-0000', '+5547390000000',
     '333.333.333-33', 'XX-3.333.333', 'outro@teste.invalid',
     '88300-000', 'SC', 'Itajai', 'Centro', '1985-05-20', 'Rua Outra', '30', 0.00, 'app', FALSE,
     FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

-- Uma indicacao do titular, para que a lista autenticada nao seja vazia. Lista
-- vazia passaria pelo teste de permissao sem provar que a carga chega.
INSERT INTO indicacoes (id, unidade, cliente, convidado, url, data_convite, data_adesao, data_venda, comissao) VALUES
    (90001150, 90001150, 90001150, 90001151, 'https://exemplo/indicacao/sessao',
     '2026-02-01 00:00:00', '2026-02-02 00:00:00', '2026-02-03 00:00:00', 22.5);

-- ---------------------------------------------------------------------------
-- O que o telefone autenticado alcanca: agenda, cupom e sorteio
-- ---------------------------------------------------------------------------
-- As tres ultimas rotas que o D59 listava como alcancaveis pelo `id` foram
-- fechadas em 03/09/2026, e ganharam sucessor em `/api/v4/clientes/:id/...`.
-- Sem estas linhas as cargas autenticadas sairiam VAZIAS, e a suite recusaria
-- grava-las -- com razao: snapshot de colecao vazia passa sem proteger formato
-- nenhum.
--
-- TUDO NA UNIDADE 90001150, que e so deste cenario. Por na unidade da
-- caracterizacao mudaria os numeros que a suite financeira confere -- e o
-- proprio `fixtures.sql` ja registra esse cuidado para o cenario fiscal.
INSERT INTO usuarios (id, unidade, grupo, nome, email, login, sexo, senha,
     visivel_agenda, visivel_pdv, ordernacao_app, status, data_criacao) VALUES
    (90001150, 90001150, 90001000, 'Colaborador da Sessao', 'colab.sessao@teste.invalid',
     'colab.sessao', 'M', '$2y$10$abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQR',
     'sim', TRUE, 1, 1, '2026-01-01 00:00:00');

INSERT INTO produtos (id, unidade, tipo, nome, valor_compra, valor_venda,
     visivel_app, insumo, status, data_criacao) VALUES
    (90001150, 90001150, 'ser', 'Corte da Sessao', 0, 70.00, TRUE, FALSE, TRUE, '2026-01-01 00:00:00');

-- Data FIXA e distante: o snapshot congela o formato de `data`, e uma data
-- relativa faria o contrato mudar sozinho a cada dia. Precisa ser futura, que e
-- o que `selecionarProximoAgendamentosCliente` procura.
INSERT INTO agendas (id, colaborador, cliente, produto, hora, data, origem, checkin, checkout, status, data_criacao) VALUES
    (90001150, 90001150, 90001150, 90001150, '14:00', '2030-06-15 14:00:00', 'app', FALSE, FALSE, TRUE, '2026-01-01 00:00:00');

INSERT INTO cupons (id, unidade, regra, produto_regra, produto_oferecido, nome, desconto, validade, momento, data_limite, status, data_criacao) VALUES
    (90001150, 90001150, 'consumiu', 90001150, 90001150, 'Cupom da Sessao', 20, 30, 'checkout', '2026-01-31', TRUE, '2026-01-01 00:00:00');

INSERT INTO cupons_clientes (id, cupom, cliente, validade, usado, status, data_criacao) VALUES
    (90001150, 90001150, 90001150, '2030-12-31', FALSE, TRUE, '2026-01-01 00:00:00');

INSERT INTO caixas (id, usuario, valor_inicial, data_criacao, status) VALUES
    (90001150, 90001150, 0.00, '2026-01-01 08:00:00', FALSE);

-- A venda existe SO para ligar o cliente ao sorteio: `selecionarSorteiosPorCliente`
-- chega ao cliente por `sorteios_vendas -> venda -> cliente`. Ela nasce
-- cancelada (`status = 0`) e na unidade 90001150 para nao entrar em soma
-- nenhuma da caracterizacao financeira.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao, nps_respondido,
     msg_rel_sem_retorno, data_criacao) VALUES
    (90001150, 90001150, 90001150, 90001150, 0, FALSE, 0, 0, 0, '2026-01-01 00:00:00');

INSERT INTO sorteios (id, nome, data_inicio, data_fim, data_sorteio, status, data_criacao) VALUES
    (90001150, 'Sorteio da Sessao', '2026-01-01', '2030-12-31', '2026-06-01 12:00:00',
     'finalizado', '2026-01-01 00:00:00');

INSERT INTO sorteios_vendas (id, sorteio, venda, data, ganhador) VALUES
    (90001150, 90001150, 90001150, '2026-01-01 00:00:00', FALSE);

-- ---------------------------------------------------------------------------
-- O consumo do cliente autenticado: uma venda CONCLUIDA e um credito
-- ---------------------------------------------------------------------------
-- `GET /api/v4/clientes/:id/consumo` monta o historico a partir de vendas
-- CONCLUIDAS com item de SERVICO -- `historicoVendasPorCliente` descarta
-- `status = 0`, e a acao descarta venda sem item do tipo `ser`.
--
-- A venda 90001150 acima nasce cancelada de proposito (existe so para ligar o
-- cliente ao sorteio), entao sem estas linhas a carga sai VAZIA e a suite
-- recusa grava-la -- com razao: snapshot de colecao vazia nao protege formato
-- nenhum.
--
-- TUDO NA UNIDADE 90001150, que e so deste cenario. Uma venda concluida na
-- unidade da caracterizacao mudaria os numeros que a suite financeira confere.
--
-- OS TIPOS AQUI NAO SAO TODOS BOOLEANOS, e isso foi conferido no destino:
-- `vendas.status` e INTEIRO no PostgreSQL (1 = concluida), enquanto
-- `comanda_temp` e BOOLEANO. Escrever `TRUE` no status carregaria no MySQL e
-- falharia la -- o inverso do D81, pela mesma raiz.
INSERT INTO vendas
    (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao, nps_respondido,
     msg_rel_sem_retorno, valor_total, valor_recebido, data_criacao)
VALUES
    (90001160, 90001150, 90001150, 90001150, 1, FALSE, 0, 0, 0,
     70.00, 70.00, '2026-03-10 16:40:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto) VALUES
    (90001160, 90001150, 90001150, 1, 70.00, 70.00, 70.00, 10, 0);

INSERT INTO clientes_creditos (id, unidade, cliente, valor, valor_pf, pontuacao, pontuacao_validade, data_criacao) VALUES
    (90001150, 90001150, 90001150, 25.00, 0, 140, '2030-12-31', '2026-03-10 16:40:00');

-- ---------------------------------------------------------------------------
-- O DICIONARIO DE CEP, escrito como producao escreve: em MAIUSCULAS
-- ---------------------------------------------------------------------------
-- Sao 709.440 logradouros na copia de producao, e o nome vem do arquivo dos
-- Correios -- "AVENIDA PRESIDENTE VARGAS", nunca "Avenida Presidente Vargas".
-- Quem digita no autocompletar digita minusculo. Enquanto o banco era MySQL a
-- collation `utf8mb4_general_ci` fechava essa distancia sozinha; no PostgreSQL
-- o `LIKE` compara byte a byte, e "presidente" achava ZERO de 2.520 (D120).
--
-- As DUAS ruas existem por motivos diferentes: a primeira caracteriza a caixa,
-- que `LOWER()` conserta; a segunda carrega acento, que ele NAO conserta -- e
-- `BuscaDeLogradouroTest` congela essa diferenca em vez de escondê-la.
--
-- OS NOMES EVITAM "de Teste" DE PROPOSITO: `EnderecoPorCepTest` conta linhas
-- com `nome LIKE '%de Teste%'` e afirma que sao exatamente uma. Um nome destes
-- caindo naquele filtro reprovaria um teste que nao tem nada a ver com isto.
--
-- E ELES TERMINAM EM "DA CARACTERIZACAO" desde 05/10/2026 (o D173). Eram
-- "AVENIDA PRESIDENTE VARGAS" e "RUA SÃO JOÃO", nomes de rua de verdade, e o
-- autocompletar devolve as DEZ primeiras por estado, cidade, bairro e rua: com
-- o dicionario real carregado, a rua do cenario caia fora delas -- o estado
-- dela vem depois de oito outros, e so "presidente vargas" casa 237 ruas, 37
-- antes dele (medido no `franquiabv_dev` do PostgreSQL, 709.440 ruas). O
-- `BuscaDeLogradouroTest` passava porque o dicionario do cenario era curto.
-- "caracteriza" casa ZERO ruas reais, entao a busca por um termo que o tenha
-- devolve so o cenario, com qualquer dicionario.
INSERT INTO estados (id, uf, nome) VALUES
    (90001000, 'ZY', 'ESTADO CARACTERIZACAO');

INSERT INTO cidades (id, estado, nome) VALUES
    (90001000, 90001000, 'CIDADE CARACTERIZACAO');

INSERT INTO bairros (id, cidade, nome) VALUES
    (90001000, 90001000, 'BAIRRO CARACTERIZACAO');

INSERT INTO logradouros (id, bairro, tipo, nome, cep) VALUES
    (90001000, 90001000, 1, 'AVENIDA PRESIDENTE VARGAS DA CARACTERIZACAO', '90001000'),
    (90001001, 90001000, 1, 'RUA SÃO JOÃO DA CARACTERIZACAO', '90001001');

-- ---------------------------------------------------------------------------
-- A IMPRESSAO DIGITAL DESTE ARQUIVO fica gravada no banco de contrato.
--
-- `montar-banco-contrato.sh` guarda o sha1 deste arquivo numa tabela do proprio
-- banco, e `rodar-contrato.sh` recusa rodar quando os dois nao batem. O banco de
-- contrato do MySQL e montado UMA VEZ e reusado -- entao, sem essa marca, mexer
-- aqui deixava a suite verde sobre o cenario de ontem. Foi assim em 06/09/2026:
-- o PostgreSQL, que remonta o banco a cada execucao, acusou uma diferenca de
-- contrato que o MySQL nao via, e a divergencia era a idade de um dos dois.
--
-- Quem mexer neste arquivo vai ver o portao pedir `--montar`. E de proposito.
-- ---------------------------------------------------------------------------

-- ---------------------------------------------------------------------------
-- O QUE O GERENTE DE TESTE PODE FAZER -- e o colaborador continua sem poder
-- ---------------------------------------------------------------------------
-- Ate 07/09/2026 a tabela `privilegios` ficava VAZIA de proposito, e o
-- comentario la em cima dizia por que: "o usuario de teste entra sem poder
-- nenhum -- que e o suficiente para as rotas que so exigem SESSAO".
--
-- Aquilo era verdade e escondia um defeito. `scripts/ensaiar-fluxo-adm-api.php`
-- roda como `gerente.teste` e faz os dezesseis passos -- cadastra cliente,
-- marca horario, abre comanda, tira dinheiro do caixa --, e passava. Nao porque
-- a API desse poder ao usuario, mas porque ela NAO CONFERIA: `getAcesso()` sem
-- `$this->funcionalidade` devolvia o modulo inteiro, que e sempre verdadeiro
-- (D123). O ensaio media o caminho feliz e nao tinha como notar.
--
-- Agora que a conferencia existe, o gerente precisa dos privilegios de verdade.
-- SAO SO OS QUE O ENSAIO USA: dar tudo a ele apagaria a diferenca entre "tem
-- permissao" e "a API nao confere", que e justamente o que se quer distinguir.
--
-- E O COLABORADOR (grupo 90001000) CONTINUA SEM NENHUM, de proposito: e ele que
-- `scripts/ensaiar-permissao-adm-api.php` usa para provar que a recusa acontece.
-- Se um dia alguem lhe der privilegio aqui, aquele ensaio para de medir o que
-- diz medir -- e vai dizer isso, porque a recusa deixa de vir.
-- A TABELA E `privilegios_usuarios`, e NAO `privilegios` -- as duas existem, e
-- so uma responde. Escrevi primeiro na outra e o ensaio de fluxo parou no
-- primeiro passo com 403: `SessaoAcl` monta a ACL a partir de
-- `PrivilegioUsuario::selecionarPorUsuario()`, por USUARIO. A tabela por GRUPO
-- alimenta a tela de permissoes, e nao a sessao.
--
-- As duas linhas do gerente sao por usuario, entao: 90001001.
-- POR NOME, E NAO POR ID -- desde 15/09/2026, pelo mesmo motivo do bloco de
-- `funcionalidades` la em cima. Agora aquelas linhas CEDEM a producao, entao o
-- id 90002013 so existe em banco montado do zero. Numa copia que tem o catalogo
-- de producao, `Clientes cadastro` tem o id de producao -- e um INSERT com o id
-- fixo violaria a chave estrangeira e abortaria a carga inteira.
--
-- SAO ONZE LINHAS NOS DOIS CASOS (eram dez ate 07/11/2026), porque os onze nomes
-- existem uma vez so em cada banco. `PrivilegioApiTest::testOCenarioTemDezPrivilegiosETodosSemMolde`
-- conta exatamente onze, e e ele que fica vermelho se este numero mudar.
--
-- `Agendas gerenciar` entrou em 13/09/2026 com o ensaio do D111. A tela que
-- FECHA a agenda e guardada por `podeGerenciarAgenda()`, e sem esta linha o
-- ensaio media a guarda em vez de medir o fechamento: TODOS os casos batiam num
-- 404 do `notFoundAction`, e o roteiro dizia que nada fora gravado -- verdade, e
-- pelo motivo errado.
--
-- `Vendas nova` NO LUGAR DE `Vendas caixa` desde 26/09/2026 (D227): a API do
-- caixa passou a pedir o bit que o caixa do ERP pede. Trocada, e nao somada --
-- continuam oito linhas. E com ela o gerente passa a ver "Abrir/Fechar Caixa"
-- no menu da tela nova, que pede o mesmo bit.
--
-- `Vendas realizadas` entrou em 26/09/2026, com a tela nova de vendas
-- realizadas: o ensaio do fluxo passou a conferir que a venda finalizada aparece
-- na listagem, e o de recusas, as recusas e o "com" e o "sem desconto" dela (D229). A nona
-- linha.
--
-- `Clientes devedores` entrou no mesmo dia, com a tela de devedores: o ensaio de
-- recusas quita o fiado da casa (o controle 9p) e cobra as recusas da quitacao,
-- e o medidor do PostgreSQL lista e le o debito (D232). A decima.
--
-- `Clientes crédito` entrou em 07/11/2026, a decima primeira (a fatia 104; a
-- resposta 99 (a) do dono, o D123): comprar e devolver credito passaram a pedi-la
-- alem do cadastro, e o ensaio do fluxo (o passo 13) e o da fidelidade compram
-- credito como o gerente. Sem ela, os dois mediriam a guarda nova em vez da compra.
INSERT INTO privilegios_usuarios (usuario, funcionalidade, ler, escrever)
SELECT 90001001, f.id, TRUE, TRUE
  FROM funcionalidades f
 WHERE f.nome IN ('Clientes cadastro',
                  'Clientes crédito',
                  'Agendas visualizar',
                  'Agendas gerenciar',
                  'Vendas nova',
                  'Comandas listar',
                  'Comandas nova',
                  'Comandas fechar',
                  'Vendas cancelar',
                  'Vendas realizadas',
                  'Clientes devedores');

-- ---------------------------------------------------------------------------
-- O CENARIO DA QUINTA FATIA: credito, pontuacao e um pacote em uso
-- ---------------------------------------------------------------------------
-- Ver docs/f2-fatia-fidelidade.md.
--
-- ELE TEM CLIENTE PROPRIO, e a primeira versao nao tinha -- custou onze testes
-- vermelhos, e nenhum deles por colisao de id.
--
-- Pendurar credito e pacote no cliente 90001000 MUDA O QUE ACONTECE COM ELE:
--
--   * `VendaProdutoService::insert()` debita a sessao do pacote em vez de
--     aplicar o desconto do convenio -- pacote tem precedencia. Tres testes de
--     `ConvenioDescontoTest` passaram a ver 89,90 onde esperavam 71,92.
--   * `FidelidadePontuacaoTest` conta pontos a partir do zero, e uma linha de
--     credito parada com 400 pontos nao e zero.
--   * `PagamentoTrocoDebitoTest` soma o troco ao saldo, e o saldo tinha 100,00
--     antes de comecar.
--
-- Cenario de fatia nova nao pode mudar o cenario das anteriores. Este cliente e
-- so desta fatia, e por isso ninguem mais tropeca nele.
INSERT INTO clientes (id, unidade, nome, programa_fidelidade, cadastro_restricao_agendamento,
     fidelizado_colaborador, fidelizado_unidade, pesquisa_satisfacao_whatsapp,
     status, data_criacao, bloqueio_agendamento_app) VALUES
    (90001004, 90001000, 'Cliente Fidelidade Teste', TRUE, FALSE, FALSE, FALSE, FALSE, TRUE,
     '2026-01-01 00:00:00', FALSE);

-- A PONTUACAO E 400 DE PROPOSITO. O piso de resgate vem de
-- `CrudController::autorizarTrocarPontuacao()`, que devolve 300 no Brasil e 150
-- fora -- e a unidade 90001000 e brasileira. Um numero abaixo de 300 faria toda
-- tentativa de resgate parar no 409, e os testes do caminho feliz nunca sairiam
-- do lugar; exatamente 300 esconderia um `>` escrito no lugar de `>=`.
--
-- 400 pontos valem 20,00: o servico divide por 20 na hora do resgate.
INSERT INTO clientes_creditos (id, unidade, cliente, valor, valor_pf, pontuacao,
     pontuacao_validade, data_criacao) VALUES
    (90001000, 90001000, 90001004, 100.00, 0, 400, '2030-12-31', '2026-01-01 00:00:00');

-- O PACOTE PRECISA DE UM PRODUTO DO TIPO `pac`, e o cenario nao tinha nenhum:
-- `pacotes_itens` liga DOIS produtos -- o combo vendido e o servico que ele
-- debita --, e a tela mostra os dois nomes lado a lado.
INSERT INTO produtos (id, unidade, tipo, nome, valor_compra, valor_venda,
     visivel_app, insumo, status, data_criacao) VALUES
    (90001004, 90001000, 'pac', 'Pacote Teste', 0, 400.00, TRUE, FALSE, TRUE, '2026-01-01 00:00:00');

INSERT INTO pacotes_itens (id, pacote, item, quantidade, valor_sessao, status, data_criacao) VALUES
    (90001000, 90001004, 90001000, 5, 80.00, TRUE, '2026-01-01 00:00:00');

-- `clientes_pacotes.venda` e NOT NULL: o pacote nasce de uma venda, e a 90001010
-- e a que ja existe na unidade 90001000.
--
-- QUANTIDADE RESTANTE MENOR QUE A CONTRATADA, de proposito: 3 de 5. Um pacote
-- intacto nao distingue "quantas sobraram" de "quantas foram compradas", e os
-- dois campos sairiam iguais no JSON sem ninguem notar se um deles estivesse
-- lendo o outro.
INSERT INTO clientes_pacotes (id, unidade, venda, cliente, item, quantidade_contratada,
     valor_sessao, quantidade_restante, validade, status, data_criacao) VALUES
    (90001000, 90001000, 90001010, 90001004, 90001000, 5, 80.00, 3, '2030-12-31', TRUE,
     '2026-01-01 00:00:00');


-- ===========================================================================
-- A UNIDADE DA DECIMA FATIA -- 90001200
-- ===========================================================================
--
-- UNIDADE PROPRIA, e nao a 90001000: aquela e o cenario de nove fatias
-- anteriores, e mexer nos valores dela para caber um teste novo quebraria os
-- outros. A licao veio da quinta fatia, onde acrescentar fidelidade ao cliente
-- 90001000 deixou onze testes vermelhos -- nao por colisao de id, mas por
-- regra de negocio.
--
-- Cada valor abaixo responde a uma pergunta que o recurso precisa saber
-- responder:
--
--   `potencial_franquia` NULO e `reducao_potencial` ZERO, lado a lado. E a
--   distincao que `Monetario::applyMask()` apaga: ela devolve "0,00" para os
--   dois. Sem os dois campos no mesmo cenario, um recurso que confundisse "nao
--   apurado" com "zero" passaria verde.
--
--   `royltes_servico` = 3.5, e nao um inteiro. O numero com casa decimal e o
--   que separa ler o campo cru de desmascarar depois: "3,50" passando por
--   `removeMask()` volta 3.50, mas "1.234,50" volta 123450. Nesta unidade o
--   valor pequeno ja prova a leitura crua; o perigo do separador de milhar fica
--   registrado no `UnidadeJson`.
--
--   `royltes_lavavip` = 0. Zero e valor legitimo -- 6 das 63 unidades da base
--   tem royalty zero em alguma linha -- e precisa sair "0.00", nao nulo.
--
--   DOMINGO SEM HORARIO. Nulo quer dizer FECHADO, e e o caso comum. Um recurso
--   que devolvesse "00:00" diria que a loja abre a meia-noite.
--
--   `estado` = 'SC' preenchido, para o recurso ter o que chamar de `uf`.
--
--   `whatsapp_api_key` e `whatsapp_instancia` COM VALOR. Sao os campos que o
--   recurso NAO pode devolver, e um cenario onde eles fossem nulos deixaria o
--   teste passar por ausencia de dado -- que nao e verde.
--
--   `faturamento_socio_adm_cpf` idem: dado pessoal presente no banco, ausente
--   na resposta.
--
--   `convenio_domingo` FALSE contra os outros seis TRUE: sao sete colunas
--   independentes, e um recurso que devolvesse a mesma para todas passaria se
--   todas fossem iguais.
INSERT INTO unidades (id, tipo, pais, estado, cidade, bairro, endereco, numero, nome,
     ddi, telefone, email, latitude, longitude,
     segunda_sexta_abertura, segunda_sexta_fechamento, sabado_abertura, sabado_fechamento,
     convenio_segunda, convenio_terca, convenio_quarta, convenio_quinta, convenio_sexta,
     convenio_sabado, convenio_domingo,
     royltes_produto_barbearia, royltes_produto_emporio, royltes_servico, royltes_lavavip,
     observacao, potencial_franquia, visivel_app, nps, reducao_potencial,
     link_boas_vindas, clientes_atualizar, indicacao_comissao, data_inauguracao,
     agenda_primeiro_nome, fidelizacao_unidade_dias, fidelizacao_unidade_visitas,
     pontuacao_validade_dias, cashback,
     faturamento_nome, faturamento_documento, faturamento_email, faturamento_telefone,
     faturamento_cep, faturamento_logradouro, faturamento_numero, faturamento_complemento,
     faturamento_bairro, faturamento_socio_adm_nome, faturamento_socio_adm_cpf,
     asaas_id,
     whatsapp_ativo, whatsapp_api_key, whatsapp_instancia, whatsapp_provedor,
     hash, status, data_criacao) VALUES
    (90001200, 'FRANQUEADA', 'Brasil', 'SC', 'Blumenau', 'Velha', 'Rua da Decima', '200',
     'Unidade Decima Fatia',
     55, '(47) 3300-0000', 'decima@teste.invalid', '-26.9194', '-49.0661',
     '09:00:00', '20:00:00', '09:00:00', '18:00:00',
     TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE,
     6, 6, 3.5, 0,
     'Unidade da decima fatia.', NULL, TRUE, 8.5, 0,
     NULL, NULL, NULL, '2019-03-15',
     FALSE, 90, 2,
     365, 1,
     'Decima Fatia Servicos LTDA', '11.222.333/0001-44', 'faturamento@teste.invalid',
     '(47) 3300-0001', '89040-000', 'Rua do Faturamento', '10', 'Sala 2',
     'Centro', 'Socio Administrador Teste', '000.000.000-00',
     'asaas-de-fixture',
     TRUE, 'chave-de-fixture-90001200', 'instancia-de-fixture-90001200', 'evolution',
     'hash-teste-90001200', TRUE, '2026-01-01 00:00:00');

-- DOIS SOCIOS, e um deles REMOVIDO.
--
-- `socioRemover` desativa em vez de apagar, entao a listagem filtra por
-- `status`. Com um socio so, ativo, um recurso que ignorasse o filtro passaria.
--
-- O CPF e o endereco estao preenchidos nos dois. `selecionarSocios()` nao os
-- seleciona -- e e por isso que o recurso nao os devolve. Cenario onde as
-- colunas fossem nulas provaria a mesma coisa que nao provar nada.
INSERT INTO unidades_socios (id, unidade, nome, cpf, profissao, telefone, telefone_sem_mascara,
     email, pais, cep, estado, cidade, bairro, logradouro, numero, data_nascimento,
     status, data_criacao) VALUES
    (90001200, 90001200, 'Socia Ativa Teste', '111.111.111-11', 'Empresaria',
     '+55 (47) 99900-0001', '+5547999000001', 'socia.ativa@teste.invalid',
     'Brasil', '89040-100', 'SC', 'Blumenau', 'Velha', 'Rua da Socia', '1',
     '1980-05-10 00:00:00', TRUE, '2026-01-01 00:00:00'),
    (90001201, 90001200, 'Socio Removido Teste', '222.222.222-22', 'Empresario',
     '+55 (47) 99900-0002', '+5547999000002', 'socio.removido@teste.invalid',
     'Brasil', '89040-200', 'SC', 'Blumenau', 'Velha', 'Rua do Socio', '2',
     '1975-11-20 00:00:00', FALSE, '2026-01-01 00:00:00');


-- ===========================================================================
-- O CENARIO DA DECIMA PRIMEIRA FATIA -- as vendas realizadas
-- ===========================================================================
--
-- CLIENTE PROPRIO (90001210) e vendas proprias, na unidade 90001000. Ela e a
-- unidade que a sessao do medidor enxerga, entao a listagem precisa achar algo
-- aqui -- e um cliente novo mantem intactos os cenarios de credito, pacote e
-- fidelidade que as fatias anteriores penduraram nos clientes existentes.
--
-- A DATA E 14/02/2026, fora de qualquer janela que outro teste afirme.
--
-- Cada detalhe responde a uma pergunta do recurso:
--
--   DOIS COLABORADORES DIFERENTES na mesma venda (90001000 e 90001003).
--   `LISTAR_DISTINTOS(col.nome)` so e exercitado quando ha mais de um -- e 6,1%
--   das vendas de 2025 sao assim, ate sete numa venda. Com um colaborador so, o
--   recurso poderia devolver texto em vez de lista e ninguem veria.
--
--   DOIS PAGAMENTOS, pelo mesmo motivo, do outro lado: DIN e CRE.
--
--   TROCO DE VERDADE. `valor_recebido` (250) maior que `valor_total` (200): o
--   troco e 50. Com recebido igual ao total, `getValorTroco()` devolveria 0 e o
--   campo passaria por qualquer coisa.
--
--   NPS RESPONDIDO COM NOTA, na venda concluida, e NAO RESPONDIDO E SEM NOTA na
--   cancelada. `vendas.nps` e anulavel, e "nao apurado" nao e "nota zero" -- a
--   mesma distincao que o `potencial_franquia` obrigou a fazer na decima fatia.
--
--   CONVENIO PREENCHIDO, para o recurso ter o que devolver em `convenio`.
--
--   TRES TIPOS NUMA TABELA SO, e isto custou uma rodada vermelha. Em
--   `vendas`, `comanda_temp` e BOOLEAN, `nps_notificacao`, `nps_respondido` e
--   `msg_rel_sem_retorno` sao SMALLINT, e `venda_credito` e INTEGER -- todas as
--   cinco com cara de sinalizador. Escrevi `TRUE` em `nps_respondido`: o MySQL
--   converteu e passou verde, o PostgreSQL recusou com *"column
--   nps_respondido is of type smallint but expression is of type boolean"*.
--   E o D128 inteiro numa linha, e as fixtures antigas ja escreviam `0` aqui.
INSERT INTO clientes (id, unidade, nome, telefone, telefone_sem_mascara, cpf, rg, email,
     cep, estado, cidade, bairro, data_nascimento, logradouro, numero, consumo, origem,
     programa_fidelidade, cadastro_restricao_agendamento, fidelizado_colaborador,
     fidelizado_unidade, pesquisa_satisfacao_whatsapp, status, data_criacao,
     bloqueio_agendamento_app) VALUES
    (90001210, 90001000, 'Cliente da Decima Primeira', '+55 (48) 3400-0000', '+5548340000000',
     '000.000.210-00', '0000210', 'cliente.11@teste.invalid',
     '88010-000', 'SC', 'Florianopolis', 'Centro', '1990-02-14 00:00:00',
     'Rua da Decima Primeira', '11', 0, NULL,
     FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, '2026-01-01 00:00:00', FALSE);

INSERT INTO vendas (id, caixa, cliente, usuario, convenio, status, comanda_temp,
     nps_notificacao, nps_respondido, msg_rel_sem_retorno, nps,
     valor_total, valor_recebido, valor_troco, desconto_total,
     cancelado_motivo, venda_credito, data_criacao) VALUES
    (90001210, 90001000, 90001210, 90001000, 90001000, 1, FALSE,
     0, 1, 0, 9.5,
     200.00, 250.00, 50.00, 20.00,
     NULL, 0, '2026-02-14 14:00:00'),
    (90001211, 90001000, 90001210, 90001000, NULL, 0, FALSE,
     0, 0, 0, NULL,
     80.00, 80.00, 0, 0,
     'Cliente desistiu', 0, '2026-02-14 15:30:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario,
     valor_total, valor_total_relatorio, comissao, valor_desconto) VALUES
    (90001210, 90001000, 90001000, 1, 110.00, 110.00, 110.00, 10, 20.00),
    (90001210, 90001003, 90001001, 1,  90.00,  90.00,  90.00, 10,     0),
    (90001211, 90001000, 90001000, 1,  80.00,  80.00,  80.00, 10,     0);

INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001210, 90001000, 150.00),
    (90001210, 90001001,  50.00),
    (90001211, 90001000,  80.00);


-- ===========================================================================
-- O CENARIO DO FINANCEIRO -- saidas, parcelas e pagamentos
-- ===========================================================================
--
-- ANTES DE 08/09/2026 NAO HAVIA NENHUM. A tela de saidas -- por onde o dinheiro
-- SAI -- era a unica area do sistema sem uma linha de fixture, e portanto sem
-- teste nenhum. Quatro defeitos apareceram na primeira leitura dela.
--
-- DUAS UNIDADES DE PROPOSITO. A 90001100 existe aqui para uma pergunta so:
-- `SaidaService::excluirParcelas()` recebia ids crus do POST e nao conferia
-- unidade nenhuma (D132). Sem uma parcela de OUTRA unidade no cenario, o teste
-- que prova a recusa nao teria o que provar.
--
-- UMA PARCELA QUITADA E UMA EM ABERTO na mesma saida, porque as duas guardas
-- que faltavam dependem dessa diferenca: a de excluir saida com parcela paga
-- (D133) e a soma que a tela mostra.
INSERT INTO saidas_tipos (id, nome, status) VALUES
    (90001000, 'Custo Fixo (teste)', TRUE);

INSERT INTO saidas (id, unidade, tipo, descricao, status, data_criacao) VALUES
    (90001000, 90001000, 90001000, 'Aluguel de teste', TRUE, '2026-01-01 00:00:00'),
    (90001100, 90001100, 90001000, 'Aluguel da outra unidade', TRUE, '2026-01-01 00:00:00');

INSERT INTO saidas_parcelas (id, saida, valor_previsto, valor_pago, data_vencimento,
     quitada, status, data_criacao) VALUES
    (90001000, 90001000, 1500.00, 1500.00, '2026-02-10', TRUE,  TRUE, '2026-01-01 00:00:00'),
    (90001001, 90001000, 1500.00, NULL,    '2026-03-10', FALSE, TRUE, '2026-01-01 00:00:00'),
    (90001100, 90001100,  900.00, NULL,    '2026-02-10', FALSE, TRUE, '2026-01-01 00:00:00'),
-- A QUARTA PARCELA E DESATIVADA E DE OUTRO ANO, e as duas coisas juntas nao sao
-- acaso: ela destrava DOIS filtros de `SaidaParcelaRepository::popularComboboxAnos()`
-- que o cenario nao conseguia distinguir.
--
-- Aquele metodo monta a lista de anos do filtro da tela de saidas com
-- `WHERE par.status = :status` (ligado a TRUE) e sem `GROUP BY` -- ele devolve uma
-- linha POR PARCELA e deduplica em PHP, no `$retorno[$ano] = $ano`.
--
--   sem esta linha   parcelas 90001000 e 90001001, ambas ativas, ambas de 2026:
--                    a lista tem UM ano com o filtro e UM sem ele. O `status` nao
--                    se distingue, e a ordenacao tampouco.
--   com esta linha   com o filtro -> {2026}.  Sem ele -> {2025, 2026}.
--
-- `status = FALSE` em vez de 0: a coluna e `tinyint(1)` no MySQL e `boolean` no
-- PostgreSQL, e o cabecalho deste arquivo pede TRUE/FALSE justamente por isso.
    (90001002, 90001000, 700.00,  NULL,    '2025-11-20', FALSE, FALSE, '2025-11-01 00:00:00');

INSERT INTO saidas_parcelas_pagamentos (id, parcela, valor, data, observacoes, status,
     data_criacao) VALUES
    (90001000, 90001000, 1500.00, '2026-02-10', 'Pago no vencimento', TRUE,
     '2026-02-10 00:00:00');


-- ===========================================================================
-- O CENARIO DOS DEVEDORES -- decima terceira fatia
-- ===========================================================================
--
-- DOIS DEBITOS EM UNIDADES DIFERENTES, e e a unica forma de provar o D137:
-- `pagarDebito()` credita o caixa de QUEM CHAMA. Sem um debito da outra
-- franquia no cenario, o teste que exige a recusa nao teria o que exigir.
--
-- O debito da casa pendura na venda 90001010, que ja existe na unidade
-- 90001000; o de fora, na 90001100, da unidade 90001100 -- e as duas ja tem
-- caixa aberto nas fixtures (90001000 e 90001100), que e o que `pagarDebito`
-- procura.
--
-- `clientes_debitos` TEM COLUNA `unidade` PROPRIA, e a listagem nao a usa:
-- ela chega a unidade pela venda (`deb.venda -> ven.usuario -> usu.unidade`).
-- Conferido na copia de producao: 9.096 debitos, ZERO divergencias entre as
-- duas. As fixtures escrevem as duas concordando, como a producao faz.
INSERT INTO clientes_debitos (id, unidade, cliente, venda, valor, status, data_criacao) VALUES
    (90001000, 90001000, 90001000, 90001010,  50.00, TRUE, '2026-01-05 10:00:00'),
    (90001100, 90001100, 90001100, 90001100, 120.00, TRUE, '2026-03-10 10:20:00');

-- ===========================================================================
-- O CENARIO DO PDV -- uma comanda ABERTA com carrinho
-- ===========================================================================
--
-- ATE 09/09/2026 NAO HAVIA NENHUMA. A unica comanda aberta do cenario estava
-- vazia, e o `ComandaApiTest` montava a SUA PROPRIA em tempo de execucao,
-- dentro da transacao que faz rollback -- entao ela nunca chegava ao banco.
--
-- Isso bastava para a suite, que afirma FORMA de resposta. Nao basta para uma
-- tela: a primeira tela da Fase 3 lista comandas, abre uma, e desenha as
-- tabelas de itens e pagamentos. Com carrinho vazio, as duas tabelas que mais
-- importam nunca apareciam -- e "a tela nao mostra nada" tanto pode ser cenario
-- pobre quanto defeito de codigo.
--
-- E o que uma tela precisa nao e "um item": e o bastante para que cada caminho
-- do desenho seja exercitado.
--
--     dois itens          a tabela com mais de uma linha, e a soma
--     um com desconto     a coluna de desconto, e o motivo ao lado
--     um pagamento        a tabela de pagamentos, com a forma
--     pagamento PARCIAL   o fiado, que e DERIVADO de recebido < total
--     sem autorizacao     o ramo "sem autorizacao registrada"
--
-- O ID E 90001500, E NAO 90001400. Aquele e o da comanda que o
-- `ComandaApiTest` insere em tempo de execucao; usar o mesmo daria chave
-- duplicada e derrubaria o teste. O 90001401 esta reservado pelo mesmo motivo.
--
-- `status = 3` e comanda aberta (D51). `comanda_temp` vai como literal FALSE, e
-- nao como parametro: no MySQL a coluna e inteira e no PostgreSQL e booleana --
-- o mesmo cuidado que o `comandaAberta()` do teste registra.
--
-- AS CONTAS FECHAM, e isso importa numa fixture: 89.90 + 40.00 = 129.90, com
-- 5.00 de desconto no segundo item e 100.00 recebidos. O fiado de 29.90 nao e
-- coluna nenhuma -- e o que `ehFiado()` deriva.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao,
     nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, desconto_total,
     data_criacao) VALUES
    (90001500, 90001000, 90001001, 90001000, 3, FALSE, 0, 0, 0,
     129.90, 100.00, 5.00, '2026-09-08 14:20:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto, desconto_motivo) VALUES
    (90001500, 90001000, 90001000, 1, 89.90, 89.90, 89.90, 10, 0, NULL),
    (90001500, 90001000, 90001005, 1, 45.00, 40.00, 40.00, 10, 5.00, 'Cortesia de teste');

-- Pagamento PARCIAL, de proposito: 100.00 de 129.90.
INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001500, 90001000, 100.00);

-- ---------------------------------------------------------------------------
-- AS DUAS INDICACOES INCOMPLETAS, e por que elas ficam AQUI e nao la em cima
--
-- Acrescentadas em 12/09/2026. `IndicacaoRepository::totaisRelatorio()` devolve
-- cinco numeros para o cabecalho do relatorio, e tres deles sao contadores
-- condicionais:
--
--   pendentes_adesao   SUM(CASE WHEN ind.dataAdesao IS NULL          THEN 1 ELSE 0 END)
--   pendentes_venda    SUM(CASE WHEN ind.dataAdesao IS NOT NULL
--                                AND ind.dataVenda  IS NULL          THEN 1 ELSE 0 END)
--   com_venda          SUM(CASE WHEN ind.dataVenda  IS NOT NULL      THEN 1 ELSE 0 END)
--
-- Ate aqui TODAS as indicacoes do cenario tinham adesao E venda, entao os dois
-- primeiros davam ZERO sempre: um teste sobre eles seria verdadeiro por ausencia
-- de dado, e continuaria verde com as duas expressoes trocadas entre si.
--
-- FICAM NO FIM DO ARQUIVO porque `indicacoes.convidado` referencia `clientes`, e
-- os clientes 90001004 e 90001010 sao criados MAIS ABAIXO que o bloco de
-- indicacoes original. Escritas la, a carga morre em *Cannot add or update a
-- child row* e o cenario fica pela metade -- medido, e nao suposto.
--
-- A comissao das duas e ZERO de proposito: quem nao vendeu nao gerou comissao, e
-- isso mantem a soma de comissao presa as indicacoes que de fato renderam.
INSERT INTO indicacoes (id, unidade, cliente, convidado, url, data_convite, data_adesao, data_venda, comissao) VALUES
    -- O INDICADOR E O 90001020, e NAO o 90001000 -- por causa do contrato.
    --
    -- `AplicativoApiTest::testIndicacoesListarAutenticado` congela o formato de
    -- `/api/cliente/indicacoes/90001000`, e o contrato grava o tipo de cada campo
    -- a partir do PRIMEIRO item da lista. Penduradas no cliente 90001000, estas
    -- duas entram naquela lista e viram o primeiro item -- e `data_venda` passa de
    -- `"string"` para `"null"` no instantaneo congelado.
    --
    -- ISSO REVELOU QUE O CONTRATO ESTA ERRADO, e o achado ficou registrado em vez
    -- de ser corrigido por efeito colateral: medido em 12/09/2026, as SEIS
    -- indicacoes da copia de producao tem `data_venda` NULA -- todas. O contrato
    -- diz `"string"` porque o cenario so tinha a indicacao completa, que e
    -- artificial. Virar um contrato congelado e decisao de quem opera, e nao
    -- consequencia de um teste de relatorio.
    (90001001, 90001000, 90001020, 90001004, 'https://exemplo/indicacao/sem-adesao',
     '2026-01-05 00:00:00', NULL, NULL, 0),
    -- Aderiu mas ainda nao comprou: conta em `pendentes_venda`.
    (90001002, 90001000, 90001020, 90001010, 'https://exemplo/indicacao/sem-venda',
     '2026-01-06 00:00:00', '2026-01-07 00:00:00', NULL, 0);

-- ---------------------------------------------------------------------------
-- AS GORJETAS, e por que sao TRES e nao uma
--
-- Acrescentadas em 12/09/2026. Ate entao a tabela `gorjetas` tinha ZERO linhas
-- na faixa do cenario -- o banco inteiro tem 11.938, todas da copia anonimizada
-- --, e por isso `GorjetaRepository::selecionarGorjetasPorColaboradorPeriodo()`
-- era o ultimo dos onze metodos de dinheiro do D10 sem teste: qualquer afirmacao
-- sobre ele seria verdadeira por ausencia de dado.
--
-- O metodo faz `COUNT(gor.id)` e `SUM(gor.valor)` filtrando por colaborador, por
-- faixa de `DATE(gor.data)` e por `ven.status != 0`. Cada uma das tres linhas
-- existe para que um desses filtros possa ser DISTINGUIDO:
--
--   90001000  venda 90001010 (status 1)  12,50  em 10/03  -- conta
--   90001001  venda 90001210 (status 1)   7,30  em 14/02  -- conta, e em OUTRO mes
--   90001002  venda 90001000 (status 0)  99,00  em 01/01  -- FORA, pelo status
--
-- Com o filtro:  2 gorjetas,  19,80.  Sem ele:  3 gorjetas, 118,80.
--
-- OS VALORES SAO DIFERENTES ENTRE SI de proposito: com duas gorjetas iguais,
-- `SUM` nao se distingue de `COUNT * valor`. E a excluida vale 99,00 -- quase
-- cinco vezes a soma das outras duas -- para que incluir-la por engano nao passe
-- por arredondamento.
--
-- AS DATAS SAO FIXAS, e em meses diferentes, porque a faixa e um dos filtros: uma
-- faixa so de marco tem de achar uma, e nao duas.
INSERT INTO gorjetas (id, venda, colaborador, valor, data) VALUES
    (90001000, 90001010, 90001000,  12.50, '2026-03-10 15:00:00'),
    (90001001, 90001210, 90001000,   7.30, '2026-02-14 16:00:00'),
    (90001002, 90001000, 90001000,  99.00, '2026-01-01 10:00:00');

-- ---------------------------------------------------------------------------
-- A VENDA COM DOIS ITENS DESCONTADOS -- o D10, 05/10/2026
-- ---------------------------------------------------------------------------
-- A listagem do relatorio de descontos e enraizada no ITEM desde 26/08/2026:
-- uma linha por item descontado, e nao uma por venda com um motivo so,
-- escolhido pelo banco (`VendaRepository::listagemIndexRelatorioDescontos`).
-- Ate aqui nenhuma venda do cenario tinha MAIS DE UM item descontado, e com um
-- item por venda as duas raizes devolvem a mesma contagem. O
-- `DescontosNoRelatorioTest` dizia isso no cabecalho; a raiz de volta so ficava
-- vermelha no caso que caracteriza um DEFEITO (a linha repetida por pagamento),
-- e esse caso muda no dia em que o defeito for consertado.
--
-- Esta tem dois, com motivos diferentes: a listagem traz quatro itens de tres
-- vendas, e enraizada na venda traria tres linhas.
--
-- O QUE ELA EVITA, de proposito, para nao mexer no que outros casos medem:
--   * o dia 14/02 -- o `ReceitaParaYungasTest` crava os R$ 200,00 do dia;
--   * o produto 90001000 com o colaborador 90001000 -- a media ponderada de
--     99,95 do `VendasPorColaboradorNoRelatorioTest`;
--   * um segundo pagamento -- o par da 90001210 continua o unico que repete
--     linha na listagem.
--
-- AS CONTAS FECHAM: 40,00 + 12,00 = 52,00, com 5,00 + 3,00 = 8,00 de desconto
-- nos itens e na venda, e 52,00 recebidos em dinheiro.
INSERT INTO vendas (id, caixa, cliente, usuario, status, comanda_temp, nps_notificacao,
     nps_respondido, msg_rel_sem_retorno, valor_total, valor_recebido, desconto_total, data_criacao) VALUES
    (90001610, 90001000, 90001210, 90001000, 1, FALSE, 0, 0, 0, 52.00, 52.00, 8.00, '2026-03-20 11:00:00');

INSERT INTO vendas_produtos (venda, colaborador, produto, quantidade, valor_unitario, valor_total,
     valor_total_relatorio, comissao, valor_desconto, desconto_motivo) VALUES
    (90001610, 90001000, 90001005, 1, 45.00, 40.00, 40.00, 10, 5.00, 'Primeiro desconto da venda de dois'),
    (90001610, 90001000, 90001002, 1, 15.00, 12.00, 12.00, 10, 3.00, 'Segundo desconto da venda de dois');

INSERT INTO vendas_pagamentos (venda, forma_pagamento, valor) VALUES
    (90001610, 90001000, 52.00);

-- ---------------------------------------------------------------------------
-- UMA UNIDADE COM O WHATSAPP LIGADO E SEM CHAVE (12/10/2026, o D360; a F0 do
-- desenho do WhatsApp, `docs/f3-telas-restantes/tela-whatsapp.md`).
--
-- As duas unidades de fixture com o WhatsApp ligado (90001150 e 90001200) tem uma
-- chave de mentira, e a tela antiga do WhatsApp, aberta numa sessao delas, falava
-- com o provedor de verdade. Esta e o caso "sem credencial": o `whatsapp_ativo`
-- ligado e a chave e a instancia NULAS -- que e como a copia anonimizada deixa as
-- unidades reais. Nenhum caminho fala com o provedor nela: a tela antiga diz que a
-- chave nao esta cadastrada (`WhatsAppTelaAntigaTest`). Ensaio e conferencia no
-- navegador do WhatsApp, so nesta unidade.
--
-- `visivel_app` FALSE pelo mesmo motivo da 90001150: o snapshot de
-- `/api/agendas/getUnidades` nao a ve. Sem usuario: quem a usa no navegador e o
-- administrador, que troca de unidade.
INSERT INTO unidades (id, tipo, pais, estado, cidade, bairro, endereco, numero,
     royltes_produto_barbearia, royltes_produto_emporio, royltes_servico, royltes_lavavip,
     visivel_app, reducao_potencial, agenda_primeiro_nome,
     fidelizacao_unidade_dias, fidelizacao_unidade_visitas, cashback,
     whatsapp_ativo, whatsapp_instancia, whatsapp_api_key, whatsapp_provedor,
     hash, nome, status, data_criacao) VALUES
    (90001170, 'PROPRIA', 'Brasil', 'SC', 'Itajai', 'Centro', 'Rua do WhatsApp', '30',
     5, 5, 10, 5, FALSE, 0, TRUE, 90, 3, 0,
     TRUE, NULL, NULL, 'evolution',
     'hash-teste-90001170', 'Unidade WhatsApp Sem Chave', TRUE, '2026-01-01 00:00:00');

-- >>> MARCA-DAS-FIXTURES -- gerada por scripts/marcar-fixtures.php >>>
--
-- NAO EDITE ESTAS TRES LINHAS A MAO. Elas dizem o sha1 de TUDO que esta
-- acima, e sao gravadas por `scripts/marcar-fixtures.php`. Quem carrega
-- este arquivo grava a marca junto, sem precisar saber disso; quem le o
-- banco descobre se o cenario dele e o de hoje ou o de uma semana atras.
--
-- `CaracterizacaoTestCase` compara as duas e recusa rodar quando diferem.
CREATE TABLE IF NOT EXISTS _fixtures_versao (id smallint NOT NULL PRIMARY KEY, sha char(40) NOT NULL);
DELETE FROM _fixtures_versao;
INSERT INTO _fixtures_versao (id, sha) VALUES (1, '3fcfa04408c0e41cd05e67bc5b7a16ef505af4ee');
