# Sankhya — o mapa da casa
> QUANDO LER: **antes da sua primeira consulta ao Sankhya.** É o índice do banco; o detalhe está nos cadernos irmãos.

Sem este mapa você gasta minutos "descobrindo" o banco tabela por tabela — e quem
espera é a pessoa. Consulte pelo `mcp__nix__sankhya` (só leitura).


---

## ⛔ ANTES DE QUALQUER CONSULTA — "O QUE EU ALCANÇO"

O Nix roda no login da própria pessoa. O SQL Server **esconde dela** o que não é dela — e não avisa: a consulta simplesmente volta **vazia, ou em branco**. Branco parece zero. É assim que o Nix mente sem querer: diz *"não vendemos nada"* quando o certo era dizer *"isso não está no seu alcance"*.

### 1. A consulta que descobre o próprio alcance (rode-a primeiro, sempre)

**Vá direto em:** `seg.BLOQUEIO` — é a tabela que o banco usa pra decidir o que cada login enxerga; cruzo com `sankhya.TSIEMP` só pra pegar o nome · **tempo medido (na credencial dele): 0,2 s**

```sql
WITH dados AS (
  SELECT TRY_CAST(LTRIM(S.value) AS INT) AS CODEMP,
         ISNULL(E.NOMEFANTASIA, '(sem cadastro na TSIEMP)') AS EMPRESA
  FROM seg.BLOQUEIO B
  CROSS APPLY STRING_SPLIT(B.VALOR, ',') S
  LEFT JOIN sankhya.TSIEMP E ON E.CODEMP = TRY_CAST(LTRIM(S.value) AS INT)
  WHERE B.USUARIO = SUSER_SNAME()
    AND B.DIMENSAO = 'CODEMP'
    AND B.ATIVO = 1
)
SELECT * FROM dados ORDER BY CODEMP
```

**Conferido (na credencial do u001 — concreto), 0,17 s, 14 empresas:** 1 TOPMIX CONCRETO SJL · 2 TOPMIX CONCRETO 040 · 3 TOPMIX CONCRETO NIQUINI · 4 TOPMIX CONCRETO FILIAL · 101 SAROO · 301 GALVAO E MONTEIRO · 302 (sem cadastro na TSIEMP) · 601, 602, 603 BETMIX CONCRETO · 701 SUPERCONCRETO APIO, 702 SUPERCONCRETO LOTE, 703 SUPERCONCRETO SJL, 704 SUPERCONCRETO BETIM. **Sem a São José.**

**Conferido (na credencial do u002 — cimento), 0,16 s, 2 empresas:** 201 e 202 SAO JOSE DISTRIBUIDORA DE CIMENTO. **Nenhuma empresa de concreto.**

⚠️ **Não descubra o alcance olhando o dado.** Testado em junho/2026: `SELECT DISTINCT FILIAL FROM sankhya.AD_VGF_VENDAS` rodado pelo u002 (cimento) devolve **1, 2, 201, 601, 602, 603, 701, 704** — sete filiais de concreto que **não são dele**. O motivo: só as linhas de CONCRETO/ADICIONAIS/ACRÉSCIMOS passam pela trava; as de **BOMBAS** e **CARTÃO** não. No mês, o u002 recebeu **1.136 linhas de BOMBAS** de filiais alheias (R$ 2.471.702,80 — só a filial 2 são 488 linhas e R$ 1.297.895,90) e **881 linhas de CARTÃO** das filiais 1, 601 e 701. Alcance se pergunta na `seg.BLOQUEIO`, não no faturamento.

**Plano B (se a `seg.BLOQUEIO` não responder):** `sankhya.TGFCAB` é filtrada de verdade pelo login — **0,4 s (u001) · 0,3 s (u002)**

```sql
WITH dados AS (
  SELECT DISTINCT CODEMP
  FROM sankhya.TGFCAB
  WHERE DTNEG >= DATEADD(DAY, -90, GETDATE())
)
SELECT * FROM dados ORDER BY CODEMP
```

**Conferido (últimos 90 dias):** u001 → 1, 2, 3, 4, 101, 301, 601, 602, 603, 701, 702, 703, 704 (a 302 não aparece: existe na liberação, não teve movimento) · u002 → 201, 202.

### 2. A regra de ouro (três linhas)

1. **Voltou vazio não quer dizer que é zero** — quer dizer que pode não ser seu.
2. **Antes de dizer "não teve venda", confira se você ALCANÇA aquela empresa** (a consulta acima, 0,2 s).
3. **Se não alcança, diga isso com todas as letras** — a pessoa sabe pedir a liberação; ela não sabe adivinhar um zero falso.

