Todos os estudos de caso

Vendas e Comercial

Painel Comercial de uma rede varejista com 42 lojas

Contexto

Rede de varejo alimentar com 42 lojas em 6 estados, 18 mil SKUs e 210 vendedores. A diretoria comercial recebia hoje três planilhas diferentes por e-mail toda segunda-feira, com números que não fechavam entre si. O objetivo é uma fonte única, atualizada diariamente, que responda em 10 segundos se o mês está no ritmo da meta e onde está o problema.

Perguntas que o painel deve responder

  • Estamos no ritmo da meta do mês, por loja e por vendedor?
  • O crescimento vem de mais clientes, mais itens ou preço maior?
  • Quais produtos estão puxando a margem para baixo?
  • Quais lojas caíram em relação ao mesmo período do ano passado, com dias comparáveis?
  • Quais clientes de atacado reduziram compra nos últimos 90 dias?

Indicadores e metas

IndicadorMetaPor que importa
Receita LíquidaR$ 48 mi/mêsIndicador-mestre; exclui devoluções e impostos sobre venda
Atingimento Proporcional≥ 100%Mede o ritmo dentro do mês, sem falso alarme no dia 5
Margem Bruta %≥ 24%Crescer vendendo com prejuízo não é crescimento
Ticket MédioR$ 87Mostra se o crescimento vem de mais clientes ou de compras maiores
Itens por Cupom≥ 5,2Mede a eficácia de cross-sell e da exposição em loja
Ruptura de Gôndola %≤ 3%Venda perdida não aparece no faturamento — só aqui
Curva ABC de ProdutosA ≤ 20% dos SKUsConcentra atenção no que realmente gera resultado

Modelo de dados

Esquema estrela clássico: uma fato de vendas na granularidade item do cupom, e dimensões de calendário, loja, produto, vendedor e cliente. A tabela de metas fica separada, em granularidade mês × loja × vendedor.

TabelaTipoGranularidadeVolume
fVendasFatoItem do cupom~ 62 mi linhas/ano
fMetasFatoMês × Loja × Vendedor~ 2,5 mil linhas/mês
fEstoqueFatoDia × Loja × SKU~ 9 mi linhas/mês
dCalendarioDimensãoDia1.826 linhas (5 anos)
dLojaDimensãoLoja42
dProdutoDimensãoSKU18.000
dVendedorDimensãoVendedor210
dClienteDimensãoCliente (atacado)3.400
  • Data e hora do cupom separadas em duas colunas (reduz ~35% do modelo).
  • Coluna CustoUnitario trazida para fVendas na carga (custo vigente na data da venda).
  • IDs textuais convertidos em chaves inteiras no Power Query.
  • Atualização incremental: últimos 7 dias recarregados diariamente, histórico congelado.

Medidas DAX

Receita Líquida

DAX
Receita Líquida =SUMX(    fVendas,    fVendas[Quantidade] * fVendas[PrecoUnitario] * ( 1 - fVendas[PercDesconto] )) - [Devoluções]

Nasce linha a linha porque o desconto é percentual por item; devoluções entram como medida separada para poder ser analisada sozinha.

Margem Bruta %

DAX
Margem Bruta =SUMX(    fVendas,    fVendas[Quantidade] * ( fVendas[PrecoUnitario] * ( 1 - fVendas[PercDesconto] ) - fVendas[CustoUnitario] )) Margem Bruta % = DIVIDE( [Margem Bruta], [Receita Líquida] )

Usa o custo gravado na venda, não o custo atual do cadastro — isso evita reescrever o histórico a cada mudança de preço de compra.

Ticket Médio e Itens por Cupom

DAX
Qtd Cupons = DISTINCTCOUNT( fVendas[NumeroCupom] ) Ticket Médio = DIVIDE( [Receita Líquida], [Qtd Cupons] ) Itens por Cupom = DIVIDE( SUM( fVendas[Quantidade] ), [Qtd Cupons] )

DISTINCTCOUNT sobre cupom é a operação mais cara do painel; em modelos muito grandes, substitua por uma coluna de cupom já deduplicada em uma tabela auxiliar.

Comparação justa com o ano anterior

DAX
Receita LY =CALCULATE( [Receita Líquida], SAMEPERIODLASTYEAR( dCalendario[Date] ) ) Receita LY Comparável =-- Só os mesmos dias já decorridos, para não comparar 12 dias com 30VAR UltimoDiaComVenda =    CALCULATE( MAX( fVendas[Data] ), REMOVEFILTERS( dCalendario ) )VAR DiaCorte = MIN( MAX( dCalendario[Date] ), UltimoDiaComVenda )RETURNCALCULATE(    [Receita Líquida],    SAMEPERIODLASTYEAR(        FILTER( VALUES( dCalendario[Date] ), dCalendario[Date] <= DiaCorte )    )) Var. YoY % = DIVIDE( [Receita Líquida] - [Receita LY Comparável], [Receita LY Comparável] )

