Skip to content

Definição do relatório

Todo relatório Sulfite é um JSON com esta estrutura:

json
{
  "reportId": "string",
  "reportName": "string",
  "version": "string",
  "pageSettings": { ... },
  "dataSources": [ ... ],
  "bands": [ ... ]
}

Campos

CampoTipoObrigatórioDescrição
reportIdstringSimIdentificador único do relatório
reportNamestringSimNome legível
versionstringNãoVersão do relatório (ex: "1.0")
pageSettingsobjectSimFormato da página, margens, orientação
dataSourcesarraySimFontes de dados esperadas
bandsarraySimFaixas horizontais que compõem o layout
parametersarrayNãoParâmetros interativos preenchidos antes da impressão (ver Filtros)
scriptsarrayNãoScripts executados em hooks do ciclo de vida (afterQuery, beforeRender)
metadataobjectNãoDados extras livres
processingModestringNão"strict" (padrão) ou "resilient"

pageSettings

json
{
  "format": "A4",
  "width": 595.28,
  "height": 841.89,
  "unit": "pt",
  "orientation": "portrait",
  "margins": {
    "left": 40,
    "right": 40,
    "top": 40,
    "bottom": 40
  }
}
CampoTipoPadrãoDescrição
formatstring"A4"Nome do formato (A3, A4, A5, Carta, Legal)
widthdouble595.28Largura em pontos
heightdouble841.89Altura em pontos
unitstring"pt"Unidade de medida
orientationstring"portrait""portrait" ou "landscape"
marginsobjectMargens (left, right, top, bottom)
labelConfigobjectnullConfiguração para modo etiqueta (ver Etiquetas)

Formatos comuns

FormatoLargura (pt)Altura (pt)
A3841.891190.55
A4595.28841.89
A5419.53595.28
Carta612.00792.00
Legal612.001008.00

Modo de processamento

  • strict (padrão): erros de binding, data source não encontrado ou tipo inválido interrompem o processamento.
  • resilient: registra erros em ProcessedData.errors e continua com valores de fallback.
json
{
  "processingMode": "resilient"
}

Scripts

O campo scripts declara handlers de ciclo de vida executados pelo AdvancedScriptEngine. Cada script é identificado por um id e disparado em um dos dois hooks disponíveis:

HookQuando executa
afterQueryLogo após o DataProcessor carregar os dados, antes de renderizar. Use para filtrar, enriquecer ou transformar registros.
beforeRenderApós o processamento, antes de montar o PDF/HTML. Use para ajustar visibilidade de bands e elementos com base em regras de negócio.
json
{
  "scripts": [
    {
      "id": "mask_custo",
      "hook": "afterQuery",
      "description": "Remove coluna de custo se usuário não tiver permissão"
    },
    {
      "id": "hide_empty_section",
      "hook": "beforeRender",
      "description": "Oculta band de detalhes quando não há registros"
    }
  ]
}

Os handlers são registrados em Dart via AdvancedScriptEngine.register() e associados ao relatório pelo id:

dart
final engine = AdvancedScriptEngine(
  externalContext: {'permissions': userPermissions},
);

engine.register('mask_custo', (ctx) {
  final podeVerCusto = ctx.context('permissions').contains('financeiro');
  if (!podeVerCusto) {
    ctx.setElementVisible('col_custo', false);
  }
});

engine.register('hide_empty_section', (ctx) {
  final rows = ctx.datasource('vendas');
  ctx.setBandVisible('band_detalhe', rows.isNotEmpty);
});

final pdfBytes = await engine.generate(
  report,
  dataPayload: payload,
  format: 'pdf',
);

ScriptContext — API disponível

MétodoDescrição
datasource(id)Retorna os registros atuais de um data source
setDatasource(id, rows)Substitui todos os registros de um data source
addRow(id, row)Adiciona um registro
removeRow(id, predicate)Remove registros que satisfaçam a condição
setBandVisible(id, visible)Mostra ou oculta uma band
setElementVisible(id, visible)Mostra ou oculta um elemento
setElementProperty(id, prop, value)Altera propriedade de um elemento
param(id)Lê o valor de um parâmetro
setParam(id, value)Define o valor de um parâmetro
context(key)Acessa o externalContext injetado no engine
query(sql, params)Executa SQL via SqlBridge (opcional)
cancel()Aborta a geração do relatório
log(msg)Log de diagnóstico

Lógica inline em elementos

Para condicionais simples sem estado, use os campos inline dos elementos:

  • printWhen em qualquer elemento ou band — expressão booleana que controla visibilidade
  • valueExpression em FieldElement — expressão calculada no contexto do row atual

Prefira scripts quando a lógica precisar de acesso a parâmetros externos, múltiplos data sources ou estado acumulado.

Exemplo completo

Um relatório de vendas com header, 50 linhas de detalhe, agregados no summary e rodapé com paginação:

json
{
  "reportId": "sales_report",
  "reportName": "Relatório de Vendas",
  "version": "2.0",
  "pageSettings": {
    "format": "A4",
    "orientation": "portrait",
    "margins": { "left": 30, "right": 30, "top": 30, "bottom": 30 }
  },
  "dataSources": [
    {
      "id": "sales",
      "type": "list",
      "schema": {
        "order_id": "string",
        "customer": "string",
        "amount": "number",
        "date": "string"
      }
    }
  ],
  "bands": [
    {
      "type": "header", "id": "hdr", "height": 60,
      "elements": [
        { "type": "text", "id": "t1", "x": 30, "y": 20, "content": "Relatório de Vendas", "fontSize": 24, "bold": true }
      ]
    },
    {
      "type": "detail", "id": "det", "dataSourceId": "sales", "height": 25,
      "elements": [
        { "type": "field", "id": "f1", "x": 30, "y": 5, "width": 80, "binding": "order_id" },
        { "type": "field", "id": "f2", "x": 120, "y": 5, "width": 200, "binding": "customer" },
        { "type": "field", "id": "f3", "x": 330, "y": 5, "width": 100, "binding": "amount", "format": "currency:BRL" },
        { "type": "field", "id": "f4", "x": 440, "y": 5, "width": 100, "binding": "date", "format": "date:dd/MM/yyyy" }
      ]
    },
    {
      "type": "summary", "id": "sum", "height": 40,
      "elements": [
        { "type": "aggregate", "id": "total", "x": 330, "y": 10, "width": 100, "verb": "SUM", "dataSourceId": "sales", "targetKey": "amount", "format": "currency:BRL", "bold": true }
      ]
    },
    {
      "type": "footer", "id": "ftr", "height": 30,
      "elements": [
        { "type": "text", "id": "pg", "x": 250, "y": 10, "content": "Página {page} de {totalPages}", "fontSize": 9, "color": "999999" }
      ]
    }
  ]
}

Próximo passo

Entender as bands →

Sulfite do 🇧🇷 para o mundo © 2026 Rafael S. Pinheiro