**As duas armadilhas, medidas na credencial deles:**
- u002 (cimento) pedindo m³ de concreto de junho/2026 na `sankhya.AD_VGF_VENDAS`: volta **uma linha com M3 e FATURAMENTO em branco** (0,9 s). Parece "vendemos zero". É "não é seu". Na mesma consulta, o u001 vê **64.577 m³ e R$ 30.768.781,34** (0,6 s).
- u001 (concreto) contando notas da São José (201/202) em junho/2026 na `sankhya.TGFCAB`: volta **0 notas** (0,5 s). A São José faturou **2.414 notas** nesse mês.

### 3. A frase pronta (o Nix fala assim, sem jargão e sem culpar ninguém)

> "Não consigo te responder isso: essa empresa está fora do seu acesso ao sistema, então o que eu vejo aqui vem em branco — e branco não é zero, é falta de permissão.
> Seu acesso hoje cobre as empresas <lista do alcance>. Se precisar dessa outra, é só pedir a liberação que eu volto com o número."

### 4. Onde está a sua base

| Se você é de… | Suas empresas | A sua base é | ⛔ Não use |
|---|---|---|---|
| **Concreto** (u001 — TopMix, BetMix, SuperConcreto) | 1, 2, 3, 4, 101, 301, 302, 601, 602, 603, 701, 702, 703, 704 | `sankhya.AD_VGF_VENDAS` — m³, faturamento, bombas, adicionais (varredura do mês inteiro: 3 a 5 s; filtrando `TIPODESERVICO = 'CONCRETO'`: 0,6 s) | — (a `CND_VGF_AD_VENDAS` **abre e é a rápida**, 0,2 s; mas **não filtra dono**: ponha `CODEMPALIANCA IN (1,601,701)` no `WHERE`) |
| **Cimento** (u002 — São José) | 201, 202 | `sankhya.TGFCAB` + `sankhya.TGFITE` (nota fiscal: `TIPMOV = 'V'`, `STATUSNOTA = 'L'`) — **0,6 s medido** | a `AD_VGF_VENDAS` **não serve pra cimento** (só devolve BOMBAS/CARTÃO). A `sankhya.AD_CND_VGFFAT` **abre e é a rápida** (0,04 s) — mas **não filtra dono**: ponha `CODEMP IN (201,202,203,204)` no `WHERE` |

**A base do cimento, conferida (junho/2026, na credencial do u002) — 0,6 s:**

```sql
WITH dados AS (
  SELECT C.CODEMP,
         COUNT(DISTINCT C.NUNOTA) AS NOTAS,
         SUM(I.QTDNEG) AS UNIDADES,
         SUM(I.VLRTOT) AS FATURAMENTO
  FROM sankhya.TGFCAB C
  JOIN sankhya.TGFITE I ON I.NUNOTA = C.NUNOTA
  WHERE C.TIPMOV = 'V'
    AND C.STATUSNOTA = 'L'
    AND C.DTNEG >= '20260601'
    AND C.DTNEG < '20260701'
  GROUP BY C.CODEMP
)
SELECT * FROM dados ORDER BY CODEMP
```

**Conferido (junho/2026, na credencial do u002):** empresa 201 → **2.389 notas**, 182.447 unidades, **R$ 5.363.684,22** · empresa 202 → **25 notas**, 687 unidades, **R$ 21.394,35**. Total: 2.414 notas.

---

## As quatro regras que quebram tudo se você errar

1. **É SQL Server 2017**, não Oracle: `SELECT TOP 10`, nunca `ROWNUM`; `GETDATE()`, não `SYSDATE`.
2. **Toda tabela mora no schema `sankhya.`** — `FROM sankhya.TGFCAB`, nunca `FROM TGFCAB`.
3. **Data em literal vai SEM hífen**: `'20260712'`. O servidor está em português — com hífen ele lê `AAAA-DD-MM`, o mês vira dia e `'2026-12-31'` morre com "data inválida".
4. **Nunca invente nome de tabela/campo.** O banco tem catálogo em português (abaixo). Uma consulta ao catálogo economiza vinte tentativas.

Você **só lê** o banco. Para LANÇAR no ERP é a API (`sankhya_propoe` → a pessoa repete o código → `sankhya_confirma`).

## O catálogo — como descobrir um campo sem adivinhar

São ~4.600 tabelas. **Não fique dando `SELECT TOP 5 *` em tabela por tabela.**

| Catálogo | O que tem |
|---|---|
| `sankhya.TDDTAB` | as tabelas (`NOMETAB`, `DESCRTAB` em português) |
| `sankhya.TDDCAM` | os campos (`NOMETAB`, `NOMECAMPO`, `DESCRCAMPO`, tipo, tamanho) |
| `sankhya.TDDOPC` | **os valores válidos** de um campo de lista (liga por `NUCAMPO`) |