A medida comparável é a que evita a reunião mensal mais desgastante do varejo: explicar por que o mês 'caiu 60%' no dia 12.

Meta proporcional e semáforo

DAX
Meta =CALCULATE(    SUM( fMetas[ValorMeta] ),    TREATAS( VALUES( dCalendario[AnoMes] ), fMetas[AnoMes] ),    TREATAS( VALUES( dLoja[Loja] ), fMetas[Loja] )) Meta Proporcional =VAR DiasDecorridos =    CALCULATE( COUNTROWS( dCalendario ), dCalendario[Date] <= TODAY() )VAR DiasTotais = COUNTROWS( dCalendario )RETURN [Meta] * DIVIDE( DiasDecorridos, DiasTotais ) Atingimento % = DIVIDE( [Receita Líquida], [Meta Proporcional] ) Cor Atingimento =SWITCH( TRUE(),    ISBLANK( [Meta] ), "#8A8F98",    [Atingimento %] >= 1,    "#2E9E6B",    [Atingimento %] >= 0.9,  "#E0A526",    "#D0453B")

TREATAS conecta metas sem relacionamento físico, evitando ambiguidade no modelo quando a meta existe em granularidades diferentes.

Ruptura de gôndola

DAX
SKUs Ativos por Loja =CALCULATE( DISTINCTCOUNT( fEstoque[IdProduto] ), REMOVEFILTERS( fEstoque[Saldo] ) ) SKUs em Ruptura =CALCULATE(    DISTINCTCOUNT( fEstoque[IdProduto] ),    fEstoque[Saldo] <= 0,    dProduto[CurvaABC] IN { "A", "B" }) Ruptura % = DIVIDE( [SKUs em Ruptura], [SKUs Ativos por Loja] ) Venda Perdida Estimada =SUMX(    FILTER( SUMMARIZE( fEstoque, dProduto[Produto], dLoja[Loja] ), [SKUs em Ruptura] > 0 ),    [Venda Média Diária do SKU])

Ruptura é o indicador que mais impacta o resultado e menos aparece nos painéis: a venda que não aconteceu não está em nenhuma tabela de faturamento.

Curva ABC dinâmica

DAX
Receita Acumulada % =VAR Base =    ADDCOLUMNS( ALLSELECTED( dProduto[Produto] ), "@Rec", [Receita Líquida] )VAR RecAtual = [Receita Líquida]VAR Acumulado = SUMX( FILTER( Base, [@Rec] >= RecAtual ), [@Rec] )RETURN DIVIDE( Acumulado, SUMX( Base, [@Rec] ) ) Classe ABC Dinâmica =SWITCH( TRUE(),    [Receita Acumulada %] <= 0.8,  "A",    [Receita Acumulada %] <= 0.95, "B",    "C")

Classe calculada por medida respeita o filtro do usuário: a curva ABC de uma loja específica é diferente da curva da rede.

Clientes de atacado em risco

DAX
Clientes em Queda =VAR Base =    ADDCOLUMNS(        VALUES( dCliente[Cliente] ),        "@Atual",    CALCULATE( [Receita Líquida], DATESINPERIOD( dCalendario[Date], TODAY(), -90, DAY ) ),        "@Anterior", CALCULATE( [Receita Líquida], DATESINPERIOD( dCalendario[Date], TODAY() - 90, -90, DAY ) )    )RETURNCOUNTROWS(    FILTER( Base, [@Anterior] > 0 && DIVIDE( [@Atual], [@Anterior] ) < 0.7 ))

Queda de 30% em 90 dias é o gatilho combinado com o time comercial — ajuste o limiar ao seu ciclo de compra.

Layout do painel

  1. 1Faixa superior: título, seletor de período, filtros ativos em texto dinâmico e carimbo de atualização.
  2. 2Linha de KPIs (6 cartões): Receita Líquida, Atingimento Proporcional, Margem %, Ticket Médio, Itens/Cupom, Ruptura % — todos com variação YoY e cor semântica.
  3. 3Bloco central esquerdo: linha de receita diária acumulada do mês contra a linha de meta acumulada (mostra o ritmo, não só o total).
  4. 4Bloco central direito: cascata explicando a variação YoY por categoria.
  5. 5Bloco inferior esquerdo: matriz por loja com barras de dados na receita, ícone de status e cor por margem.
  6. 6Bloco inferior direito: Top 10 produtos por contribuição de margem e Bottom 10 por margem negativa.
  7. 7Tooltip de página em toda a matriz: tendência de 12 meses da loja ou do produto.
  8. 8Drill-through por loja: página com detalhe de vendedores, ruptura e mix.
  9. 9Página oculta 'Dicionário': definição escrita de cada indicador e a origem do dado.

Desafio final

Implemente o painel completo e, depois, responda com ele: se a rede cresceu 8% no ano, quanto desse crescimento veio de mais cupons, quanto de ticket maior e quanto de inflação de preço? Crie a decomposição em cascata que separa efeito volume, efeito mix e efeito preço.