Skip to main content

Visão Geral

O armazenamento seguro de NFe é fundamental para empresas que precisam manter conformidade fiscal e facilitar auditorias. Com a API GuardaNFe da ValidaNFe, você pode criar um sistema completo de backup fiscal na nuvem.

Benefícios do Armazenamento Seguro

  • Conformidade fiscal garantida por até 10 anos
  • Backup automático com redundância geográfica
  • Busca e recuperação rápida de documentos
  • Auditoria facilitada com logs completos de acesso

Arquitetura de Armazenamento

1

Recebimento

NFe recebidas são processadas e validadas automaticamente
2

Indexação

Metadados extraídos para busca e categorização eficiente
3

Armazenamento

XML original armazenado com criptografia AES-256
4

Backup

Replicação automática em múltiplas regiões geográficas
5

Acesso

Interface de consulta e download com controle de permissões

Implementação Básica

1. Sistema de Upload Automático

import { ValidaNFeSDK } from 'validanfe-sdk';
import fs from 'fs';
import path from 'path';

class ArmazenadorNFe {
  constructor() {
    this.validanfe = new ValidaNFeSDK({
      apiKey: process.env.VALIDANFE_API_KEY
    });
  }

  async processarDiretorio(diretorio) {
    const arquivos = fs.readdirSync(diretorio);
    const xmlFiles = arquivos.filter(file => file.endsWith('.xml'));

    console.log(`Processando ${xmlFiles.length} arquivos XML...`);

    for (const arquivo of xmlFiles) {
      try {
        await this.processarArquivo(path.join(diretorio, arquivo));
      } catch (error) {
        console.error(`Erro ao processar ${arquivo}:`, error.message);
      }
    }
  }

  async processarArquivo(caminhoArquivo) {
    const xmlContent = fs.readFileSync(caminhoArquivo, 'utf8');
    const chaveNFe = this.extrairChaveNFe(xmlContent);

    if (!chaveNFe) {
      throw new Error('Chave NFe não encontrada no XML');
    }

    // Verificar se já existe no GuardaNFe
    const jaExiste = await this.verificarSeExiste(chaveNFe);
    if (jaExiste) {
      console.log(`NFe ${chaveNFe} já armazenada`);
      return;
    }

    // Armazenar no GuardaNFe
    const resultado = await this.validanfe.guarda.armazenar({
      chave: chaveNFe,
      xml: xmlContent,
      metadata: {
        origem: 'upload_automatico',
        arquivo_original: path.basename(caminhoArquivo),
        processado_em: new Date().toISOString()
      }
    });

    console.log(`NFe ${chaveNFe} armazenada com sucesso. ID: ${resultado.arquivoId}`);

    // Salvar referência no banco local
    await this.salvarReferencia({
      chave_nfe: chaveNFe,
      arquivo_id: resultado.arquivoId,
      url_download: resultado.urlDownload,
      arquivo_original: path.basename(caminhoArquivo),
      armazenado_em: new Date()
    });
  }

  extrairChaveNFe(xmlContent) {
    const match = xmlContent.match(/<infNFe[^>]*Id="NFe(\d{44})"/);
    return match ? match[1] : null;
  }

  async verificarSeExiste(chaveNFe) {
    try {
      await this.validanfe.guarda.verificar({ chave: chaveNFe });
      return true;
    } catch (error) {
      if (error.status === 404) {
        return false;
      }
      throw error;
    }
  }
}

2. Sistema de Backup Incremental

class BackupIncremental {
  constructor() {
    this.armazenador = new ArmazenadorNFe();
    this.ultimaVerificacao = this.carregarUltimaVerificacao();
  }

  async executarBackup() {
    console.log('Iniciando backup incremental...');

    // Buscar NFe modificadas desde última verificação
    const nfesModificadas = await this.buscarNFesModificadas();
    
    for (const nfe of nfesModificadas) {
      try {
        await this.processarNFe(nfe);
      } catch (error) {
        console.error(`Erro ao processar NFe ${nfe.chave}:`, error.message);
        await this.registrarErro(nfe.chave, error.message);
      }
    }

    // Atualizar timestamp da última verificação
    this.ultimaVerificacao = new Date();
    await this.salvarUltimaVerificacao(this.ultimaVerificacao);

    console.log(`Backup incremental concluído. ${nfesModificadas.length} NFe processadas.`);
  }

  async buscarNFesModificadas() {
    return await database.nfes.find({
      $or: [
        { modificado_em: { $gte: this.ultimaVerificacao } },
        { guardanfe_id: { $exists: false } }
      ]
    });
  }

  async processarNFe(nfe) {
    if (!nfe.guardanfe_id) {
      // Primeira vez - armazenar
      const resultado = await this.armazenador.validanfe.guarda.armazenar({
        chave: nfe.chave,
        xml: nfe.xml_content,
        metadata: {
          empresa_id: nfe.empresa_id,
          tipo: nfe.tipo,
          valor: nfe.valor_total,
          data_emissao: nfe.data_emissao
        }
      });

      await database.nfes.updateOne(
        { _id: nfe._id },
        { 
          guardanfe_id: resultado.arquivoId,
          guardanfe_url: resultado.urlDownload,
          backup_em: new Date()
        }
      );
    } else {
      // Atualizar se necessário
      await this.verificarEAtualizar(nfe);
    }
  }