Receita pronta pra descobrir o que significa um código (ex.: status `'F'`):

```sql
SELECT c.NOMECAMPO, c.DESCRCAMPO, o.VALOR, o.OPCAO
FROM sankhya.TDDCAM c
JOIN sankhya.TDDOPC o ON o.NUCAMPO = c.NUCAMPO
WHERE c.NOMETAB = 'BH_CCTREM' AND c.NOMECAMPO = 'BH_CCTSTATUSREM';
```

Estrutura física (view? tabela? colunas?) sai de `sys.objects` / `sys.columns`.
**Saber se é VIEW ou TABELA importa muito** — veja "o atalho rápido", abaixo.

## O negócio, em cinco linhas

O grupo **vende CONCRETO usinado** (em **m³**) — nunca chame de "pedra" ou "brita" — e
**cimento** pela distribuidora São José (em **sacos**). São **5 alianças** (uma aliança é
uma operação comercial; cada uma tem vários CNPJs/CODEMP):

| Aliança | Quem é | Vende |
|---|---|---|
| `1` | **TopMix** (a principal; a transportadora **Saroo** é dela) | concreto |
| `601` | **BetMix** | concreto |
| `701` | **SuperConcreto** | concreto |
| `201` | **São José** — distribuidora | cimento (CODEMP 201 e 204) |
| `401` | Outras (só holdings) | nada — fora de análise operacional |

- "As três alianças" / "as concreteiras" = **1, 601, 701**.
- **Nunca some a empresa "consolidada" com as filiais** — as consolidadas (CODEMP terminado em `99`: 99, 299, 699, 799, 999) repetem os dados e dobram o número.
- A aliança da empresa está em `TSIEMP.AD_CODEMPALIANCA`.
- **Usina** = planta que produz concreto (`AD_CCTUSI`, 8 ativas). **Ponto de carga (PC)** = a boca onde o caminhão carrega, dentro da usina (`BH_CCTPC`).
- Uma concreteira **pode produzir na usina da outra**. Quem vendeu emite a nota; a dona da usina recebe pelo uso. Por isso "usina onde carregou" ≠ "aliança que faturou" (`ALIUSINA` vs `CODEMPALIANCA` na base de vendas).

## O ciclo do concreto — por que "pedido" não é "venda"

1. **Pedido** (`BH_CCTCAB`, PK `NUPEDIDO`) — o cliente agenda obra, volume, traço, dia e hora. É a **única movimentação do grupo que não vive em TGFCAB**.
2. **Remessa** (`BH_CCTREM`) — cada **caminhão carregado que sai** é uma remessa (~7 a 8 m³ por betoneira). Um pedido de 30 m³ vira ~4 remessas.
3. **Nota** (`TGFCAB`) — **cada remessa vira uma nota**. É a remessa que fatura, não o pedido.

Consequência: **pedido é agenda** (pode ser cancelado/mudado no dia); **entrega é faturamento**.
Para "o que entregamos" → vendas. Para "o que vamos entregar amanhã" → pedidos.
O preço não nasce na nota: vem do **contrato da obra** (`BH_CCTCON`), que fixa o preço por m³ de cada traço.

## As tabelas que respondem quase tudo

