3. Conversão de Valores — Guia para sessões de IA

✅ Todas as regras de preço por convênio EM PRODUÇÃO (23–24/09/2026) — zero é zero; Utiliza = cobertura (sem Utiliza: receita 0, orçamento a R$ 0,00); itens sempre entram (abre = true); Zerar por item, sem cascata; linha ✅ do serviço = base; Farol consolidado; tipo de atendimento por convênio; textos e valores finais convertidos; aba Farol › Itens e GET /convenios/{id}/farol/itens por linha. Nenhum item da série segue pendente de ativação (série 22–24/09); a coluna Valor do serviço com 4 linhas (linha Σ) está ✅ em produção desde 24/09.
Novidades de 01–15/10/2026:
Novidades de 24–30/09/2026:
📌 Nota: esta é a versão para o manual; a versão técnica completa (tabelas/consultas) fica na wiki interna do GitLab (Implantação › IA-Onboarding › Conversão de Valores — Guia para IA).

Especificação operacional para uma IA que vai coletar, configurar, validar ou explicar preços no RABI. Complementa a visão geral e o Guia do Implantador (nomes de tela). Regra de serviço composto = regra única de 18/09/2026, refinada em 22–23/09/2026 (itens sempre entram; zerar por item sem cascata) — em produção desde 23–24/09/2026. Para a precedência de cada atributo (nome, descrição, código, tabela 87, tipo de atendimento, valor, entra/não entra, custo) veja a Árvore de decisão do cadastro no convênio.