  async verificarEAtualizar(nfe) {
    try {
      const info = await this.armazenador.validanfe.guarda.obterInfo({
        arquivoId: nfe.guardanfe_id
      });

      // Verificar se precisa atualizar
      if (info.hash !== this.calcularHashXML(nfe.xml_content)) {
        await this.armazenador.validanfe.guarda.atualizar({
          arquivoId: nfe.guardanfe_id,
          xml: nfe.xml_content
        });
        
        console.log(`NFe ${nfe.chave} atualizada no GuardaNFe`);
      }
    } catch (error) {
      console.error(`Erro ao verificar NFe ${nfe.chave}:`, error.message);
    }
  }
}

3. Sistema de Busca e Recuperação

class BuscadorNFe {
  constructor() {
    this.validanfe = new ValidaNFeSDK({
      apiKey: process.env.VALIDANFE_API_KEY
    });
  }

  async buscar(filtros) {
    const { 
      dataInicio, 
      dataFim, 
      cnpjEmitente, 
      valorMinimo, 
      valorMaximo,
      status,
      limite = 50,
      pagina = 1
    } = filtros;

    // Buscar no banco local primeiro (mais rápido)
    const query = this.construirQuery(filtros);
    const nfesLocais = await database.nfes
      .find(query)
      .limit(limite)
      .skip((pagina - 1) * limite)
      .sort({ data_emissao: -1 });

    // Enriquecer com URLs de download do GuardaNFe
    const nfesEnriquecidas = await Promise.all(
      nfesLocais.map(async (nfe) => {
        if (nfe.guardanfe_id) {
          try {
            const urlDownload = await this.obterUrlDownload(nfe.guardanfe_id);
            return { ...nfe.toObject(), url_download: urlDownload };
          } catch (error) {
            console.error(`Erro ao obter URL para NFe ${nfe.chave}:`, error.message);
            return nfe.toObject();
          }
        }
        return nfe.toObject();
      })
    );

    return {
      nfes: nfesEnriquecidas,
      total: await database.nfes.countDocuments(query),
      pagina,
      limite
    };
  }

  construirQuery(filtros) {
    const query = {};

    if (filtros.dataInicio || filtros.dataFim) {
      query.data_emissao = {};
      if (filtros.dataInicio) {
        query.data_emissao.$gte = new Date(filtros.dataInicio);
      }
      if (filtros.dataFim) {
        query.data_emissao.$lte = new Date(filtros.dataFim);
      }
    }

    if (filtros.cnpjEmitente) {
      query.cnpj_emitente = filtros.cnpjEmitente;
    }

    if (filtros.valorMinimo || filtros.valorMaximo) {
      query.valor_total = {};
      if (filtros.valorMinimo) {
        query.valor_total.$gte = parseFloat(filtros.valorMinimo);
      }
      if (filtros.valorMaximo) {
        query.valor_total.$lte = parseFloat(filtros.valorMaximo);
      }
    }

    if (filtros.status) {
      query.status = filtros.status;
    }

    return query;
  }

  async obterUrlDownload(arquivoId) {
    const info = await this.validanfe.guarda.obterInfo({ arquivoId });
    return info.urlDownload;
  }

  async baixarNFe(chaveNFe) {
    const nfe = await database.nfes.findOne({ chave: chaveNFe });
    
    if (!nfe || !nfe.guardanfe_id) {
      throw new Error('NFe não encontrada no armazenamento');
    }

    const xmlContent = await this.validanfe.guarda.baixar({
      arquivoId: nfe.guardanfe_id
    });

    // Registrar acesso para auditoria
    await this.registrarAcesso({
      chave_nfe: chaveNFe,
      usuario: 'sistema', // ou ID do usuário
      tipo_acesso: 'download',
      timestamp: new Date()
    });

    return {
      chave: chaveNFe,
      xml: xmlContent,
      metadata: nfe.toObject()
    };
  }
}

Casos de Uso Avançados

Organização por Categorias

  • Por Período Fiscal
  • Por Fornecedor
class OrganizadorPeriodoFiscal {
  async organizarPorAno(ano) {
    const nfes = await database.nfes.find({
      data_emissao: {
        $gte: new Date(`${ano}-01-01`),
        $lt: new Date(`${ano + 1}-01-01`)
      }
    });

    const organizacao = {
      ano: ano,
      trimestres: {},
      totais: {
        quantidade: nfes.length,
        valor_total: 0
      }
    };

    nfes.forEach(nfe => {
      const trimestre = Math.ceil((nfe.data_emissao.getMonth() + 1) / 3);
      
      if (!organizacao.trimestres[trimestre]) {
        organizacao.trimestres[trimestre] = {
          nfes: [],
          valor_total: 0
        };
      }

      organizacao.trimestres[trimestre].nfes.push({
        chave: nfe.chave,
        valor: nfe.valor_total,
        emitente: nfe.nome_emitente,
        data: nfe.data_emissao
      });

      organizacao.trimestres[trimestre].valor_total += nfe.valor_total;
      organizacao.totais.valor_total += nfe.valor_total;
    });

    return organizacao;
  }
}