| Objeto | O que é | Chave |
|---|---|---|
| `sankhya.CND_VGF_AD_VENDAS` | **⭐ A BASE DE VENDA DE CONCRETO.** Tabela (rápida), 1 linha por entrega/serviço, 123 colunas. **Comece por aqui** — ver `sankhya-vendas.md` | — |
| `sankhya.AD_VGF_VENDAS` | a **view ao vivo** que gera a de cima. Use só quando precisar de "agora" | — |
| `sankhya.AD_CND_VGFFAT` | **faturamento da São José** (cimento) | — |
| `sankhya.TGFCAB` | cabeçalho de toda movimentação (nota, devolução…). O tipo é o `CODTIPOPER` (TOP) | `NUNOTA` |
| `sankhya.TGFITE` | itens da nota (`QTDNEG` = quantidade) | `NUNOTA`+`SEQUENCIA` |
| `sankhya.TGFFIN` | **financeiro** — uma linha por parcela. `RECDESP` = 1 receita / -1 despesa | `NUFIN` |
| `sankhya.TGFPAR` | parceiros (cliente, fornecedor, transportadora — as flags acumulam) | `CODPARC` |
| `sankhya.TGFPRO` | produtos (o traço é um produto) | `CODPROD` |
| `sankhya.TGFTOP` | Tipos de Operação — é a TOP que separa venda de devolução | `CODTIPOPER` |
| `sankhya.TSIEMP` | empresas/filiais. Aliança em `AD_CODEMPALIANCA` | `CODEMP` |
| `sankhya.TSICUS` | centros de resultado (o 1º dígito indica a aliança: 1→1, 6→601, 7→701, 3→201, 9→universal) | `CODCENCUS` |
| `sankhya.BH_CCTCAB` | **pedido de concreto** (a programação de entrega) | `NUPEDIDO` |
| `sankhya.BH_CCTITE` | itens do pedido (`QTDNEG`, `DTPREVISTA`, `HRPREVISTA`) | `NUPEDIDO`+`SEQ` |
| `sankhya.BH_CCTREM` | **remessas** (view) — cada caminhão que saiu, com status | — |
| `sankhya.BH_CCTOBR` | **obras** (`CODOBRA`, `NOMEOBRA`, cliente) | `CODOBRA` |
| `sankhya.BH_CCTCON` | **contratos** — o preço por m³ de cada traço, por obra | `NUMCONTRATO` |
| `sankhya.AD_FECHAMENTO_GERAL_DADOS_TOPMIX` | **o resultado gerencial do mês** (faturamento, MCC, custos, despesas) por aliança | `NOME`+`MESANO`+`CODEMPALIANCA` |

## O atalho rápido: tabela CND_ vs view AD_ (leia isto antes de reclamar de lentidão)

O Sankhya mantém **cópias físicas** ("snapshots") das views pesadas, com prefixo `CND_`.
Elas são **a mesma coisa, muito mais rápida**:

| Você quer | Use | Custo medido |
|---|---|---|
| Histórico, mês fechado, ranking, comparativo | **`CND_VGF_AD_VENDAS`** (tabela) | **0,55 s** |
| O número **de agora** (últimas horas de hoje) | `AD_VGF_VENDAS` (view) | 2 a 3 s |

**A pegadinha:** a `CND_` é recarregada **de hora em hora** (procedure `AD_ATUAL_CND_VGF_VENDAS_HORA`, que apaga e reinsere os **últimos 5 dias**) + um rebuild completo de madrugada. Ou seja: **pra "hoje", a CND pode estar até 1 hora atrasada.** Medido em 13/07/2026 às 12h: CND dizia **1.167,5 m³**, a view ao vivo dizia **1.222,0 m³**. Os dois estão "certos" — um é foto, o outro é filme.

> Regra: **período fechado → CND (rápida). "Agora/hoje" → view ao vivo.** E, se der diferença entre dois números seus, é quase sempre isto. Diga qual fonte você usou.

## Como escrever a consulta

- **Formato:** `WITH dados AS ( ... ) SELECT * FROM dados ORDER BY ...`. O resultado final mora sempre num bloco chamado `dados`, e a última linha é só `SELECT * FROM dados`. Assim a pessoa fatia por data/usina/cliente mexendo numa linha só. O `ORDER BY` vai na linha final, nunca dentro do CTE.
- **A menor consulta que resolve.** Sem junção, coluna ou bloco que a pergunta não pediu.
- **Toda tabela grande exige filtro de data.** Sem ele a consulta demora minutos. Se a pergunta não tem período, escolha um (mês corrente) e **diga qual escolheu**.
- **`COUNT(*)` mente sobre o custo de uma view** — o otimizador poda colunas e junções que a contagem não usa. Pra medir de verdade: `SELECT TOP 100 * ... WHERE <data>`.
- **Valide num caso conhecido** antes de generalizar. Ex.: o faturamento de concreto que você somar tem de bater com a linha `FATURAMENTO_CONCRETO` do fechamento gerencial (bate ao centavo — confira em `sankhya-financeiro.md`).
- Número que você não conferiu não é fato. Diga de onde veio.

---

---

## O que a casa aprendeu (com o uso)

*Sai do uso de verdade: o que um Nix descobriu sobre a empresa, conferido e reescrito, vale pra todos.*

- **Ferramenta `sankhya` corta resultados em 500 linhas**. Para bases grandes, divida a consulta em blocos de no máximo 400 linhas usando `OFFSET n ROWS FETCH NEXT 400 ROWS ONLY` com `ORDER BY` determinístico (por coluna de texto, não por medida) para evitar pulos ou repetições de linhas entre blocos.

## O que eu aprendi (meu caderno)

*Aqui vai o que EU descobrir trabalhando com esta pessoa — a view que serve pro que ela
pergunta toda semana, o código da usina dela, o filtro que ela sempre quer. Uma linha por coisa.*
