A apuração do SPED/EFD dentro do Protheus normalmente exige rodar vários processos, conferir validações e ajustar divergências. Cada passo manual é uma chance de erro — e de multa. Este artigo mostra o fluxo completo, as funções nativas do Protheus e como montar uma automação que realmente funciona.
Fluxo completo de apuração SPED
A ordem dos processos é crítica. Pular etapas ou invertê-las gera divergências que só aparecem na validação. O fluxo correto:
-- Etapa 1: Fechamento de estoque e custo MATA220() -- Fechamento mensal de estoque (apuração fiscal depende do custo) -- Etapa 2: Apuração dos tributos MATA953() -- Apuração de ICMS (rotina nativa da Central TOTVS) -- Apuração de IPI: rotina conforme release — confirme no menu Fiscal -- Etapa 3: Geração e validação do arquivo EFD SPDFIS() -- Geração/validação do SPED Fiscal (EFD ICMS/IPI) -- Etapa 4: Validação (cross-check) -- Rotina customizada de validação (ver abaixo) -- Etapa 5: Transmissão — NÃO é feita pelo Protheus nem pelo TSS -- PVA da Receita: importar → validar → assinar (certificado A1/A3) -- → transmitir via Receitanet
Cuidado com telas em automação: rotinas como FINA070/FINA050 (baixas) e MATA220 são telas para operação humana. Automação de back-end usa ExecAuto (MSCM260, FINA040 etc.), Schedule/Job aprovado e fluxo controlado — chamar tela em rotina automática quebra em ambiente sem usuário.
E o TSS? O TSS (TOTVS Sped Service) transmite DF-e (NF-e, CT-e, MDF-e). A transmissão do EFD ICMS/IPI passa pelo PVA da Receita + Receitanet — confundir os dois leva a projeto de integração errado desde o início.
Rotinas nativas por etapa
Antes de criar customizações, saiba o que o Protheus já oferece nativamente:
| Rotina | Módulo | O que faz |
|---|---|---|
MATA953() | Fiscal | Apuração do ICMS próprio e diferencial |
SPDFIS() | Fiscal | Geração/validação do SPED Fiscal (EFD ICMS/IPI) |
MATA220() | Estoque | Fechamento mensal de estoque |
| PVA (Receita) | Externo | Validação, assinatura e transmissão do EFD (via Receitanet) |
Nota: rotinas de apuração de IPI e de EFD-Contribuições (PIS/COFINS) variam conforme release — valide no menu Fiscal do seu ambiente antes de citar em projeto. Não presuma função por nome de memória: confirme no ambiente.
Queries de validação antes da transmissão
A automação deve validar antes de transmitir. As queries abaixo estão em SQL puro (SSMS), com tabelas físicas (SF3010) e filial explícita — a regra é: filial + D_E_L_E_T_ em todo WHERE. E atenção: campos tipo data no Protheus são CHAR(8) em formato AAAAMMDD; "data vazia" é SPACE(8) (8 espaços), nunca um espaço só.
-- 1. Notas canceladas que ainda aparecem no SPED SELECT F3_FILIAL, F3_SERIE, F3_NFISCAL, F3_CLIEFOR, F3_DTCANC FROM SF3010 SF3 WHERE SF3.F3_FILIAL = '01' AND SF3.F3_DTCANC <> ' ' -- vazio = 8 espaços (CHAR(8)) AND SF3.F3_SERIE IN ('1', '2') AND SF3.F3_EMISSAO BETWEEN '20260801' AND '20260831' AND SF3.D_E_L_E_T_ = ' ' -- 2. CFOPs inconsistentes com a operação — join completo com loja SELECT C5.C5_NUM, C5.C5_LOJACLI, C6.C6_PRODUTO, C6.C6_CF, C5.C5_TIPO FROM SC5010 C5 JOIN SC6010 C6 ON C6.C6_FILIAL = C5.C5_FILIAL AND C6.C6_NUM = C5.C5_NUM WHERE C5.C5_FILIAL = '01' AND C5.C5_TIPO = 'N' AND C6.C6_CF LIKE '5%' AND C5.C5_EMISSAO BETWEEN '20260801' AND '20260831' AND C5.D_E_L_E_T_ = ' ' AND C6.D_E_L_E_T_ = ' ' -- 3. Divergência entre estoque e fiscal — coluna com underscore (B2_QATU) SELECT B2.B2_COD, B2.B2_QATU, SUM(D3.D3_QUANT) AS QTD_MOV FROM SB2010 B2 LEFT JOIN SD3010 D3 ON D3.D3_FILIAL = B2.B2_FILIAL AND D3.D3_COD = B2.B2_COD WHERE B2.B2_FILIAL = '01' AND B2.D_E_L_E_T_ = ' ' GROUP BY B2.B2_COD, B2.B2_QATU HAVING B2.B2_QATU <> SUM(D3.D3_QUANT)
SQL puro × ADVPL: RetSqlName("SF3") é função ADVPL — ela não roda dentro do SSMS. Se o bloco é SQL puro, use a tabela física (SF3010); se é ADVPL, monte a string com RetSqlName(), passe por ChangeQuery() e execute via TCQUERY ... NEW ALIAS. E F3_EMISSAO LIKE '202608%' funciona, mas é não-SARGable: prefira BETWEEN.
Função de validação customizada
Exemplo de função ADVPL que roda as validações e retorna as divergências encontradas:
// valida_sped.prw — Valida o SPED antes da transmissão. // Retorna array de divergências encontradas. #Include "protheus.ch" #Include "topconn.ch" User Function VALIDASPED(cMes, cAno) Local aErros := Local cQuery := "" Local cPeriodo := cAno + cMes // 1. Notas canceladas no período (ADVPL: RetSqlName + ChangeQuery + TCQUERY) cQuery := "SELECT F3_FILIAL, F3_NFISCAL, F3_SERIE, F3_CLIEFOR " cQuery += "FROM " + RetSqlName("SF3") + " SF3 " cQuery += "WHERE SF3.F3_FILIAL = '" + xFilial("SF3") + "' " cQuery += " AND SF3.F3_DTCANC <> '" + Space(8) + "' " cQuery += " AND SF3.F3_EMISSAO BETWEEN '" + cPeriodo + "01' AND '" + cPeriodo + "31' " cQuery += " AND SF3.D_E_L_E_T_ = ' ' " cQuery += " %nolock%" cQuery := ChangeQuery(cQuery) TCQUERY cQuery NEW ALIAS "QSFC" QSFC->(dbGoTop()) While QSFC->(!Eof()) aAdd(aErros, "Nota cancelada: " + ; QSFC->F3_NFISCAL + " / " + QSFC->F3_SERIE) QSFC->(dbSkip()) End QSFC->(dbCloseArea()) // 2. Período apurado: verifique nas tabelas de apuração/fechamento do seu // ambiente (MATA953 grava o resultado da apuração). Não existe um parâmetro // MV_ genérico "ICMS apurado" — controle é por tabela, não por GetMv. Return aErros
Controle de idempotência
Reprocessar o mesmo período não pode duplicar movimentos. A solução: tabela de controle com filial + período como chave, sem "hash mágico" — hash que depende da data de execução muda a cada rodada e não prova nada.
// Tabela customizada ZZ_SPED // Campos: ZZ_FILIAL, ZZ_PERIOD, ZZ_STATUS, ZZ_DTPROC User Function SPEDOK(cPeriodo) Local lRet := .F. // Área + ordem corretas antes de buscar (índice: ZZ_FILIAL + ZZ_PERIOD) DbSelectArea("ZZ_SPED") ZZ_SPED->(DbSetOrder(1)) // Verifica se já foi processado If ZZ_SPED->(MsSeek(xFilial("ZZ_SPED") + cPeriodo)) If ZZ_SPED->ZZ_STATUS == "OK" // Já processado — log estruturado, sem MsgAlert (isso roda em job) FWLogMsg("WARN", "", "SPEDOK", "", "", "", ; "Periodo " + cPeriodo + " ja processado em " + DTOC(ZZ_SPED->ZZ_DTPROC)) Return .F. EndIf EndIf // Grava registro de controle RecLock("ZZ_SPED", .T.) ZZ_SPED->ZZ_FILIAL := xFilial("ZZ_SPED") ZZ_SPED->ZZ_PERIOD := cPeriodo ZZ_SPED->ZZ_STATUS := "PROC" ZZ_SPED->ZZ_DTPROC := Date() MsUnLock() Return .T.
Padrões aplicados: campos em maiúsculas (ZZ_DTPROC, não ZZ_DT_proc), FWLogMsg em vez de interface (MsgAlert em rotina automática trava o job), e nomenclatura de campo validada no SX3 antes de gravar.
Checklist de validação antes da transmissão
A automação deve verificar tudo antes de transmitir. Cada item é uma query ou regra de negócio:
CFOP vs Operação
CFOP de saída (5xxx) em nota de entrada? CFOP de importação (3xxx) sem DI? A automação deve cruzar CFOP com tipo de operação.
CST/CSOSN consistente
CST do cadastro do produto (SB1) batendo com o CST da nota (SF3)? Divergência gera flag no EFD.
Valores batendo
Batimento SF2 × itens (SD2) com tolerância de centavos e regra por TES/CFGTRIB: frete, seguro, desconto e impostos mudam a composição. Fórmula simplificada demais gera falso positivo toda semana.
Base de cálculo ICMS
Base de cálculo do ICMS = valor da operação? Em operações com ST, a base é diferente. A query deve contemplar ambas.
IPI batendo
Valor do IPI calculado = valor do IPI informado na NF? Divergência pode indicar tabela de alíquotas desatualizada.
PIS/COFINS
Alíquota de PIS/COFINS do cadastro do produto batendo com o regime de apuração (cumulativo/não cumulativo)?
Cuidados de engenharia
- Idempotência: reprocessar o mesmo período não pode duplicar movimentos. Use tabela de controle por filial + período.
- Regressão fiscal: cada versão do Protheus pode mudar regras de apuração. Homologue sempre antes de produção.
- Correção, não "rollback": apuração fiscal não tem "desfazer genérico" — a correção exige estorno/retificação conforme o período e a obrigação (EFD retificadora, guia complementar). Prometer rollback simples de apuração é perigoso.
- Log completo: cada etapa deve gerar log com timestamp, registros processados e resultado. Auditoria exige isso.
- EFD-Contribuições ≠ EFD ICMS/IPI: PIS/COFINS tem regras, leiaute e geração próprios — valide a rotina da sua release no menu Fiscal antes de automar; não misture os dois fluxos.
O objetivo não é "apertar um botão e esquecer". É transformar um processo crítico em algo rastreável, repetível e auditável — com o humano atuando onde importa: na decisão sobre divergência.
Automação fiscal que não falha na hora H?
Falar com a ELP