Programação Por Equipe DevBras

Capa do artigo: Enviar o XML da NF-e ao cliente sem mandar a nota de outro pedido

Enviar o XML da NF-e ao cliente sem mandar a nota de outro pedido

Automatize o envio do XML da nota: só depois da autorização, com o arquivo nomeado pela chave, conferido contra o pedido e com uma fila de envio que repete o e-mail sem gerar outra nota.

Segunda-feira, 10h12, a loja de ferragens emitiu duas notas no mesmo segundo. As duas rotinas gravaram o arquivo como temp/nota.xml, e o cliente do pedido 10432 recebeu o XML do vizinho de fila, com nome, CPF e endereço de outra pessoa. A resposta curta: o XML que segue para o cliente é o arquivo autorizado daquela venda, identificado pela chave de acesso e conferido contra o pedido antes de sair. Dispare só depois da autorização, nomeie pelo número da chave, confira chave e destinatário, e use uma fila de envio que repete o e-mail sem nunca emitir outra nota.

Este guia monta esse fluxo com o pedido 10432 como exemplo, em PHP e MySQL, mas a lógica vale para qualquer linguagem.

Por que o XML errado sai

O envio automático costuma nascer como três linhas no fim da emissão: gravar o arquivo, montar o e-mail, anexar. Isso esconde três suposições frágeis. A primeira é que o arquivo no disco é o da venda atual; com nome fixo e duas emissões simultâneas, não é. A segunda é que a emissão terminou bem; se a rotina envia logo depois de transmitir, pode anexar um XML ainda sem protocolo de autorização, ou de uma nota rejeitada. A terceira é que o e-mail funciona na primeira tentativa; quando ele falha, alguém aperta "emitir de novo" para "reenviar", e aí nasce uma segunda nota para a mesma venda.

O XML da NF-e não é um anexo qualquer. Ele traz dados pessoais do destinatário, tem valor fiscal e é identificado por uma chave de acesso de 44 dígitos. Tratar o envio como "mandar um arquivo" é o que permite os três erros.

Qual arquivo enviar

O arquivo que o cliente precisa é o XML da nota junto com o protocolo de autorização, normalmente chamado de XML de distribuição: a raiz nfeProc contém a NFe assinada e o protNFe com a resposta da Sefaz. Dentro do protocolo, cStat igual a 100 indica uso autorizado e chNFe traz a chave. O XML que você montou e assinou, antes de transmitir, ainda não é esse arquivo. A regra da NF-e prevê que o emitente disponibilize o XML ao destinatário; a forma de fazer isso na sua operação é assunto para confirmar com o contador, porque isto não substitui a orientação de um profissional de contabilidade.

Como montar o envio automático

  1. Depois da autorização, grave o XML de distribuição com o nome da chave, por exemplo 35261012345678000199550010000104321000104328-procNFe.xml, numa pasta definitiva, nunca num arquivo temporário com nome fixo.
  2. Grave no pedido a chave e o status conferido no protocolo.
  3. Crie uma linha na fila de envio com pedido, chave e destinatário.
  4. Um processo separado lê a fila, reabre o arquivo pela chave e confere chave, status e documento do destinatário contra o pedido.
  5. Só então envia o e-mail. Se falhar, registra o erro e tenta de novo depois, com o mesmo arquivo.
  6. Se a nota for cancelada mais tarde, envie também o XML do evento de cancelamento.

A fila de envio

CREATE TABLE envio_xml (
  id INT AUTO_INCREMENT PRIMARY KEY,
  pedido_id INT NOT NULL,
  chave CHAR(44) NOT NULL,
  destinatario VARCHAR(200) NOT NULL,
  status VARCHAR(20) NOT NULL DEFAULT 'pendente',
  tentativas INT NOT NULL DEFAULT 0,
  ultimo_erro VARCHAR(500) NULL,
  enviado_em DATETIME NULL,
  UNIQUE KEY uq_envio (chave, destinatario)
);

A chave única em (chave, destinatario) impede duas linhas para o mesmo envio. Reenviar é mudar o status de volta para pendente, não emitir nada.

A conferência antes de anexar

