Etapa 04 — Cadastro de veículo e frota¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-06-15
Estende o parsing da etapa 01 e o UPSERT diff-aware da etapa 02 com as colunas veiculares e uma regra de preservação específica.
1. Contexto e escopo¶
As planilhas RESULTADO_TRANSPORTE_* recentes trazem, além dos campos históricos,
frota (própria vs terceiros) e identificação do caminhão (marca, modelo,
anos). O processamento mapeia essas colunas e as persiste preservando correções
manuais de cadastro feitas direto no banco.
Dentro do escopo: mapeamento das colunas novas; parse do ano AAAA/AAAA;
backfill do cadastro veicular nas linhas existentes; defesa contra entrada
inválida; preservação no reprocessamento.
Fora do escopo: uma entidade de veículo normalizada — hoje os dados veiculares
vivem desnormalizados nas colunas dos próprios fatos
bi_faturamento/bi_movimento, chaveados por placa (não há tabela mestre de
frota persistente).
2. Modelo de dados¶
Cinco colunas adicionadas em ambos os fatos (V3__bi_veiculo_frota.sql):
erDiagram
bi_faturamento {
varchar tipo_frota "aba 20 col 33"
varchar marca_veiculo "col 34"
varchar modelo_veiculo "col 35"
smallint ano_construcao "col 36, esq. da barra"
smallint ano_modelo "col 36, dir. da barra"
}
bi_movimento {
varchar tipo_frota "aba 30 col 27"
varchar marca_veiculo "col 28"
varchar modelo_veiculo "col 29"
smallint ano_construcao "col 30, esq."
smallint ano_modelo "col 30, dir."
}
Tipos: tipo_frota VARCHAR(20), marca_veiculo/modelo_veiculo VARCHAR(80),
ano_construcao/ano_modelo SMALLINT (todas nullable). Mapeamento 0-based:
aba 20 → 33/34/35/36; aba 30 → 27/28/29/30. O ano é uma string
AAAA/AAAA (ex.: 2006/2007): AnosVeiculoParser grava os 4 dígitos à esquerda
em ano_construcao e os à direita em ano_modelo; formato inválido → ambos null.
O backfill do V10 gravava um relatório de não-matched numa tabela
xls_veiculo_backfill_relatorio— one-time, lida por nada em runtime, removida em V15. O backfill em si (UPDATE nosbi_*) permanece.
Defesa veicular (6 colunas em xls_processamento, V11): defesa_marca_ausente_qtd,
defesa_modelo_ausente_qtd, defesa_ano_invalido_qtd, defesa_tipo_frota_ausente_qtd,
defesa_placa_malformada_qtd (INTEGER) + xls_legado (BOOLEAN).
3. Fluxos principais¶
- Mapeamento + defesa: ao ler cada linha das abas 20/30, o
ExcelProcessorregistra as ocorrências de marca/modelo/ano/tipo_frota ausentes e placa malformada nas contagensdefesa_*_qtd— sem bloquear o lote (entrada ruim vira métrica + evento no Bugsink, não erro). - Backfill (
V10__backfill_veiculos.sql): a partir de um mestre veicular (~3100 placas, planilha20260525-veiculos-final.xlsxcarregada numa TEMP TABLEON COMMIT DROP), faz UPDATE-join idempotente preenchendo as colunas veiculares nas linhas existentes debi_faturamento/bi_movimento, sem sobrescrever valores já gravados não-vazios. (A migration está congelada; o gerador one-shot que a produziu foi removido — ver CHANGELOG.) - Preservação (decisão 0012): as cinco colunas estão em
ColunasConteudo.PRESERVAR_SE_VAZIO_NA_ENTRADA. No UPSERT, entrada "vazia" (NULL/''/0/ placeholders'SEM MARCA'/'SEM MODELO') não sobrescreve o valor gravado, viaCOALESCE(NULLIF(EXCLUDED.col, <sentinela>), <tabela>.col)— e também não dispara UPDATE (sem churn dexmin/PowerSync, consistente com a etapa 02). Correções de cadastro feitas direto no banco sobrevivem a reprocessamentos; em troca, esses campos só são limpos por script no banco, nunca por upload.
4. Decisões¶
| Nº | Decisão |
|---|---|
| 0012 | Preservação de cadastro de veículo no UPSERT |
Relacionado: o mecanismo de UPSERT diff-aware é o da etapa 02.
5. Riscos¶
- Cliente muda o layout das colunas (índices) → o parse pega célula errada; mitigado por testes com fixtures reais por período e pelas métricas de defesa.
- Upload com colunas vazias sobrescrevendo cadastro bom → resolvido pela preservação (decisão 0012).