Programação Por Equipe DevBras

Capa do artigo: SAT, NFC-e ou NF-e: decida qual documento o caixa emite antes da biblioteca

SAT, NFC-e ou NF-e: decida qual documento o caixa emite antes da biblioteca

CF-e SAT, NFC-e e NF-e são documentos diferentes, com equipamento, assinatura e contingência próprios. Veja como separar o fluxo no código, deixar a regra por loja configurável e homologar de verdade.

O sistema da rede de lojas já emitia NF-e para as vendas ao atacado. Quando entrou uma loja de varejo em São Paulo, alguém achou uma biblioteca de SAT no GitHub, ligou no mesmo botão "Emitir nota" e foi para a homologação. O XML não tinha nada a ver com o da NF-e, o equipamento precisava de ativação, a contingência era outra, e o cliente da loja de Minas Gerais recebeu um cupom que não era o documento que a operação dele exigia.

A resposta curta: CF-e SAT, NFC-e e NF-e são documentos fiscais diferentes, para operações diferentes, com leiaute, assinatura e contingência próprios. Antes de escolher biblioteca, defina com o contador qual documento cada loja emite em cada tipo de operação. No código, cada documento tem seu emissor separado, e a escolha entre eles vem de uma regra configurada por loja, não de um if espalhado pela tela de venda.

Isto não substitui a orientação de um contador nem a consulta à legislação do seu estado; o objetivo é mostrar como o sistema deve ser desenhado para acomodar a regra que eles definirem.

O que diferencia os três documentos

Os três são eletrônicos e terminam num XML assinado, o que dá a impressão de serem variações do mesmo tema. Não são.

  • NF-e (modelo 55): a nota fiscal eletrônica de uso geral, usada em operações entre empresas, em vendas para outros estados e em muitas situações que exigem documento completo. O seu sistema monta o XML, assina com o certificado digital da empresa e envia para autorização da Secretaria da Fazenda. A representação impressa é o DANFE.
  • NFC-e (modelo 65): a nota fiscal de consumidor eletrônica, voltada à venda no varejo para consumidor final. Também é assinada com o certificado da empresa e autorizada pela SEFAZ, mas tem leiaute e regras próprias, e o cupom impresso traz um QR Code para consulta.
  • CF-e SAT (modelo 59): o cupom fiscal eletrônico gerado por um equipamento SAT ligado ao computador do caixa, usado no varejo de São Paulo. O seu sistema envia os dados da venda ao equipamento; é ele quem gera, assina e transmite o cupom para a SEFAZ-SP. O equipamento precisa ser ativado e vinculado ao estabelecimento.

Há variações regionais. O Ceará, por exemplo, adotou o MFE, um módulo fiscal com lógica parecida com a do SAT, mas que não é o mesmo produto. E São Paulo, onde o SAT nasceu, passou a admitir a NFC-e e vem conduzindo uma transição entre os dois modelos; o calendário e as condições ficam na página da SEFAZ-SP, e é lá que você confere a situação atual. Some a isso a reforma tributária, que está acrescentando campos novos aos leiautes, e fica claro por que a decisão não pode estar cravada no código. O guia sobre SAT de um estado não servir para outro aprofunda a parte regional.

Como separar o fluxo no código

  1. Com o contador, faça a matriz de cada loja: tipo de operação, documento exigido, estado.
  2. Guarde essa matriz como configuração por loja, com data e responsável pela validação.
  3. Crie um emissor por documento, cada um atrás da mesma interface, sem compartilhar montagem de XML.
  4. Na venda, descubra a operação, consulte a regra da loja e chame o emissor certo. Se a loja não tiver regra para aquela operação, pare com erro claro.
  5. Guarde o XML e o retorno de cada documento emitido, com chave de acesso e situação.
  6. Homologue cada emissor no seu ambiente de homologação, com o equipamento ou certificado real.

A regra da loja como configuração

{
  "lojaId": 12,
  "uf": "SP",
  "documentos": {
    "VarejoPresencial": "CFeSat",
    "VendaInterestadual": "NFe",
    "VendaParaRevenda": "NFe"
  },
  "validadoPor": "Escritório Contábil Exemplo",
  "validadoEm": "2026-09-10"
}

Os nomes das operações são da sua empresa, não da legislação. O que importa é que a decisão "esta operação, nesta loja, gera este documento" está escrita num lugar só, com quem aprovou e quando. Mudou a regra do estado, muda o arquivo, revalida, e o código não é tocado.

Emissores separados e a escolha na venda

public enum DocumentoFiscal { NFe, NFCe, CFeSat }

public enum Operacao { VarejoPresencial, VendaInterestadual, VendaParaRevenda }

public record ResultadoEmissao(bool Autorizado, string? ChaveAcesso, string Xml, string Mensagem);