0. Regras de conduta para a IA

  1. Nunca escreva direto no banco. Configure pela tela, pela importação Excel das abas do convênio ou pela API externa. As consultas de verificação (mantidas na wiki interna) são somente leitura e devem rodar no banco de desenvolvimento, salvo autorização explícita e pontual do responsável.
  2. Não invente preço. Todo valor vem de contrato/tabela fornecida pela clínica. Sem o dado → pergunte.
  3. Vazio ≠ zero. Ausência de regra = campo vazio. 0 só quando o item é gratuito naquele convênio.
  4. Valores monetários no banco são inteiros em centavos (35000 = R$ 350,00). Fator K é percentual (15 = +15%).
  5. Depois de configurar, sempre valide (seção 6 e seção 7) — lendo a árvore de cada serviço configurado pelo Expandir serviço (tela) ou por GET /convenios/{id}/farol/itens/{servicoRaizId} (API) — e apresente ao humano o valor efetivo antes de considerar concluído.
  6. Antes de excluir/inativar produto ou taxa, liste os serviços em que ele está e substitua-o na composição — desde 02/10/2026 o sistema recusa (tela e API: 409) a exclusão de item em uso em serviço ativo (2.13).
  7. Multi-tenant: cada clínica tem o seu ambiente próprio. Confirme o ambiente/tenant da clínica antes de qualquer leitura.
  8. ✅ Novo — 30/09/2026 Pela tela, o convênio abre em modo consulta (#632, em produção desde 29/09/2026): consultar é seguro — nada é gravado (a tela avisa: "Modo consulta. Para alterar, clique em Liberar para edição."). Ao conduzir um humano numa alteração de convênio (valores, Utiliza, Pacote, Zerar, especialidades, colaboradores, planos, taxas, produtos, serviços, dados fiscais, copiar, importar planilha), a sequência é sempre Liberar para edição → alterar → Salvar (no cabeçalho do convênio): ✅ Novo — 01/10/2026 as abas Planos, Especialidades, Produtos, Serviços e Taxas só gravam no Salvar (a célula pendente fica destacada); ações em massa (Selecionar/Desmarcar todos, Copiar, Importar) e as abas Colaboradores, Custos extras, Farol e Dados Fiscais gravam na hora. A liberação vale só nesta visita — ao terminar, Bloquear edição. Para saber quem alterou, botão Histórico (#638). Conflito: "Este registro foi alterado por outra pessoa. Recarregue a tela antes de alterar." (#640). Convênio recém-criado abre liberado; usuário sem permissão só consulta ("Modo consulta. Você não tem permissão para alterar convênios."). Não conduza o humano por "Selecionar todos" nas colunas Retorno/Autorização/Pacote (só mexe no Utiliza) nem por "Copiar convênio" (correção não confirmada — #639). A API externa não muda: PUT /convenios/{id}/… grava normalmente.
  9. Nunca publique nem registre o token de API (rbk_ ou rbt_) em documento, chamado, e-mail, manual ou conversa salva; token de uma clínica não acessa outra; suspeita de vazamento → revogar e gerar outro.

1. Modelo de dados (tela ↔ API ↔ banco)

🔒 Seção técnica (nomes de tabelas/colunas, consultas e arquivos de código) mantida apenas na wiki do GitLab, de acesso restrito: Implantação › IA-Onboarding › Conversão de Valores — Guia para IA. Não é copiada para o manual.

2. Algoritmo exato

Notação: os nomes em codigo abaixo são pseudocódigo e correspondem aos campos de tela descritos no Guia do Implantador.

2.1 Valor unitário de PRODUTO no convênio

cp  = cadastro do produto DENTRO do convênio (aba Produtos)   # pode não existir
pol = Política de Preço por Tipo de Produto do convênio (ativa)
cfg = aba Estoque do cadastro do produto

se cp.ValorUnitario (convertido) está preenchido:
    return cp.ValorUnitario * (1 + (cp.FatorK ou 0)/100)
    # Fator K SÓ do próprio cp — não herda de pol/cfg

fonte  = cp.fonte ?? pol.fonte ?? cfg.fonte            # herança campo a campo (?? = só vazio desce)
tipo   = cp.tipoPrecificacao ?? pol.tipoPrecificacao ?? cfg.tipoPrecificacao
fatorK = cp.fatorK ?? pol.fatorK ?? cfg.fatorK ?? 0

se fonte == vazio: return 0
caso fonte.nome:
  'PRECO FIXO CADASTRADO'    -> Preço de venda tabela (aba Estoque)             # SEM fator K
  'PRECO DA ULTIMA COMPRA'   -> última compra unitária * (1+fatorK/100)
  'PRECO DA ULTIMA PESQUISA' -> Preço da última pesquisa * (1+fatorK/100)
  'PRECO MEDIO DE COMPRA'    -> preço médio por unidade * (1+fatorK/100)
  outra (tabela interna)     -> (tabela[produto][tipo] || Preço de venda tabela || 0) * (1+fatorK/100)

# EM PRODUÇÃO desde 15/10/2026 (#662, 1ª fase): nível 2 de REFERÊNCIA OFICIAL, entre cp e pol.
#   Só se o convênio tiver "Referências oficiais por tipo de produto" para o tipo do produto.
#   preço  = cp.valor || (preçoEdiçãoVigente / fatorConversão * (1 + (cp.fatorK ?? ref.ajuste%)/100)) || pol || cfg
#            (arredondado ao centavo; o Fator K do item substitui o ajuste da referência)
#   código = cp.codigo || códigoPrincipalDaPublicação || cfg
#   descr. = cp.descricao || descriçãoOficial (se marcado) || cfg
#   Vale em Farol, orçamento, autorização, atendimento, pré-faturamento, guia e XML.
#   XML descarta itens das tabelas 05 e 12: na política use 20 (medicamentos) ou 19 (materiais).
#   CUIDADO: importação de preços pela tela RETIRADA em 15/10 — sem preço carregado, cai para pol/cfg.
#   Não afirme que há preço de referência carregado sem confirmar com o time Rabi.
# Convênio sem a regra nova continua exatamente como acima.

2.2 Valor de TAXA no convênio

Valor da taxa no convênio, se preenchido; senão o Valor do cadastro da taxa — 0 explícito é respeitado. Custo = 0.

2.3 Valor PRÓPRIO (base) de SERVIÇO no convênio

Valor convertido do serviço no convênio, se preenchido — inclusive quando 0 (zero é zero); senão 0 se o serviço soma itens; senão o Valor do cadastro.
✅ Corrigido em 23/09/2026 valor_interno considera o valor convertido inclusive quando 0: só desce de nível se o campo estiver vazio/null. Vale em todas as telas (Farol, linha ✅, agendamento, orçamento, pré-faturamento, contas a receber e XML) — antes o Farol tratava 0 como vazio.

2.4 Valor TOTAL de serviço composto (recursivo, por convênio) ✅ Em produção desde 23–24/09/2026

func pacote_fechado(S, C):
    return sc(S,C).pacote AND (NOT S.somar_itens OR valor_convertido(S,C) preenchido)
    # "preenchido" inclui 0 — só vazio/null conta como não preenchido
    # sc(S,C).pacote é OBRIGATÓRIO: valor_convertido (combinado) ou preço fixo SEM pacote
    # NUNCA fecha pacote — só troca a base; os itens somam por cima (regra vigente, 25/09)
    # pacote existe só em sc (serviço × convênio); não há pacote no catálogo do serviço

func valor(S, C, zeraCtx = false):
    base = base(S, C)                                        # 2.3
    abre = true                                              # desde 23/09: itens SEMPRE entram
                                                             # (somar_itens decide só a base)
    zera = zeraCtx OR pacote_fechado(S, C)                   # contexto desce para todos os níveis
    total = base
    para cada item i de S (produto, taxa, subserviço) com quantidade q:
        se NOT utiliza(i, C):
            continue          # NAO_UTILIZA_NO_CONVENIO — se i é subserviço, a subárvore toda
                              # fica fora (PAI_FORA_DO_TOTAL). Único corte que cascateia.
        zerado = zera AND zerar(i, C)                        # ZERADO_EM_PACOTE (só a linha de i)
        se i é subserviço:
            v = valor(i, C, zera)                            # itens de i avaliados um a um
            se zerado: v = v - base(i, C)                    # perde SÓ a base (não cascateia, 24/09)
            total += q * v
        senão:
            se zerado: continue
            total += q * valor_unitario(i, C)                # 2.1 / 2.2
    return total

custo(S) = Σ de TODOS os produtos da árvore (sem filtro de Utiliza/Pacote/Zerar)

Exclusões possíveis de um item: só duas — (a) sem Utiliza; (b) Zerar marcado dentro de pacote de preço fechado (do próprio serviço ou de um ancestral). O motivo histórico PAI_NAO_SOMA_ITENS deixou de existir em 23/09/2026. Ciclos são cortados pelo caminho visitado. O "Zerar valor em pacotes" do serviço raiz não zera a própria base; zerar nunca altera o valor do item avulso.

Linha ✅ do serviço na aba Serviços = base(S, C) (valor da linha de procedimento do XML), não valor(S, C). O Farol do serviço usa valor(S, C) ÷ custo(S). A linha Σ (em produção desde 24/09) exibe valor(S, C) — ver 2.11.

Consequência direta (regra vigente): zera só fica verdadeiro com sc(S,C).pacote = true (no próprio serviço ou num ancestral). Com valor combinado e pacote = false, valor(S, C) = valor_convertido + Σ itens com Utiliza — o zerar dos itens não é consultado.

Diagrama da conta do serviço composto: base mais soma dos itens que passam pelas duas perguntas (Utiliza? / zerado em pacote de preço fechado?)
A conta do serviço composto — mesma fórmula da seção 2.4.

2.5 Regra transacional (orçamento) — quantidade usada × quantidade da composição ✅ Em produção desde 23/09/2026

embute = composicao_qtd > 0 AND ( absorvido_por_pacote_acima
                                  OU (zera AND zerar(item)) )
        # desde 23/09: serviço de preço fixo SEM Pacote NÃO embute mais
se embute: cobra 0 pela qtd da composição e preço cheio só pelo EXCEDENTE
senão:     cobra preço cheio pela quantidade inteira
preço cheio = cadeia de conversão do convênio (nível 3 → política → cadastro), nunca o preço da casa avulso
item sem Utiliza (produto, taxa ou subserviço + subárvore): entra a R$ 0,00 (tem custo, sem receita)
linha do serviço = base(S,C)   (0 se o subserviço está zerado dentro de pacote de preço fechado;
                                os itens dele não zerados continuam cobrados)

Para o preço fixo (ou o valor combinado) "já incluir" itens no orçamento: Pacote = true no serviço + Zerar = true nos itens inclusos. Sem isso, o serviço cobra os itens na quantidade inteira — valor combinado sozinho não embute nada. O serviço raiz do orçamento não é zerado por Utiliza (a tela só oferece serviços que o convênio utiliza). Orçamento existe só para convênio "Pago no ato do atendimento".

2.6 Farol ✅ Atualizado — 12/10/2026

custo_farol(S, C, profissional?) = custo_produtos(S)                        # todos os produtos da árvore
                                 + custo_extra_convenio(S, C)              # aba Custos extras (#655)
                                 + prestadores(S, C)                       # painel Serviços extras
                                 + repasse(profissional, S, C)             # regra do serviço ou linha geral
        # sem profissional definido: repasse = MAIOR repasse entre quem atende S e aceita C (pior caso)
        # custo_extra: Percentual da receita → % × receita cobrada de cada linha incidente
        #              Valor fixo por execução → valor × quantidade × sessões; respeita vigência e "Incide sobre"

indice = receita / custo_farol * 100
cor:   custo_farol = 0                         → sem cor
       algum produto com custo de produtos 0   → ROXO (SEM_CUSTO) — bloqueia
       indice  < Parâmetro Vermelho (%)        → VERMELHO
       Vermelho ≤ indice < Parâmetro Amarelo   → AMARELO   (exatamente no limite do vermelho = AMARELO, desde 12/10)
       indice ≥ Parâmetro Amarelo (%)          → VERDE
bloqueio/alçada: se "Custos extras (convênio, prestadores e repasse) também bloqueiam" = false (PADRÃO),
                 usam a cor calculada SEM custo_extra, prestadores e repasse; a cor exibida inclui tudo

Parâmetros da régua: Configurações › Parâmetros › aba Valores (defaults 100/120). Opção de bloqueio e botão "Ver serviços que mudam de cor": Configurações › Parâmetros › Orçamento. Antes de 12/10/2026 o custo era só o dos produtos: serviço ou taxa sem produto ficava sem cor, e o índice igual ao limite vermelho bloqueava. Detalhes em 2.15.

2.7 Farol consolidado (orçamento, agendamento, autorização) ✅ Em produção desde 23/09/2026

func farol_consolidado(pedido, C):
    receita = Σ receita(item, C) para TODOS os serviços, produtos e taxas do pedido
              # só itens com Utiliza geram receita, pela cadeia de conversão do convênio
              # item SEM Utiliza: receita = 0 (o custo dele CONTA)
    custo   = Σ custo(TODOS os produtos envolvidos)
              + custos extras do convênio + prestadores + repasse   # desde 12/10/2026 (2.6, 2.15)
    se algum produto com custo 0 (ou item sem preço): return ROXO   # bloqueia
    indice  = receita / custo * 100                     # cores pelos parâmetros de 2.6
    return cor(indice)   # bloqueio/alçada: cor SEM os custos novos enquanto o parâmetro estiver desmarcado

2.8 Tipo de atendimento efetivo ✅ Em produção desde 23/09/2026

tipo_atendimento_efetivo(S, C) = tipo_atendimento_convertido(S, C) se definido no convênio
                                  senão tipo_atendimento do cadastro do serviço

Configurado na coluna Tipo de Atendimento da aba Serviços do convênio (3 linhas 🔒/🔁/✅). O efetivo vai para o atendimento, o pré-faturamento e o campo tipoAtendimento do XML.

2.9 Textos e valores finais convertidos ✅ Em produção desde 24/09/2026

precedência de exibição (todas as telas do convênio e a aba Farol):
    nível 3 (item no convênio)  →  nível 2 (política do convênio — SÓ preço de produto)  →  catálogo
texto vazio ('') = vazio (desce); 0 = zero (não desce)

serviço  nome       = nome_conversao(S,C)       ?? nome(S)
         descrição  = descricao_convenio(S,C)   ?? descricao(S)
         código     = codigo(S,C) ?? codigo_convenio(S,C) ?? codigo(S) ?? codigo_tuss(S)
         tabela 87  = tabela87(S,C)  ?? tabela87(S)       (idem tipo de código)
         parcelas   = parcelas(S,C)  ?? limite_parcelas(C)
produto  nome/descr = convertido(P,C) ?? cadastro(P)
         código     = codigo_conversao(P,C) ?? código da tabela da fonte de preço ?? codigo(P)
         tabela 87  = tabela87(P,C)  ?? tabela87(P)
taxa     nome/descr = convertido(T,C) ?? cadastro(T)
         código     = codigo(T,C) ?? codigo(T)
         tabela 87  = tabela87(T,C)  ?? tabela87(T)

2.10 Farol › Itens — cada linha reflete só ela ✅ Em produção desde 24/09/2026

para cada linha L da árvore do serviço raiz R no convênio C:
    valor_efetivo(L) = valor considerado na conta; 0 se L ficou fora por qualquer motivo
    conta_no_total(L) = Sim | Não   (+ motivo: NAO_UTILIZA_NO_CONVENIO | ZERADO_EM_PACOTE | PAI_FORA_DO_TOTAL)
    se L é produto ou taxa:  receita, custo, margem, farol = só da própria linha
    se L é subserviço:       receita, custo, margem, farol = total da subárvore de L
    se L é o serviço raiz:   receita, custo, margem, farol = total do serviço (= Farol do serviço)

Fontes de dados — todas com os mesmos números (mesma função no banco; nunca recalculados na tela):

FonteQuando usar
Expandir serviço (tela) ✅ Novo — 26/09/2026 — seta da linha em Convênios › [convênio] › aba Serviços, ou em Serviços › [serviço] › aba ConvêniosConferência humana de um serviço: colunas Farol · Item tipo · Item nome · Tipo código · Código · Tabela 87 · Zerar valor · Somar itens · Conta no total · Utiliza · Motivo · Unidade de medida · Quantidade · Custo unitário · Receita unitária · Custo total · Receita. Itens fora da cobrança aparecem esmaecidos; Motivo em português ("Convênio não utiliza", "Zerado em pacote", "Subserviço pai fora do total"). Concluído em 25/09/2026 (#625). ✅ Novo — 29/09/2026 No Expandir serviço, o tooltip da bolinha do Farol de cada linha mostra margem, receita e custo; não há linha de total no fim da lista (o total é a linha Σ da coluna Valor / a linha nivel = 0); ao salvar valor, Pacote ou Zerar na linha do serviço, a lista expandida se atualiza sozinha.
Aba Farol › Itens (tela)Varredura de todos os serviços do convênio.
GET /convenios/{id}/farol/itens/{servicoRaizId} (API externa) ✅ Novo — 26/09/2026Árvore de um serviço raiz, sem paginação nem envelope (poucas dezenas de linhas), com farol_servico, margem_servico_pct e totais já calculados por subárvore (cada SUBSERVICO traz o total da própria subárvore). Preferível quando já se sabe o serviço. Permissão convenio:read.
GET /convenios/{id}/farol/itens (API externa)Árvore paginada (envelope padrão) de vários serviços; filtros servicoRaizId, itemTipo, itemNome, search, apenasAtivosNoConvenio, servicoAtivo.

Campos de cada linha (ambas as rotas de itens; valores em reais): servico_raiz_id, servico_raiz, convenio_id, convenio, item_tipo (SERVICO_RAIZ / SUBSERVICO / PRODUTO / TAXA), nivel (0 = raiz), caminho, servico_pai_id, servico_pai, item_id, item_nome, item_descricao, codigo, tipo_codigo, tabela_ans_87, zerar_valor, somar_itens, conta_no_total, motivo_exclusao, unidade_medida, quantidade, quantidade_efetiva, custo_unitario, receita_unitaria, custo_item_total, receita_item_total, custo_total_servico, receita_total_servico, margem_servico_pct, farol_servico (VERDE / AMARELO / VERMELHO / SEM_CUSTO), utiliza_no_convenio, pacote_pai.

algoritmo de diagnóstico ("por que o serviço R está vermelho / o que a guia cobra?"):
    linhas = GET /convenios/{C}/farol/itens/{R}
    raiz   = linha com nivel = 0          # receita_total_servico = Σ = valor(R, C); farol_servico = cor do serviço
    fora   = linhas com conta_no_total = false  → ler motivo_exclusao:
               NAO_UTILIZA_NO_CONVENIO | ZERADO_EM_PACOTE | PAI_FORA_DO_TOTAL
    dentro = linhas com conta_no_total = true   → cobradas na guia (receita_item_total)
    culpado = linha(s) com maior custo_item_total e menor receita_item_total;
              SUBSERVICO: olhar farol_servico/margem_servico_pct da própria subárvore
    comparar com o contrato: item incluso no pacote deve estar fora por ZERADO_EM_PACOTE;
              item cobrado à parte deve estar dentro

✅ Correção 26/09/2026 A API externa traz sim margem (margem_servico_pct), "conta no total" (conta_no_total) e o motivo (motivo_exclusao) — não é preciso calcular a margem a partir de receita e custo. A sub-aba Farol › Serviços, que mostrava "0 registros", foi corrigida.

2.11 Coluna Valor do serviço — 4 linhas ✅ em produção desde 24/09

coluna Valor do SERVIÇO S no convênio C (aba Serviços):
  🔒 = S.somar_itens ? Σ itens a preço de CASA  (etiqueta "(soma dos itens)")
                     : Valor do cadastro de S
  🔁 = valor_convertido(S, C)                    (vazio = não digitado)
  ✅ = base(S, C)                                 (linha de procedimento do XML)
       se S.somar_itens E valor_convertido vazio → 0   # não é erro
          explicação "0,00 (sem preço próprio: itens cobrados à parte)":
          hoje no tooltip da linha ✅; texto visível na própria linha = próximo ajuste
  Σ  = valor(S, C)  (2.4)  = receita total do Farol do serviço = o que o convênio paga

produtos, taxas e coluna Tipo de Atendimento: continuam com 3 linhas (🔒/🔁/✅)
o mesmo total também está no Farol / Farol › Itens / Expandir serviço
API do sistema (usada pela tela): item do serviço traz somarItens (boolean) e efetivo.totalConvenio (= Σ)
API externa: somarItens aparece no Swagger (cadastro de serviço); efetivo.totalConvenio não aparece no Swagger
             → para o total pela API externa, use receita_total_servico da linha nivel = 0
               em GET /convenios/{id}/farol/itens/{servicoRaizId} (2.10)

Caso motivador: "Ferinject aplicado" no convênio Particular, com "Definir preço do serviço pelos itens" marcado — ✅ mostrava R$ 0,00 e parecia erro. É o comportamento correto: a base é 0 e o total (medicamento + aplicação) está em Σ / Farol.

2.12 Gravando pacote pela API externa ✅ Regra vigente

PUT /convenios/{id}/servicos   { "servicos": [ { "servicoId": S, "utiliza": true,
                                                 "valorInternoConvenio": 100.00,   # null limpa; omitido mantém
                                                 "pacote": true } ] }             # SEM isto não é pacote
PUT /convenios/{id}/produtos   { "produtos":  [ { "produtoId": P, "utiliza": true, "zerarValor": true } ] }
PUT /convenios/{id}/taxas      { "taxas":     [ { "taxaId":    T, "utiliza": true, "zerarValor": true } ] }
PUT /convenios/{id}/servicos   subserviço incluso: { "servicoId": U, "utiliza": true, "zerarValor": true }

valorInternoConvenio sozinho não fecha pacote: sem pacote: true, os itens somam por cima e o zerarValor deles nem é lido. Envie zerarValor explicitamente em cada item (true nos inclusos, false nos cobrados à parte) — não dependa de valor padrão; desde 25/09/2026, criar o vínculo do serviço marcando só pacote não liga mais o zerar sozinho. Confira o resultado por GET /convenios/{id}/farol/itens/{servicoRaizId}: inclusos com conta_no_total = false e motivo_exclusao = ZERADO_EM_PACOTE. Detalhe: Implantação pela API › abas do convênio.

2.13 Excluir/inativar produto ou taxa que está em composição ✅ Bloqueio em produção — 02/10/2026

DESDE 02/10/2026 (#626):  exclusão/inativação de produto ou taxa presente na composição de serviço ATIVO
                          → RECUSADA. Tela: "Não é possível excluir" + lista Serviço / Código / Quantidade
                            (link para cada serviço). API externa: DELETE /produtos/{id}, DELETE /taxas/{id}
                            e PUT /produtos/{id} com ativo:false → 409, lista em "servicos"
                          → serviço INATIVO não bloqueia; sem cache: corrigida a composição, passa na hora

procedimento para a IA ao substituir o item X:
    1. listar os serviços que contêm X: a própria recusa (409 / tela) traz a lista;
       ou GET /convenios/{id}/farol/itens?itemNome=… (item_id = X; servico_raiz_id = serviço afetado)
    2. substituir X na composição: PUT /servicos/{id} só com a LISTA afetada (PUT parcial, 2.14):
       produtoIds (produto) ou servicoTaxa: [{taxaId, quantidade}] (taxa) — a lista enviada
       SUBSTITUI a atual, então envie a lista inteira daquele tipo, já com o substituto
       e marcar utiliza/zerarValor do substituto nos convênios (PUT /convenios/{id}/produtos|taxas)
    3. então excluir/inativar X; conferir a árvore (farol/itens/{servicoRaizId})

histórico: até 02/10/2026 a exclusão era livre e o item sumia da composição sem aviso
           → serviços cujo item foi excluído antes disso podem estar cobrando menos

Do mesmo jeito, fornecedor usado em custo extra ou prestador ativo de convênio não pode ser excluído nem inativado (tela).

2.14 Contrato da API externa: composição do serviço, PUT parcial e lote no estoque ✅ Atualizado — 13/10/2026

Correção geral da API externa em produção desde 28/09/2026 (17:43, Brasília) e, desde 01–02/10/2026, regra única de PUT (#634 corrigido). Swagger de 13/10/2026: 270 operações / 193 caminhos.

REGRA DO PUT (serviços, orçamentos, pacientes e vínculo de convênio, colaboradores, convênios,
              grades de colaborador/equipamento, movimentações financeiras, guias de faturamento):
  campo omitido   → MANTÉM o valor atual
  null            → LIMPA (ex.: perfilFiscalId: null desvincula; valor: null vira 0)
  lista omitida   → MANTÉM os vínculos
  lista enviada   → SUBSTITUI os vínculos por exatamente o que veio ([] apaga)
  PUT cuja descrição no Swagger não diz nada → trate como sobrescrita (GET antes, objeto completo)

POST /servicos · POST /servicos/bulk · PUT /servicos/{id}
  documentos:           [ { "id": 3 } ]                              # documentos obrigatórios (ex.: PRESCRIÇÃO MÉDICA)
  perfilFiscalId:       "…" | null                                   # perfil fiscal NFS-e
  servicoTaxa:          [ { "taxaId": T, "quantidade": 1 } ]          # taxas do serviço
                        # SAÍRAM taxaServicoId e valorTaxaServico — não os envie mais
  produtoIds:           [ P ]  ou  [ { "id": P, "quantidade": 2, "valorUnitario": 12.50 } ]
                        # produto enviado SEM valorUnitario mantém o valor que já tinha no serviço;
                        # produto NOVO sem valor entra com 0
  equipamentoIds:       [ E ]  ou  [ { "id": E } ]
  servicosRelacionados: [ U ]  ou  [ { "servicoId": U, "quantidade": 1 } ]   # subserviços
  ex.: { "nome": "X" } só renomeia; { "documentos": [{ "id": 3 }] } deixa só o documento 3

POST /estoque/saida · POST /estoque/transferencia
  lote: OBRIGATÓRIO → "L123" ou null (produto sem lote)

2.15 Custos extras do convênio, prestadores e repasse no custo do Farol ✅ Novo — 12/10/2026

CUSTO EXTRA DO CONVÊNIO (aba Custos extras — grava na hora, fora do Salvar do convênio)
  tipo = PERCENTUAL DA RECEITA   → percentual (0–100) × receita cobrada de cada linha incidente
                                   (5% em cada linha = 5% da guia)
  tipo = VALOR FIXO POR EXECUÇÃO → valor × quantidade × sessões
  incide sobre: Tudo | Só serviços | Só produtos | Só taxas | Serviços específicos (lista)
  vigência: início / fim (vazio = "Sempre"); credor (fornecedor) opcional; grupo do DRE = só classificação

PRESTADORES (painel Serviços extras ao expandir o serviço na aba Serviços do convênio)
  prestador (fornecedor) · descrição · valor fixo por execução · quantidade · vigência
  por convênio (o do convênio sobrescreve o geral); percentual de prestador: ainda não existe

REPASSE DO PROFISSIONAL
  profissional definido → regra do profissional para o serviço, senão a LINHA GERAL do tipo (#643)
  sem profissional      → MAIOR repasse entre quem atende o serviço e aceita o convênio (pior caso)

NÃO MUDA: guia, XML, valores cobrados, repasse pago, DRE (custo extra é projeção; não gera lançamento)
VALE EM:  orçamento, agendamento, autorização, aba Serviços do convênio, serviço × convênios,
          relatórios de Farol e as leituras de Farol da API

Composição exibida no tooltip/expansão: Produtos, Custo extra do convênio, Prestadores (serviços extras), Repasse, Custo total, Receita, Índice. Ao configurar, cadastre os custos extras antes de validar o Farol e avise o humano que a cor de alguns serviços pode mudar sem mudança de preço. Não ligue a opção de bloqueio sem antes rodar "Ver serviços que mudam de cor" e ter a aprovação da clínica.

3. Fontes de verdade para leitura

🔒 Seção técnica (nomes de tabelas/colunas, consultas e arquivos de código) mantida apenas na wiki do GitLab, de acesso restrito: Implantação › IA-Onboarding › Conversão de Valores — Guia para IA. Não é copiada para o manual.

4. Árvore de decisão — do contrato para a configuração

Para cada serviço × convênio, pergunte nesta ordem (versão detalhada, atributo por atributo, em Árvore de decisão do cadastro):

(tela) toda alteração de convênio: "Liberar para edição" → alterar → "Salvar" no cabeçalho
       (modo consulta #632; desde 01/10 as abas só gravam no Salvar); pela API externa não há esse passo.
0. (convênio, uma vez) aba Especialidades: Atende marcado em cada especialidade que o convênio cobre,
   ANTES de configurar serviços e profissionais do convênio (serviço de especialidade não atendida
   fica "Não atendida" e não aceita Utiliza). No agendamento/orçamento a trava está DESLIGADA
   desde 06/10/2026 (#628). Exceção: a consulta de disponibilidade da IA (TalkMe, #633)
   respeita a coluna Atende (a IA pode dizer "não temos" onde a recepção agenda). Convênio sem nenhuma especialidade Atende não restringe nada.
0b. (convênio, uma vez) aba Custos extras: custos que a operadora cobra à parte (2.15).
1. O convênio atende este serviço?            não → Utiliza = false. FIM.
2. O preço é um valor fechado negociado (já inclui itens)?
   sim → Valor convertido do serviço = preço; Pacote = true (OBRIGATÓRIO — valor convertido
         sozinho NÃO fecha pacote; pacote só existe no convênio);
         para CADA item da composição, inclusive os de dentro de subserviços
         (zerar NÃO desce em cascata):
             já incluso no preço? → Zerar = true · cobrado à parte? → Zerar = false
   não → 3
3. O preço é "soma do que foi usado" (medicamento + aplicação…)?
   sim → "Definir preço do serviço pelos itens" = true; Valor convertido = vazio; Pacote = false;
         garantir Utiliza = true em cada item/subserviço; preço de cada item pelos 3 níveis
         (se há um valor extra do convênio sobre o serviço, ele vai em UM lugar:
          no Valor convertido da raiz OU no subserviço)
   não → 4
4. Preço fixo do serviço (valor próprio):
   igual ao da casa → Valor convertido vazio
   diferente        → Valor convertido = preço  (muda só a base — NÃO é pacote)
   a composição tem itens?  → eles ENTRAM por cima (desde 23/09), cada um com Utiliza:
       todos cobrados à parte → Pacote = false (nada a zerar)
       algum já incluso no fixo → Pacote = true + Zerar=true nos inclusos, Zerar=false nos cobrados à parte
   item que o convênio não cobre → Utiliza = false (custo sem receita)

Para cada produto × convênio: preço específico → Valor Unitário convertido na aba Produtos; regra por tipo (tabela ± %) → política de nível 2; nada → herda o cadastro. Não cobre → Utiliza = false. Gratuito → Valor Unitário convertido = 0.

5. Dados a coletar da clínica (checklist de perguntas)

6. Invariantes a validar antes de concluir

#Invariante
I1Todo item de composição de serviço atendido tem Utiliza marcado no convênio
I2Serviço com preço fechado tem Pacote marcado e itens inclusos com Zerar marcado
I3Sem valor duplicado raiz × subserviço
I4Nenhum serviço com valor convertido de R$ 0,01 no convênio (marcador antigo de "sem valor")
I5Nenhum produto utilizado sem custo
I6receita_total = receita_servicos + receita_produtos + receita_taxas
I7Valor de cadastro do serviço = 0 quando "Definir preço do serviço pelos itens" está marcado
I8Serviço que soma itens tem ao menos um item que conta no total, ou valor convertido preenchido
I9Serviço de preço fixo com composição e sem Pacote: confirmado com a clínica que os itens são cobrados à parte (desde 23/09/2026 eles entram sempre). Se o preço já os inclui → Pacote + Zerar
I10Em pacote de preço fechado, todo item incluso dentro de subserviços tem o próprio Zerar marcado (zerar o subserviço não zera o que está dentro dele)
I11Linha ✅ do serviço = valor próprio (base); Farol do serviço e linha do serviço em Farol › Itens = total. Conferir os dois
I12Valor combinado não é pacote: todo serviço cujo contrato é "preço fechado que já inclui itens" tem Pacote marcado — valor convertido preenchido com Pacote desmarcado significa, por definição, "itens cobrados por cima". Nunca conclua que um valor convertido embute itens sem Pacote = true
I13✅ vigente desde 24/09 Linha Σ da coluna Valor = valor(S, C) = receita do Farol do serviço = efetivo.totalConvenio na API do sistema
I14✅ Novo — 26/09/2026 Para cada serviço configurado, a árvore (farol/itens/{servicoRaizId} ou Expandir serviço) bate com o contrato: itens inclusos no pacote com conta_no_total = false e motivo_exclusao = ZERADO_EM_PACOTE; itens cobrados à parte com conta_no_total = true; nenhum NAO_UTILIZA_NO_CONVENIO inesperado
I15✅ Novo — 26/09/2026 Nenhum produto/taxa foi excluído ou inativado enquanto ainda fazia parte da composição de um serviço ativo (desde 02/10/2026 o sistema bloqueia — #626; confira exclusões anteriores)
I16✅ Novo — 29/09/2026 Toda especialidade dos serviços e profissionais configurados no convênio está com Atende marcado na aba Especialidades (no cadastro do convênio, especialidade faltando deixa o serviço "Não atendida", sem Utiliza; a trava no agendamento está desligada desde 06/10/2026 — #628)
I17✅ Novo — 29/09/2026 Serviços gravados pela API usam servicoTaxa (não taxaServicoId/valorTaxaServico) e a composição lida de volta bate com a planilha; o que foi gravado antes de 28/09/2026 17:43 passou pela conferência retroativa (2.14)
I18✅ Novo — 30/09/2026 #633 (em produção desde 09/10/2026) — se a clínica usa a IA TalkMe: todo profissional tem Atende convênio em cada convênio que atende; a grade dele tem os serviços e os convênios (Incluir/Excluir); o convênio tem Utiliza nos serviços cobertos e, se usar, Atende nas especialidades; e está ativo na unidade onde é atendido. Faltando algo, a IA e o painel Disponibilidade por Convênio (#659, desde 09/10 — convênios por unidade vêm de "Unidades do convênio") podem responder "sem atendimento", mesmo que a recepção consiga agendar pela tela. A consulta não mostra horários (esses vêm da agenda). ✅ Novo — 14/10/2026 Desde 14/10 (#664) a IA também não oferece serviço que o Farol bloqueia ou que exige aprovação, e o painel (com convênio no filtro) esconde os bloqueados pelo Farol — um serviço vermelho/roxo para o convênio explica um "sem atendimento".
I19✅ Novo — 30/09/2026 As Políticas de Preço por Tipo de Produto de cada convênio estão ativas e conforme o contrato (até 29/09/2026, um Salvar pela tela feito antes de as políticas carregarem mandava lista vazia e inativava todas — corrigido)
I20✅ Novo — 12/10/2026 Os custos que a operadora cobra à parte estão na aba Custos extras e os prestadores no painel Serviços extras; o repasse de cada profissional (inclusive a linha de repasse geral) está cadastrado — o Farol só fica realista com isso (2.15)
I21✅ Novo — 01/10/2026 Toda alteração feita pela tela no convênio foi salva (nenhuma linha destacada como pendente; mensagem "N alteração(ões) das abas gravada(s)") e conferida pelo Histórico
I22Nenhuma coluna Retorno/Autorização/Pacote foi alterada por "Selecionar todos" (só alterna o Utiliza) e nenhum convênio foi montado por "Copiar convênio" sem conferência completa depois (#639)

7. Consultas de verificação (somente leitura)

🔒 Seção técnica (nomes de tabelas/colunas, consultas e arquivos de código) mantida apenas na wiki do GitLab, de acesso restrito: Implantação › IA-Onboarding › Conversão de Valores — Guia para IA. Não é copiada para o manual.

8. Casos de teste de referência ✅ Em produção desde 23–24/09/2026

Colunas: "somar" = Definir preço do serviço pelos itens · "pacote" = Pacote no convênio · "valor convertido" = Valor convertido do serviço no convênio ("—" = campo vazio; 0 preenchido é zero de verdade) · item = (valor · Zerar · Utiliza; T = marcado, F = desmarcado). Valores ilustrativos.

#somarpacotevalor convertidoitem (valor · zerar · utiliza)esperado
T1FF—valor fixo 100; produto 50·F·T150 (itens sempre entram; até 23/09 dava 100)
T2FT—fixo 100; produto 50·T·T100
T3FT—fixo 100; produto 50·F·T150
T4FT90produto 50·F·T140
T5TF—produto 3000·T·T3000 (zerar ignorado)
T6TF266,16produto 3000·F·T3266,16
T7TT—produto 135,42·T·T + sub fixo 80,00215,42 (nada zerado)
T8TT3506,53produto 3000·T·T3506,53
T9TF—produto 3000·F·F0 (não utiliza)
T10T——sub com utiliza=F contendo produtosub e produto fora (PAI_FORA_DO_TOTAL); custo do produto conta
T11orçamento, T8, usou 2 (composição 1)3506,53 + 3000 (excedente)
T12FF0,00 (explícito)valor de cadastro 100; produto 50·F·Tbase 0 (zero é zero; não desce para o cadastro) + produto 50 = 50; linha ✅ do serviço = 0
T13Farol consolidado: orçamento com serviço A (receita 50, custo 100 → linha vermelha) + serviço B (receita 500, custo 100 → linha verde); parâmetros 100/120consolidado = 550/200 = 275% → VERDE, não bloqueia (a regra antiga, da cor mais crítica, daria vermelho)
T14Farol consolidado: produto sem Utiliza (preço da casa 80, custo 60) junto de serviço com receita 100 e custo 40receita do produto = 0 (sem Utiliza), mas o custo dele conta: consolidado = 100/100 = 100% → na régua 100/120, exatamente no limite do vermelho = 🟡 AMARELO desde 12/10/2026 (antes: bloqueado). Com custo um centavo maior, cairia abaixo de 100% → vermelho, bloqueado. (Sem custos extras, prestadores nem repasse; se algum produto estivesse com custo 0, o consolidado seria ROXO e bloquearia.)
T15FT0,01sub "aplicação" Zerar=T contendo taxa de sala 73,99·F·T — caso Noripurum/Bradescosub = 0 (só a linha dele); taxa entra: 0,01 + 73,99 = 74,00 (+ demais itens não zerados). Até 23/09 a taxa ficava fora (receita real 16,03 × custo 24,74 = vermelho; hoje ≥ 90,02 × 24,74 = verde)
T16FT—fixo 100; sub (fixo 40, Zerar=F) contendo produto 30·T·T100 + 40 + 0 = 140 — o contexto de pacote fechado desce: produto zerado dentro do sub fica fora
T17TF—sub de preço fixo 80 (sem Pacote) contendo produto 20·F·T100 (80 + 20). Antes de 23/09 dava 80 (o preço fixo do sub "incluía" os itens)
T18orçamento: serviço fixo 100 sem Pacote; composição produto 50 × 1; usou 2100 + 2 × 50 = 200 (quantidade inteira). Antes de 23/09: 100 + 50 (só o excedente)
T19orçamento: produto sem Utiliza (preço da casa 80) na composiçãolinha a R$ 0,00; custo conta no Farol
T20linha ✅ × Farol: serviço soma itens, valor convertido 266,16, produto 3000·F·Tlinha ✅ = 266,16 (base, linha de procedimento do XML); Farol / linha do serviço em Farol › Itens = 3266,16
T21textos: serviço com nome de conversão vazio e código no convênio "X1"; cadastro "Consulta" / TUSS 10101012nome exibido = Consulta (vazio desce); código = X1 (nível 3)
T22produto sem valor unitário no convênio; política do convênio p/ o tipo: tabela interna Preço 1 = 50, Fator K 10; cadastro: fixo 60valor = 50 × 1,10 = 55,00 (nível 2 vale só para preço de produto)
T23FF100produto 50·T·T; taxa 30·T·TΣ = 100 + 50 + 30 = 180 — valor combinado sem Pacote não é pacote; o Zerar dos itens nem é lido
T24FT100produto 50·T·T; taxa 30·T·TΣ = 100 (combinado + Pacote + itens inclusos zerados = preço fechado)
T25FT100produto 50·T·T; taxa 30·F·TΣ = 100 + 30 = 130 (item sem Zerar dentro do pacote é cobrado à parte)
T26TF—"Ferinject aplicado" no Particular: produto 900·F·T + sub "aplicação" fixo 80 (Utiliza T)✅ = 0 (explicação "0,00 (sem preço próprio: itens cobrados à parte)" no tooltip da linha ✅); Σ = Farol = 980. Não é erro
✅ Itens 6 a 9 em produção (23–24/09/2026): (6) no orçamento, item sem Utiliza entra a R$ 0,00 (T19); (7) a linha ✅ do serviço mostra a base — a linha de procedimento do XML — e o Farol do serviço consolida tudo (T20); (8) itens sempre entram (T1, T12, T17, T18); (9) Zerar por item, sem cascata (T15, T16). Também em produção desde 24/09: textos e valores finais convertidos (T21, T22) e Farol › Itens por linha (seção 2.10). Regra vigente reforçada em 25/09: valor combinado não é pacote (T23–T25).
✅ Em produção desde 24/09: a exibição da linha Σ (T23–T26). A explicação do 0,00 aparece ao passar o mouse na linha ✅; um texto visível na própria linha chega no próximo ajuste.

9. Efeitos a jusante (para explicar ao usuário)

Agendamento/Autorização leem a composição e os valores na hora · Atendimento congela o valor de cadastro do serviço, o valor convertido do serviço e as conversões de cada produto/taxa · Pré Faturamento edita os congelados e pode recalcular em massa (exceto lote fechado) · XML = serviço × quantidade + taxas + produtos por Tabela 87 ANS (20/05, 19/00, 18), ignorando anulados e guias filhas.

Diagrama do caminho do valor: onde o sistema calcula e onde congela, do cadastro até a guia
Efeitos a jusante: cálculo na hora até o atendimento; a partir dali, valores congelados.

Navegação: Visão Geral · 1. Guia para a Clínica · 2. Guia do Implantador · Guia para IA (esta página) · Árvore de decisão do cadastro