Gerar relatório SmartView (código → artefato renderizando)
Visão geral
Um relatório SmartView tem duas camadas:
- Backend — Business Object TLPP (
IntegratedProvider): define os dados (getData) e o schema
de colunas/parâmetros (getSchema). É código, 100% gerável.
- Artefato no SmartView (Data Grid / Pivot / Report): consome o BO. Criado na plataforma
(via API REST + UI). O
.trp exportado é cifrado pelo servidor — nunca gerar offline.
Os BOs padrão da TOTVS podem vir vazios num ambiente sem dado/empresa configurada. Um BO
customizado próprio (com getData que lê uma tabela com dado OU devolve dados literais) renderiza
de forma confiável. Para validar a esteira, comece com um BO de dados literais.
Fluxo (executar em ordem)
1. Gerar o Business Object TLPP
Use scripts/generate_bo.py (Jinja2) a partir de um spec JSON (ver scripts/example_spec.json), OU
escreva o .tlpp direto seguindo assets/VENDASIA.tlpp (exemplo completo com dados literais).
Regras do padrão: namespace tbc.fsw.smartview.*, herda totvs.framework.treports.integratedprovider.IntegratedProvider,
decorator @totvsFrameworkTReportsIntegratedProvider, métodos new()/getData()/getSchema(),
getData faz self:oData:appendData(JsonObject) por linha + self:setHasNext(.F.),
getSchema declara self:addProperty(id,titulo,tipo,desc,campo). Sem BEGIN SEQUENCE. Ver
detalhes em references/recipe.md (seção "Padrão IntegratedProvider").
1.1 Escolha o padrão de getData pela complexidade (não reescreva SQL à toa)
self:oData:aliasToData("SED", oFilter) — framework lê o alias, pagina e devolve. Zero loop. Para 1 tabela simples sem JOIN. (aliasToData é método de oData, como o appendData.)
setQuery(cQuery) + setWhere(cWhere) + setOrder(...) com placeholders #QueryFields# / #QueryWhere# — framework itera e pagina. Para query customizada de 1 tabela.
- Manual (montar
cQuery, abrir alias, loop while + appendData(JsonObject)) — só quando há JOIN/cálculo/LGPD/aninhados. Implementar setPageSize, o skip (nPage-1)*pageSize e o setHasNext explicitamente.
oFilter oferece: hasFilter(), getSQLExpression() (WHERE pronto), hasFields()/getFields() (subset de colunas pedido), getParameters() (parâmetros nativos).
1.2 Schema: propriedades, parâmetros de filtro e lookup
addProperty(cId, cTitulo, cType, cDescricao, cRealName) — mesma assinatura da linha "id,titulo,tipo,desc,campo" acima (ex.: assets/VENDASIA.tlpp: addProperty("VENDEDOR","Vendedor","string","Nome do vendedor","VENDEDOR")). cType ∈ string|number|boolean|date|memo. O cRealName (nome real do campo) é essencial p/ o filtro funcionar; para campo manual, repetir o cId.
- Filtro de período / parâmetro nativo:
addParameter(cId, cDisplayName, cType, lIsMultiValue, cUrl, lHasOptions, lHasLookUp, cIdConsult[, cParamId, cDescription, lAllowNull, aDefaultValues]) — suporta lookup (F3), combo (SX1), multivalor e valor default (ex.: {totvs.framework.treports.date.dateToTimeStamp(Date())}). Recuperar no getData via oFilter:getParameters(). É o jeito certo de DATA_INI/DATA_FIM.
- Aninhados (
addNestedProperty/transformInNested): hierarquia pai-filho — não são filtráveis e não paginam (entregar completos). Para volume alto, prefira flat + agrupamento no design.
1.3 🔴 Datas — conversão OBRIGATÓRIA
Todo campo date no appendData precisa virar timestamp — e a função depende do tipo do valor: campo de data nativo ((cAlias)->CAMPO, tipo D) → totvs.framework.treports.date.dateToTimeStamp((cAlias)->CAMPO); valor já string (calculado/concatenado) → stringToTimeStamp(...). O padrão da fábrica usa um dispatcher varToTimeStamp que escolhe por valType. Gravar AllTrim/string crua (sem timestamp) → o valor chega nulo no SmartView. E desative MV_HVERAO (horário de verão) — ele distorce FwTimeStamp e gera datas erradas (ex.: "visão retroativa" trazendo títulos indevidos).
1.4 🔴 Query manual — qualifique os campos
Em getData com JOIN, qualifique todo campo (alias.CAMPO). Campo ambíguo (ex.: D3_EMISSAO em 2 tabelas) → connectors.native.failed-to-deserialize / internal-server-error. Trate também caractere especial (apóstrofo ') nos dados — quebra Pergunte/Profile.
2. Compilar no AppServer (advpls remoto — NÃO trava o RPO)
Use scripts/compile_bo.sh <fonte.tlpp> <environment> (default env CLIENTES_FSW_REST). Ele monta o
advpls.ini e chama o advpls (TDS-LS) conectando no AppServer rodando pela porta TCP de build.
appsrvlinux -compile LOCAL falha ("Failed to open repository" — RPO travado pelo appserver vivo).
Pré-requisitos e valores (porta, includes, credenciais) em references/recipe.md (seção "Compilação").
3. Registrar + verificar discovery
Reinicie o AppServer para registrar o IntegratedProvider (a REST fica ~60s indisponível após o
commit do build — esperar /<namespace>/ping → 401). Pré-requisitos de INI (confirmar as chaves exatas do seu ambiente em references/recipe.md): REST 2.0 com segurança habilitada (o discovery /.well-known/treports/ exige a REST autenticada) e a seção [REPORTSERVICE] configurada.
Confirme via API: GET /api/connectors/business-objects?q=<nome> (use scripts/smartview_client.py).
Ligue FwTraceLog=1 no INI para logar a integração.
4. Montar o artefato no SmartView
- Data Grid / Pivot: criar pela UI (Playwright) escolhendo o BO + campos — rebind via API não
reconfigura colunas. Validar render via API:
POST /api/resources/{data-grid|pivot-table}/<id>/viewer-data.
- Report (PDF): exige a lib nativa
libfontconfig1+libfreetype6 no container do smartview-agent
(DevExpress/SkiaSharp) — sem ela, designer-model dá 500. Instalar + reiniciar o agent. Layout do
Report monta-se no designer (arrastar o BO/campos para a banda Detail). Detalhes em references/recipe.md.
5. Verificar de forma independente (anti-falso-positivo)
SEMPRE confirme o render por um canal próprio (não só pelo agente Playwright): viewer-data via API
para Grid/Pivot; para Report, ler o screenshot do viewer. "Existir" ≠ "renderizar dado".
6. Da geração ao uso (chamar do Protheus)
- Amarração: registrar o recurso no Protheus via Configurador > Integração Smart View (grava a amarração no dicionário), senão o recurso não aparece no menu do módulo.
- Chamar: classe
totvs.framework.smartview.callSmartView():new(cId, cType) (report/pivot-table/data-grid) → setParam / executeSmartView / getError. Substitui callTReports (depreciada, LIB 20240226+).
- Permissões: o Grupo Default nega TODOS os BOs — após publicar, criar privilégio explícito por BO/usuário no Configurador; liberar também os lookups/combos dos parâmetros.
Falhas comuns (troubleshooting — casos reais de suporte)
| Erro / sintoma |
Causa |
Fix |
connectors.native.failed-to-deserialize / "conteúdo não condiz com o padrão esperado" |
Campo ambíguo no JOIN; ou apóstrofo (') no dado quebrando Pergunte/Profile |
Qualificar campos; limpar caractere especial; aplicar patch |
connectors.native.internal-server-error após incluir campos |
Ambiguidade de campo (ex.: D3_EMISSAO) |
Qualificar alias.campo |
| "Não foi possível encontrar o objeto de negócio no conector" |
Vínculo BO↔conector perdido (SaaS) |
Refazer conector; patches 12.1.2507.14 / 2511.8 / 2603.2 (fix 2607) |
| "Usuário não possui acesso ao objeto de negócio" |
Grupo Default nega tudo; [REPORTSERVICE] no INI |
Criar privilégio por BO; conferir [REPORTSERVICE] |
| "400 BadRequest" / conectores/relatórios não abrem / "Falha ao recuperar a estrutura" |
URL externa do SmartView não liberada nas máquinas dos usuários |
Infra libera a URL; relatório apontando servidor.local → usar IP |
| "Servidor não está respondendo" (grande volume, >1h) |
Paginação/buffer/timeout |
setPageSize + setHasNext corretos; filtros de período curtos |
| Datas / "visão retroativa" divergentes |
MV_HVERAO distorce FwTimeStamp |
Desativar MV_HVERAO |
| Erros intermitentes de estrutura/profile |
Profile do relatório corrompido |
Apagar/recriar o profile (não precisa dropar tabelas) |
Personalização de campos em BO nativo (via Configurador) exige Porta Multiprotocolo + Interface PO UI ativas.
Regras de modelo (TBC)
- Tarefas com Playwright (montar artefato na UI, screenshots) → SEMPRE
model: sonnet.
- Geração de código/scaffolding →
sonnet (haiku só em deploy/compilação).
Recursos
scripts/generate_bo.py + scripts/templates/integratedprovider.tlpp.j2 — gerador do BO.
scripts/smartview_client.py — cliente da API SmartView (auth Basic→Bearer, find-BO, viewer-data, import/rebind/export).
scripts/compile_bo.sh — compila o .tlpp remoto via advpls.
assets/VENDASIA.tlpp — BO de exemplo (dados literais) que renderiza.
references/recipe.md — receita detalhada do ambiente (portas, credenciais por env, gotchas, endpoints).
1---2name: smartview-relatorio3description: Gera um relatório TOTVS SmartView de ponta a ponta, do código ao artefato renderizando dados. A partir de uma especificação (tabelas/campos Protheus, query SQL ou dados literais), gera o Business Object TLPP (IntegratedProvider), compila no AppServer via advpls (TDS CLI remoto), registra na discovery e monta o artefato no SmartView (Data Grid, Tabela Dinamica/Pivot ou Report). Esta skill deve ser usada quando o usuario pedir para criar ou gerar um relatorio SmartView, fazer um Business Object para o SmartView, publicar um IntegratedProvider, gerar Data Grid, Pivot ou Report no SmartView, ou desenvolver relatorios SmartView com agentes de IA. Cobre um ambiente SmartView (TReports) self-hosted ligado a um AppServer Protheus.4---56# Gerar relatório SmartView (código → artefato renderizando)78## Visão geral910Um relatório SmartView tem **duas camadas**:111. **Backend — Business Object TLPP** (`IntegratedProvider`): define os dados (`getData`) e o schema12 de colunas/parâmetros (`getSchema`). É código, 100% gerável.132. **Artefato no SmartView** (Data Grid / Pivot / Report): consome o BO. Criado na plataforma14 (via API REST + UI). O `.trp` exportado é cifrado pelo servidor — **nunca gerar offline**.1516Os BOs **padrão** da TOTVS podem vir vazios num ambiente sem dado/empresa configurada. Um **BO17customizado próprio** (com `getData` que lê uma tabela com dado OU devolve dados literais) renderiza18de forma confiável. Para validar a esteira, comece com um BO de dados literais.1920## Fluxo (executar em ordem)2122### 1. Gerar o Business Object TLPP23Use `scripts/generate_bo.py` (Jinja2) a partir de um spec JSON (ver `scripts/example_spec.json`), OU24escreva o `.tlpp` direto seguindo `assets/VENDASIA.tlpp` (exemplo completo com dados literais).25Regras do padrão: namespace `tbc.fsw.smartview.*`, herda `totvs.framework.treports.integratedprovider.IntegratedProvider`,26decorator `@totvsFrameworkTReportsIntegratedProvider`, métodos `new()/getData()/getSchema()`,27`getData` faz `self:oData:appendData(JsonObject)` por linha + `self:setHasNext(.F.)`,28`getSchema` declara `self:addProperty(id,titulo,tipo,desc,campo)`. Sem `BEGIN SEQUENCE`. Ver29detalhes em `references/recipe.md` (seção "Padrão IntegratedProvider").3031#### 1.1 Escolha o padrão de `getData` pela complexidade (não reescreva SQL à toa)32- **`self:oData:aliasToData("SED", oFilter)`** — framework lê o alias, pagina e devolve. Zero loop. Para 1 tabela simples sem JOIN. (`aliasToData` é método de `oData`, como o `appendData`.)33- **`setQuery(cQuery)` + `setWhere(cWhere)` + `setOrder(...)`** com placeholders `#QueryFields#` / `#QueryWhere#` — framework itera e pagina. Para query customizada de 1 tabela.34- **Manual** (montar `cQuery`, abrir alias, loop `while` + `appendData(JsonObject)`) — **só** quando há JOIN/cálculo/LGPD/aninhados. Implementar `setPageSize`, o skip `(nPage-1)*pageSize` e o `setHasNext` explicitamente.35- `oFilter` oferece: `hasFilter()`, `getSQLExpression()` (WHERE pronto), `hasFields()`/`getFields()` (subset de colunas pedido), `getParameters()` (parâmetros nativos).3637#### 1.2 Schema: propriedades, parâmetros de filtro e lookup38- `addProperty(cId, cTitulo, cType, cDescricao, cRealName)` — mesma assinatura da linha "id,titulo,tipo,desc,campo" acima (ex.: `assets/VENDASIA.tlpp`: `addProperty("VENDEDOR","Vendedor","string","Nome do vendedor","VENDEDOR")`). `cType` ∈ `string|number|boolean|date|memo`. O **cRealName** (nome real do campo) é essencial p/ o filtro funcionar; para campo manual, repetir o cId.39- **Filtro de período / parâmetro nativo:** `addParameter(cId, cDisplayName, cType, lIsMultiValue, cUrl, lHasOptions, lHasLookUp, cIdConsult[, cParamId, cDescription, lAllowNull, aDefaultValues])` — suporta lookup (F3), combo (SX1), multivalor e valor default (ex.: `{totvs.framework.treports.date.dateToTimeStamp(Date())}`). Recuperar no getData via `oFilter:getParameters()`. É o jeito certo de DATA_INI/DATA_FIM.40- **Aninhados** (`addNestedProperty`/`transformInNested`): hierarquia pai-filho — **não são filtráveis e não paginam** (entregar completos). Para volume alto, prefira flat + agrupamento no design.4142#### 1.3 🔴 Datas — conversão OBRIGATÓRIA43Todo campo `date` no `appendData` precisa virar timestamp — e a função depende do **tipo** do valor: campo de data nativo (`(cAlias)->CAMPO`, tipo `D`) → `totvs.framework.treports.date.dateToTimeStamp((cAlias)->CAMPO)`; valor já string (calculado/concatenado) → `stringToTimeStamp(...)`. O padrão da fábrica usa um dispatcher `varToTimeStamp` que escolhe por `valType`. Gravar `AllTrim`/string crua (sem timestamp) → o valor chega **nulo** no SmartView. E **desative `MV_HVERAO`** (horário de verão) — ele distorce `FwTimeStamp` e gera datas erradas (ex.: "visão retroativa" trazendo títulos indevidos).4445#### 1.4 🔴 Query manual — qualifique os campos46Em getData com JOIN, **qualifique todo campo** (`alias.CAMPO`). Campo ambíguo (ex.: `D3_EMISSAO` em 2 tabelas) → `connectors.native.failed-to-deserialize` / `internal-server-error`. Trate também caractere especial (apóstrofo `'`) nos dados — quebra Pergunte/Profile.4748### 2. Compilar no AppServer (advpls remoto — NÃO trava o RPO)49Use `scripts/compile_bo.sh <fonte.tlpp> <environment>` (default env `CLIENTES_FSW_REST`). Ele monta o50`advpls.ini` e chama o `advpls` (TDS-LS) conectando no AppServer **rodando** pela porta TCP de build.51`appsrvlinux -compile` LOCAL falha ("Failed to open repository" — RPO travado pelo appserver vivo).52Pré-requisitos e valores (porta, includes, credenciais) em `references/recipe.md` (seção "Compilação").5354### 3. Registrar + verificar discovery55Reinicie o AppServer para registrar o IntegratedProvider (a REST fica ~60s indisponível após o56commit do build — esperar `/<namespace>/ping` → 401). **Pré-requisitos de INI** (confirmar as chaves exatas do seu ambiente em `references/recipe.md`): REST 2.0 com **segurança habilitada** (o discovery `/.well-known/treports/` exige a REST autenticada) e a seção `[REPORTSERVICE]` configurada.57Confirme via API: `GET /api/connectors/business-objects?q=<nome>` (use `scripts/smartview_client.py`).58Ligue `FwTraceLog=1` no INI para logar a integração.5960### 4. Montar o artefato no SmartView61- **Data Grid / Pivot**: criar pela UI (Playwright) escolhendo o BO + campos — rebind via API **não**62 reconfigura colunas. Validar render via API: `POST /api/resources/{data-grid|pivot-table}/<id>/viewer-data`.63- **Report (PDF)**: exige a lib nativa **`libfontconfig1`+`libfreetype6`** no container do smartview-agent64 (DevExpress/SkiaSharp) — sem ela, `designer-model` dá 500. Instalar + reiniciar o agent. Layout do65 Report monta-se no designer (arrastar o BO/campos para a banda Detail). Detalhes em `references/recipe.md`.6667### 5. Verificar de forma independente (anti-falso-positivo)68SEMPRE confirme o render por um canal próprio (não só pelo agente Playwright): `viewer-data` via API69para Grid/Pivot; para Report, ler o screenshot do viewer. "Existir" ≠ "renderizar dado".7071### 6. Da geração ao uso (chamar do Protheus)72- **Amarração:** registrar o recurso no Protheus via Configurador > **Integração Smart View** (grava a amarração no dicionário), senão o recurso não aparece no menu do módulo.73- **Chamar:** classe `totvs.framework.smartview.callSmartView():new(cId, cType)` (`report`/`pivot-table`/`data-grid`) → `setParam` / `executeSmartView` / `getError`. Substitui `callTReports` (depreciada, LIB 20240226+).74- **Permissões:** o **Grupo Default nega TODOS os BOs** — após publicar, criar privilégio explícito por BO/usuário no Configurador; liberar também os lookups/combos dos parâmetros.7576## Falhas comuns (troubleshooting — casos reais de suporte)77| Erro / sintoma | Causa | Fix |78|---|---|---|79| `connectors.native.failed-to-deserialize` / "conteúdo não condiz com o padrão esperado" | Campo ambíguo no JOIN; ou apóstrofo (`'`) no dado quebrando Pergunte/Profile | Qualificar campos; limpar caractere especial; aplicar patch |80| `connectors.native.internal-server-error` após incluir campos | Ambiguidade de campo (ex.: `D3_EMISSAO`) | Qualificar `alias.campo` |81| "Não foi possível encontrar o objeto de negócio no conector" | Vínculo BO↔conector perdido (SaaS) | Refazer conector; patches 12.1.2507.14 / 2511.8 / 2603.2 (fix 2607) |82| "Usuário não possui acesso ao objeto de negócio" | Grupo Default nega tudo; `[REPORTSERVICE]` no INI | Criar privilégio por BO; conferir `[REPORTSERVICE]` |83| "400 BadRequest" / conectores/relatórios não abrem / "Falha ao recuperar a estrutura" | URL externa do SmartView não liberada nas máquinas dos usuários | Infra libera a URL; relatório apontando `servidor.local` → usar IP |84| "Servidor não está respondendo" (grande volume, >1h) | Paginação/buffer/timeout | `setPageSize` + `setHasNext` corretos; filtros de período curtos |85| Datas / "visão retroativa" divergentes | `MV_HVERAO` distorce `FwTimeStamp` | Desativar `MV_HVERAO` |86| Erros intermitentes de estrutura/profile | Profile do relatório corrompido | Apagar/recriar o profile (não precisa dropar tabelas) |8788> Personalização de campos em BO nativo (via Configurador) exige **Porta Multiprotocolo + Interface PO UI** ativas.8990## Regras de modelo (TBC)91- Tarefas com **Playwright** (montar artefato na UI, screenshots) → SEMPRE `model: sonnet`.92- Geração de código/scaffolding → `sonnet` (haiku só em deploy/compilação).9394## Recursos95- `scripts/generate_bo.py` + `scripts/templates/integratedprovider.tlpp.j2` — gerador do BO.96- `scripts/smartview_client.py` — cliente da API SmartView (auth Basic→Bearer, find-BO, viewer-data, import/rebind/export).97- `scripts/compile_bo.sh` — compila o `.tlpp` remoto via advpls.98- `assets/VENDASIA.tlpp` — BO de exemplo (dados literais) que renderiza.99- `references/recipe.md` — receita detalhada do ambiente (portas, credenciais por env, gotchas, endpoints).