public interface IEmissorFiscal
{
    DocumentoFiscal Tipo { get; }
    Task<ResultadoEmissao> EmitirAsync(Venda venda, CancellationToken ct);
}

public class RegraFiscalDaLoja
{
    private readonly IReadOnlyDictionary<Operacao, DocumentoFiscal> _documentos;

    public RegraFiscalDaLoja(IReadOnlyDictionary<Operacao, DocumentoFiscal> documentos)
        => _documentos = documentos;

    public DocumentoFiscal DocumentoPara(Operacao operacao)
        => _documentos.TryGetValue(operacao, out var doc)
            ? doc
            : throw new InvalidOperationException(
                $"A loja não tem documento definido para {operacao}. Fale com o fiscal.");
}

public class FechamentoDeVenda
{
    private readonly RegraFiscalDaLoja _regra;
    private readonly IReadOnlyDictionary<DocumentoFiscal, IEmissorFiscal> _emissores;
    private readonly IArquivoFiscal _arquivo;

    public FechamentoDeVenda(RegraFiscalDaLoja regra,
        IEnumerable<IEmissorFiscal> emissores, IArquivoFiscal arquivo)
    {
        _regra = regra;
        _emissores = emissores.ToDictionary(e => e.Tipo);
        _arquivo = arquivo;
    }

    public async Task<ResultadoEmissao> FecharAsync(Venda venda, CancellationToken ct)
    {
        var documento = _regra.DocumentoPara(venda.Operacao);
        if (!_emissores.TryGetValue(documento, out var emissor))
            throw new InvalidOperationException(
                $"Este caixa não tem emissor de {documento} instalado.");

        var resultado = await emissor.EmitirAsync(venda, ct);
        await _arquivo.GuardarAsync(venda.Id, documento, resultado, ct);
        return resultado;
    }
}

O EmissorSat conversa com o equipamento pela biblioteca que você escolheu; o EmissorNfce e o EmissorNfe montam o XML e falam com os serviços da SEFAZ. Nenhum deles sabe que os outros existem. A loja de Minas, sem SAT instalado, nunca tenta emitir CF-e: a regra dela aponta outro documento, e se apontasse SAT por engano, o caixa pararia com uma mensagem clara em vez de gerar papel errado.

Contingência e homologação, cada uma no seu documento

Quando a internet cai, cada documento tem um caminho diferente. No SAT, o próprio equipamento emite e guarda os cupons para transmitir depois. Na NFC-e, existe emissão em contingência com regras e prazo de transmissão posteriores definidos pela legislação. Na NF-e, há modalidades de contingência próprias. Tratar tudo como "tenta de novo mais tarde" gera documento fora do prazo ou venda sem documento.

Homologue com o equipamento SAT real, ativado em ambiente de testes, e com o certificado de verdade para NFC-e e NF-e. O simulador ajuda no começo, mas não reproduz o tempo de resposta do aparelho, o erro de comunicação USB nem a rejeição que a SEFAZ devolve. A diferença entre os ambientes está explicada em homologação não é produção.

Erros comuns

  • Ligar o SAT no mesmo botão da NF-e. A loja emite um documento que a operação dela não admite, e o cliente fica com papel inválido.
  • Cravar a regra fiscal em if por estado. Cada mudança de legislação vira deploy, e um caso esquecido emite o documento errado sem aviso.
  • Reaproveitar a montagem de XML entre documentos. Os leiautes são diferentes, e um ajuste num quebra o outro.
  • Homologar só com simulador. Os problemas de ativação, comunicação e rejeição aparecem no primeiro dia da loja.
  • Misturar certificado e ambiente. Documento de homologação vai para produção, ou o contrário, e o arquivo fiscal fica inconsistente.
  • Não guardar o XML e o retorno. Na hora da fiscalização ou do cancelamento, ninguém acha o documento original.

Checklist

  • Existe uma matriz por loja, validada pelo contador, de operação para documento.
  • A matriz é configuração, com data e responsável, e não código.
  • Cada documento tem emissor próprio atrás de uma interface comum.
  • Operação sem regra definida bloqueia a venda com mensagem clara.
  • A contingência de cada documento foi testada separadamente.
  • O SAT foi homologado com equipamento real ativado.
  • Todo XML e retorno da SEFAZ ou do equipamento fica guardado.

Para o funcionamento do SAT no dia a dia do caixa, veja SAT fiscal no PDV, e para as diferenças de XML, XML de SAT não é a NF-e com a raiz trocada. E agora olhe a tela de venda do seu sistema: o botão de fechar sabe qual documento esta loja deve emitir, ou ele emite sempre o mesmo?

Avalie este artigo

Referência: https://github.com/ACBrNet/ACBr.Net.Sat