<?php
function conferirXmlParaEnvio(string $caminho, array $pedido): void
{
    $doc = new DOMDocument();
    if (!$doc->load($caminho)) {
        throw new RuntimeException('XML ilegível: ' . $caminho);
    }
    $xp = new DOMXPath($doc);
    $xp->registerNamespace('n', 'http://www.portalfiscal.inf.br/nfe');

    $chave  = $xp->evaluate('string(/n:nfeProc/n:protNFe/n:infProt/n:chNFe)');
    $status = $xp->evaluate('string(/n:nfeProc/n:protNFe/n:infProt/n:cStat)');
    $docDest = $xp->evaluate('string(/n:nfeProc/n:NFe/n:infNFe/n:dest/n:CNPJ)')
            ?: $xp->evaluate('string(/n:nfeProc/n:NFe/n:infNFe/n:dest/n:CPF)');

    if ($status !== '100') {
        throw new RuntimeException("Nota sem autorização (cStat $status).");
    }
    if ($chave !== $pedido['nfe_chave']) {
        throw new RuntimeException("Chave do arquivo ($chave) diferente da do pedido.");
    }
    $docPedido = preg_replace('/[^0-9]/', '', $pedido['cliente_documento']);
    if ($docDest !== $docPedido) {
        throw new RuntimeException('Destinatário do XML não é o cliente do pedido.');
    }
}

Se qualquer conferência falhar, o envio fica com status erro e a mensagem vai para ultimo_erro, para alguém olhar. No caso da segunda-feira, a função teria parado o envio: a chave do arquivo nota.xml não era a do pedido 10432. O nome do arquivo pela chave, por si só, já teria evitado a troca; a conferência pega o que o nome não pega, como um pedido ligado à nota errada por um bug de tela.

O e-mail em si

O endereço vem do cadastro do pedido, que é o que o cliente informou na compra. O assunto leva o número da nota e o nome da loja; o corpo diz o número do pedido e a chave, para o cliente conferir no portal da NF-e se quiser. Anexe o XML e, se você gera, o PDF do DANFE. Use um serviço de envio com SPF e DKIM configurados, senão o e-mail da nota cai no spam; o guia de formulário de contato que chega explica essa parte.

Guardar o arquivo é obrigação sua

Mandar o XML ao cliente não dispensa você de guardar o seu. O arquivo de distribuição precisa ficar armazenado pelo prazo que a legislação exige, mesmo que a emissão seja feita por uma API de terceiros. O post sobre API de nota que não guarda por você trata disso. Para entender o que existe dentro do XML antes da autorização, veja o XML válido e o que a tela mostrou.

Erros comuns

  • Arquivo temporário com nome fixo. Duas emissões simultâneas sobrescrevem o mesmo arquivo e um cliente recebe os dados de outro.
  • Enviar logo depois de transmitir. Vai um XML sem protocolo, ou de uma nota rejeitada, que não serve ao cliente.
  • Emitir de novo para reenviar o e-mail. Nasce uma segunda nota para a mesma venda, que depois precisa ser cancelada.
  • Não conferir o destinatário. Um pedido ligado à nota errada manda dados pessoais para a pessoa errada.
  • Esquecer o evento de cancelamento. O cliente fica com uma nota que, para a Sefaz, não vale mais.
  • Enviar sem registrar. Quando o cliente diz que não recebeu, ninguém sabe se o e-mail saiu, falhou ou nem foi tentado.

Checklist

  • O XML enviado é o de distribuição, com protocolo e cStat 100.
  • O arquivo é nomeado e encontrado pela chave de acesso.
  • Antes de anexar, chave e documento do destinatário são conferidos contra o pedido.
  • O envio passa por uma fila com status, tentativas e último erro.
  • Reenviar não emite outra nota.
  • Cancelamentos também geram envio do XML do evento.
  • O e-mail sai por um serviço com SPF e DKIM configurados.

Faça agora um teste de cinco minutos: emita uma nota em homologação, abra o e-mail que chegou e compare a chave do anexo com a chave na tela do pedido. São a mesma? E se duas notas forem emitidas no mesmo segundo, o seu sistema ainda manda cada uma para o dono certo?

Avalie este artigo

Referência: http://www.gestortotal.com.br/emissor-nfe/como-configurar-sistema-para-enviar-arquivo-xml-automaticamente-cliente