Programação Por Equipe DevBras

Capa do artigo: NF-e em homologação e produção: como impedir que um ambiente vaze no outro

NF-e em homologação e produção: como impedir que um ambiente vaze no outro

Amarre URL, tpAmb, série e numeração a uma única chave de ambiente, confira tudo antes de transmitir e deixe o ambiente visível para quem emite.

Segunda, 9h. A Casa Ferragem Silva emitiu doze notas no sábado, os clientes levaram a mercadoria e ninguém percebeu que o sistema ainda apontava para homologação. As doze notas foram autorizadas, só que sem valor fiscal. No mesmo dia, o caso inverso: um desenvolvedor testou um ajuste no XML e consumiu a numeração de produção, deixando buracos na sequência da série 1.

A resposta curta: ambiente de NF-e não é "o mesmo sistema com outro endereço". É um conjunto amarrado — URL do web service, campo tpAmb, série, contador de numeração e o aviso na tela — e tudo isso precisa derivar de uma única configuração, conferida antes de cada transmissão. Se cada peça é configurada à parte, um dia uma delas fica para trás.

Por que os dois ambientes se misturam

A SEFAZ mantém dois ambientes separados. Homologação aceita nota para teste, devolve protocolo de autorização de verdade e não gera obrigação fiscal. Produção é o mundo real: a nota vale, entra no cruzamento do fisco e só sai de lá por cancelamento ou evento. O XML diz em qual ambiente quer estar pelo campo tpAmb (1 para produção, 2 para homologação), e o endereço do web service diz para qual servidor você está mandando.

O problema começa quando essas informações moram em lugares diferentes. A URL fica num arquivo de configuração, o tpAmb fica fixo no código que monta o XML, a série fica numa tabela e o contador é o mesmo para os dois. Basta alguém trocar só a URL para o sistema mandar XML de produção para homologação (que rejeita pelo ambiente divergente) ou, pior, achar que trocou tudo e continuar emitindo nota de teste para cliente real.

O certificado digital não ajuda a diferenciar: o mesmo certificado A1 da empresa funciona nos dois ambientes. Por isso ele não pode ser o "sinal" de que você está em produção. Sobre a etapa anterior ao XML, há um panorama em o que acontece antes do XML da nota; e sobre por que o ambiente de teste existe, em homologação existe para errar sem valer. Aqui o foco é a engenharia que impede a mistura.

Como amarrar o ambiente a uma única chave

  1. Escolha o ambiente em um só lugar. Uma variável de configuração, por exemplo NFE_AMBIENTE=homologacao. Nada mais no sistema decide ambiente por conta própria.
  2. Derive tudo dessa chave. URL do autorizador, tpAmb do XML, série padrão e contador de numeração saem da mesma escolha. Ninguém digita a URL à mão.
  3. Separe a numeração por ambiente. O contador tem chave composta (ambiente, série). Teste nunca consome número de produção.
  4. Confira antes de transmitir. Leia o tpAmb do XML já assinado e compare com o ambiente configurado. Divergiu, não envia.
  5. Confira o retorno. O protocolo devolvido também traz tpAmb. Grave-o junto com a URL usada e o número do protocolo.
  6. Mostre o ambiente na tela. Uma faixa fixa "HOMOLOGAÇÃO — SEM VALOR FISCAL" na tela de emissão e o mesmo aviso impresso no DANFE de teste.

Exemplo em C#: configuração que não deixa peça solta

No sistema da Casa Ferragem Silva, a configuração só aceita o ambiente. A URL vem de uma tabela no código, indexada pelo próprio ambiente. Os endereços abaixo são fictícios; os reais dependem do autorizador da sua UF e estão publicados no Portal da NF-e.

public enum AmbienteNfe { Producao = 1, Homologacao = 2 }

public sealed class ConfigNfe
{
    private static readonly Dictionary<AmbienteNfe, string> UrlAutorizacao = new()
    {
        [AmbienteNfe.Producao] = "https://nfe.exemplo-uf.gov.br/ws/NFeAutorizacao4.asmx",
        [AmbienteNfe.Homologacao] = "https://homologacao.nfe.exemplo-uf.gov.br/ws/NFeAutorizacao4.asmx"
    };

    public AmbienteNfe Ambiente { get; }
    public string Url => UrlAutorizacao[Ambiente];
    public int TpAmb => (int)Ambiente;

    public ConfigNfe(string valorDaVariavel)
    {
        Ambiente = valorDaVariavel switch
        {
            "producao" => AmbienteNfe.Producao,
            "homologacao" => AmbienteNfe.Homologacao,
            _ => throw new InvalidOperationException(
                "NFE_AMBIENTE deve ser 'producao' ou 'homologacao'. Valor recebido: " + valorDaVariavel)
        };
    }
}

