Relatório: agrupado, somado e pronto para exportar.
O relatório abaixo roda no app de exemplo, publicado no Teste Online, sobre as mesmas 52 vendas. Elas aparecem agrupadas por vendedor, com subtotais por grupo e total geral de R$ 391.796,04.
Todas as vendas de uma vez, separadas por vendedor
Um relatório é uma listagem com o agrupamento ligado e sem paginação. Todos os registros saem de uma vez, separados por grupo, com subtotais e o status colorido.

Três propriedades transformam a listagem em relatório
Com três propriedades no controller, a listagem vira relatório. Só há uma regra: a ordenação padrão (defaultSort) precisa começar pelos campos do agrupamento. Se não começar, o mesmo grupo aparece mais de uma vez.
class VendaReport extends MadDataGrid{protected string $model = Venda::class;// Sort DEVE começar pelos campos de agrupamento (senão os grupos repetem)protected string $defaultSort = 'vendedor ASC, data_venda ASC';public int $perPage = 0; // sem paginação: grupos inteirosprotected string|array $groupBy = 'vendedor';protected bool $groupTotal = true;protected string $exportTitle = 'Relatório de Vendas';protected string $exportFilename = 'relatorio-de-vendas';} A exportação mantém os grupos e os subtotais
Grupos, subtotais e total geral vão junto para o CSV, o Excel e o PDF. O PDF é o mesmo da página de Listagem, com cabeçalho, quebras por grupo, status colorido e Página X de Y.

Quando usar o relatório
Use o relatório quando alguém precisa ver tudo de uma vez, separado em grupos e somado. É a tela do fechamento e da conferência.
- Comissão de vendas. As vendas do mês por vendedor, com o subtotal de cada um.
- Extrato financeiro. Lançamentos por conta, com um saldo que recomeça em cada conta.
- Movimento de estoque. Entradas e saídas por produto e, dentro dele, por mês.
- Chamados do suporte. Chamados por técnico, com a quantidade de cada um.
Para editar registro por registro, use a listagem. Para indicadores e gráficos, o dashboard. Para imprimir um pedido, o documento. E os filtros do relatório viram consultas Eloquent comuns, como mostra a geração de código.
O que você configura
Além das três propriedades acima, estes atributos mudam o que sai na tela e no PDF.
- Níveis do agrupamento
group-by - Até três campos, separados por vírgula. Aceita um campo de outra tabela e uma data agrupada por dia, mês ou ano.
- Rótulo do grupo
group-mask - O texto que abre cada grupo, com campos e valores já formatados, como moeda e data.
- Subtotal alinhado
group-band - Com o valor
cells, os subtotais ficam embaixo das colunas somadas, como num relatório impresso. - Linha de detalhe
row-detail - Uma segunda linha sob cada registro, como o histórico de um lançamento. Sai na tela e no PDF.
- Saldo acumulado
running - Soma a coluna linha a linha. Com
running-reset="group", o saldo recomeça em cada grupo. - Subtítulo do arquivo
export-subtitle - Pode trazer o período filtrado. Assim o PDF já diz de quando são os números.
O que vai para o projeto Laravel
O relatório usa a mesma base da listagem (MadDataGrid), numa classe em app/Control com a view <mad-grid>. O que você ajusta no código:
- Ajustes em propriedades PHP. Agrupamento, subtotal, título e nome do arquivo são propriedades da classe. Se o Blade trouxer o atributo do título, ele vence.
- Filtro extra em Eloquent. Uma condição que a tela não oferece entra no método de busca da classe (
onSearch). - Cabeçalho do PDF com marcadores. As faixas do PDF ficam num bloco da classe, com título, data, período, filtros ativos e número da página. Um dado só desta tela entra por um método próprio (
exportPdfPlaceholders).
Como toda tela do MadBuilder, esses arquivos abrem no seu editor, vão para o seu Git e aceitam código à mão em blocos protegidos, que continuam lá quando a tela é gerada de novo. Veja como o código é gerado.
Perguntas sobre o relatório
Dá pra agrupar o relatório por mais de um campo?
Dá, em até três níveis, como vendedor e depois mês. Cada nível ganha a sua faixa de grupo.
Dá pra agrupar por um campo de outra tabela?
Dá, quando cada registro aponta para um só item da outra tabela, como a venda e o seu cliente. Pelos pagamentos da venda, que são vários, não dá.
Por que o relatório não tem paginação?
Com paginação, um grupo seria cortado no meio e o subtotal somaria só a parte da página. Em bases grandes, dá para obrigar o usuário a filtrar antes de consultar.
E mais
Crie a conta, monte uma tela, baixe o projeto.
Sem demo agendada e sem call de descoberta. Se o Laravel que sair não passar na revisão do seu time, você perdeu uma tarde.
- Crie a contaBeta aberto, sem cartão.
- Monte uma telaNo visual, no código ou pedindo à IA.
- Baixe o .zipUm projeto Laravel que roda onde você quiser.