Auditoria e Compliance

class AuditoriaArmazenamento {
  async gerarRelatorioAuditoria(periodo) {
    const relatorio = {
      periodo: periodo,
      estatisticas: await this.calcularEstatisticas(periodo),
      integridade: await this.verificarIntegridade(periodo),
      acessos: await this.relatarAcessos(periodo),
      conformidade: await this.verificarConformidade(periodo)
    };

    return relatorio;
  }

  async verificarIntegridade(periodo) {
    const nfes = await this.buscarNFesPeriodo(periodo);
    const verificacoes = [];

    for (const nfe of nfes) {
      if (nfe.guardanfe_id) {
        try {
          const info = await this.validanfe.guarda.obterInfo({
            arquivoId: nfe.guardanfe_id
          });

          const integridadeOk = info.hash === this.calcularHashXML(nfe.xml_content);
          
          verificacoes.push({
            chave_nfe: nfe.chave,
            integridade: integridadeOk ? 'OK' : 'FALHA',
            ultima_verificacao: new Date(),
            tamanho_arquivo: info.tamanho,
            hash_esperado: this.calcularHashXML(nfe.xml_content),
            hash_armazenado: info.hash
          });

        } catch (error) {
          verificacoes.push({
            chave_nfe: nfe.chave,
            integridade: 'ERRO',
            erro: error.message
          });
        }
      }
    }

    return {
      total_verificado: verificacoes.length,
      integras: verificacoes.filter(v => v.integridade === 'OK').length,
      com_falha: verificacoes.filter(v => v.integridade === 'FALHA').length,
      com_erro: verificacoes.filter(v => v.integridade === 'ERRO').length,
      detalhes: verificacoes
    };
  }

  async verificarConformidade(periodo) {
    const nfes = await this.buscarNFesPeriodo(periodo);
    
    const conformidade = {
      prazo_armazenamento: this.verificarPrazoArmazenamento(nfes),
      backup_geografico: await this.verificarBackupGeografico(nfes),
      criptografia: await this.verificarCriptografia(nfes),
      acesso_controlado: await this.verificarControleAcesso(periodo)
    };

    return conformidade;
  }
}

API REST para Acesso

// Endpoints para acesso ao armazenamento
app.get('/api/nfes/buscar', async (req, res) => {
  try {
    const buscador = new BuscadorNFe();
    const resultado = await buscador.buscar(req.query);
    res.json(resultado);
  } catch (error) {
    res.status(500).json({ erro: error.message });
  }
});

app.get('/api/nfes/:chave/download', async (req, res) => {
  try {
    const buscador = new BuscadorNFe();
    const nfe = await buscador.baixarNFe(req.params.chave);
    
    res.setHeader('Content-Type', 'application/xml');
    res.setHeader('Content-Disposition', `attachment; filename="${nfe.chave}.xml"`);
    res.send(nfe.xml);
  } catch (error) {
    res.status(404).json({ erro: error.message });
  }
});

app.get('/api/auditoria/:ano', async (req, res) => {
  try {
    const auditor = new AuditoriaArmazenamento();
    const relatorio = await auditor.gerarRelatorioAuditoria({
      inicio: new Date(`${req.params.ano}-01-01`),
      fim: new Date(`${req.params.ano}-12-31`)
    });
    
    res.json(relatorio);
  } catch (error) {
    res.status(500).json({ erro: error.message });
  }
});

Benefícios do Armazenamento Seguro

Conformidade Legal

10 anos de retenção conforme legislação fiscal brasileira
  • Backup automático com redundância
  • Logs de auditoria completos

Segurança Avançada

Criptografia AES-256 e controle de acesso granular
  • Múltiplas réplicas geográficas
  • Verificação de integridade automática

Performance

Busca instantânea em milhões de documentos
  • Indexação inteligente por metadados
  • Cache distribuído para downloads

Economia

70% de redução nos custos de armazenamento físico
  • Eliminação de servidores físicos
  • Redução de equipe de TI dedicada

Próximos Passos

1

Avaliar Volume

Determine a quantidade de NFe que precisa armazenar
2

Configurar API

Configure sua conta ValidaNFe e credentials da API GuardaNFe
3

Implementar Upload

Desenvolva o sistema de upload automático das NFe
4

Configurar Backup

Implemente rotinas de backup incremental
5

Testar Recuperação

Teste os procedimentos de busca e recuperação
6

Monitorar Compliance

Configure auditorias automáticas de conformidade

Consultoria em Armazenamento Fiscal

Precisa de ajuda para planejar sua estratégia de armazenamento? Nossa equipe especializada pode ajudar.