Repare que não existe valor padrão. Se a variável estiver ausente ou com erro de digitação, o sistema não sobe. É melhor a emissão parar às 8h com uma mensagem clara do que funcionar o dia inteiro no ambiente errado.

A conferência antes do envio

using System.Xml.Linq;

static void ConferirAmbiente(string xmlAssinado, ConfigNfe config)
{
    XNamespace ns = "http://www.portalfiscal.inf.br/nfe";
    var doc = XDocument.Parse(xmlAssinado);
    var tpAmb = doc.Descendants(ns + "tpAmb").FirstOrDefault()?.Value;

    if (tpAmb != config.TpAmb.ToString())
        throw new InvalidOperationException(
            "XML com tpAmb=" + tpAmb + " mas o sistema está em " + config.Ambiente + ". Envio bloqueado.");
}

A checagem custa microssegundos e pega exatamente o caso do XML gerado num ambiente e transmitido em outro, que acontece quando há fila de reenvio, XML montado num servidor e enviado por outro, ou um script de contingência esquecido.

Numeração separada no banco

CREATE TABLE numeracao_nfe (
  ambiente        TINYINT NOT NULL,
  serie           INT     NOT NULL,
  proximo_numero  INT     NOT NULL,
  PRIMARY KEY (ambiente, serie)
);

INSERT INTO numeracao_nfe VALUES (1, 1, 1532);  -- produção, série 1
INSERT INTO numeracao_nfe VALUES (2, 1, 1);     -- homologação, série 1

Com a chave composta, o teste da segunda-feira usa o contador da linha de homologação e a série 1 de produção continua em 1532. Se o teste tivesse consumido números de produção, os buracos na sequência precisariam ser tratados com inutilização de numeração, que é um evento formal e não uma limpeza de banco. Para quem prefere isolar ainda mais, uma série exclusiva para testes também funciona, desde que o contador continue separado por ambiente.

O que homologação exige de diferente

Homologação tem regras próprias. A mais conhecida é o texto padrão exigido no nome do destinatário, "NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL". Se o seu código monta o destinatário igual nos dois ambientes, a nota de teste é rejeitada. A redação exata e as demais regras estão no Manual de Orientação do Contribuinte (MOC) e nas notas técnicas vigentes; confira a versão que você implementou, porque dica de nota fiscal antiga pode rejeitar a nota de hoje.

Essa diferença é mais um motivo para a regra sair da mesma chave: o montador de XML pergunta à configuração se está em homologação e aplica o texto, em vez de alguém lembrar de trocar.

Deixar o ambiente visível para quem emite

O operador do caixa não abre XML. Ele vê a tela e o papel. Se em homologação a tela é idêntica à de produção, o erro de sábado vai se repetir. Coloque uma faixa colorida fixa no topo da emissão, o nome do ambiente no rodapé de cada tela e a marca "SEM VALOR FISCAL" no DANFE gerado em homologação. Muitas bibliotecas de DANFE já fazem isso quando leem tpAmb=2; confira se a sua faz.

No log de cada autorização, grave ambiente, URL, série, número, chave de acesso e protocolo. Quando o contador pedir explicação sobre uma nota, você responde em minutos.

Erros comuns

  • Trocar só a URL no arquivo de configuração. O tpAmb continua fixo no código e a SEFAZ rejeita, ou a troca parcial passa despercebida até alguém conferir uma nota real.
  • Usar o mesmo contador de numeração para os dois ambientes. O teste consome números de produção e abre buracos que exigem inutilização.
  • Ter um valor padrão de ambiente no código. Se a variável some num deploy, o sistema sobe silenciosamente no ambiente padrão, seja ele qual for.
  • Usar o certificado como sinal de ambiente. O mesmo certificado vale nos dois; ele não diferencia nada.
  • Imprimir DANFE de teste igual ao de produção. O papel vai junto com a mercadoria e o cliente acha que tem nota válida.
  • Copiar o banco de produção para homologação sem zerar a numeração. O ambiente de teste herda contadores e dados reais de clientes, o que também é um problema de privacidade.

Checklist

  • O ambiente é escolhido em uma única variável, sem valor padrão.
  • URL, tpAmb e regras específicas de homologação derivam dessa variável.
  • A tabela de numeração tem chave (ambiente, série).
  • O tpAmb do XML assinado é conferido antes do envio.
  • O tpAmb do protocolo de retorno é conferido e gravado.
  • A tela de emissão mostra o ambiente sem precisar abrir o XML.
  • O DANFE de homologação traz "SEM VALOR FISCAL".
  • O log de autorização guarda ambiente, URL, série, número e protocolo.

Abra agora a tela de emissão do seu sistema, sem olhar configuração nem XML: você consegue dizer em qual ambiente está e qual será o número da próxima nota de produção?

Avalie este artigo

Referência: https://pt.stackoverflow.com/questions/35235/como-emitir-o-xml-da-nfe-ao-ws-da-sefaz-usando-c