Pular para conteúdo

ECD — Regras Gerais de Geração

Mecanismo de Habilitação de Registros

Todos os registros da ECD passam pela verificação:

def _registro_em_uso(self, registro):
    return registro in self.company_id.l10n_br_sped_ecd_registros.mapped('name')

Como funciona

Aspecto Detalhe
Campo da empresa l10n_br_sped_ecd_registros (Many2many → l10n_br_ciel_it.sped.registro)
Menu Empresa → aba Localização BR → Registros SPED Contábil (ECD)
Efeito Se o registro não está na lista, o método retorna imediatamente sem gerar nada
Tipo de regra ⚙️ Parametrização

O que acontece quando um registro não está habilitado

Registro Impacto se desabilitado
0000 Arquivo sem abertura — invalida todo o SPED
0001 Bloco 0 sem indicador de dados
0007 Sem inscrição estadual no arquivo
I050 Sem plano de contas — invalida todo o SPED
I155 Sem balancetes mensais
I200/I250 Sem lançamentos — ECD fica sem Livro Diário
I355 Sem saldos de resultado
J100 Sem Balanço Patrimonial
J150 Sem DRE
J930 Sem signatário — invalida a ECD

Regra funcional: A maioria dos registros é obrigatória para uma ECD válida. Desabilitar registros é útil apenas para depuração ou geração parcial de teste.

Riscos de configuração incorreta

Risco Consequência Como prevenir
Nenhum registro habilitado Arquivo vazio — rejeição no PVA Verificar lista de registros na empresa
Registro 0000 desabilitado Arquivo sem cabeçalho Sempre manter habilitado
I050 desabilitado sem I155 Balancete sem plano de contas Habilitar ambos ou nenhum
J930 desabilitado Sem signatário Sempre manter habilitado

Seleção de Contas e Grupos

O método _get_account_and_group_ids() (linha 107) é executado antes de qualquer registro, para determinar quais contas e grupos serão processados.

Lógica de seleção

flowchart TD
    A["_get_account_and_group_ids()"] --> B["Consultar saldos ANTES do período"]
    B --> C["read_group: contas com date < date_ini, posted"]
    C --> D{"saldo_inicial ≠ 0?"}
    D -->|"Sim"| E["Incluir conta + toda a hierarquia de grupos"]
    D -->|"Não"| F["Ignorar"]
    A --> G["Consultar movimentações DO período"]
    G --> H["read_group: contas com date_ini ≤ date ≤ date_fim, posted"]
    H --> I{"conta encontrada?"}
    I -->|"Sim"| E
    I -->|"Não"| F
    E --> J["Retorna: account_ids, group_ids"]

Regras detalhadas

Critério Filtro Tipo de regra
Empresa company_id = empresa selecionada 🔒 Fixo
Status move_id.state = 'posted' 🔒 Fixo — somente lançamentos postados
Saldo inicial ≠ 0 debit - credit ≠ 0 antes de date_ini 🧮 Calculado
Movimentação no período Qualquer debit ou credit entre date_ini e date_fim 🧮 Calculado
Hierarquia de grupos Para cada conta incluída, percorre group_id → parent_id até a raiz 🧮 Automático

Consequência: Uma conta que nunca teve saldo e não teve movimentação no período NÃO aparece na ECD. Isso é correto e intencional — a ECD só deve conter contas utilizadas.

Por que uma conta pode não aparecer

Motivo Como verificar
Conta nunca teve movimentação Verificar se há algum account.move.line para essa conta
Movimentações não postadas Verificar move_id.state — deve ser 'posted'
Conta de outra empresa Verificar company_id da conta
Saldo zerado e sem movimento Correto — comportamento esperado

Tratamento do Período

Período anual

O período da ECD é definido pelos campos date_ini e date_fim do wizard:

Campo Uso típico Efeito
date_ini 01/01/AAAA Define o início dos movimentos e saldos
date_fim 31/12/AAAA Define o fim dos movimentos e demonstrativos

Geração mensal automática (I150)

O sistema divide automaticamente o período anual em sub-períodos mensais para os registros I150/I155:

gerar_range_mensal(data_inicio, data_fim)  [(01/Jan, 31/Jan), (01/Fev, 28/Fev), ..., (01/Dez, 31/Dez)]

Cada par (primeiro_dia, último_dia) gera um registro I150 com seus I155 correspondentes.


Cálculo de Saldos

A ECD utiliza o conceito de saldo inicial, movimentação e saldo final em vários registros:

Fórmula padrão

Saldo Inicial = sum(debit) - sum(credit)  ONDE date < data_inicio AND posted
Débitos Mês   = sum(debit)                ONDE data_inicio ≤ date ≤ data_fim AND posted
Créditos Mês  = sum(credit)               ONDE data_inicio ≤ date ≤ data_fim AND posted
Saldo Final   = Saldo Inicial + Débitos - Créditos

Indicador D/C

Valor Significado Quando
'D' Débito Saldo > 0 (natureza devedora)
'C' Crédito Saldo ≤ 0 (natureza credora)

Regra fixa no código: 'D' if valor > 0 else 'C'. O valor absoluto é gravado no campo numérico.


Lançamentos Contábeis Aceitos

Filtro padrão para lançamentos (I200)

Critério Condição
Empresa company_id = empresa
Período date_ini ≤ date ≤ date_fim
Status state = 'posted'
Valor sum(line_ids.debit) > 0 — ignora lançamentos com valor total zero

Classificação do lançamento

IND_LCTO Condição Significado
'N' is_encerramento = False Lançamento normal
'E' is_encerramento = True Lançamento de encerramento do exercício

Campo is_encerramento: Boolean em account.move (linha 640 de account.py). Marcado automaticamente pelo módulo de Encerramento Contábil.


Serialização do Arquivo

Após gerar todos os registros, o método gerar_sped() serializa:

to_write["arquivo"] = str(uuid.uuid4())[:8] + "_%s_%s.TXT" % (date_ini, date_fim)
to_write["name"] = to_write["arquivo"][:-4]
to_write["situacao"] = "PROCESSADO"
to_write["arquivo_sped_ecd"] = base64.b64encode(_arq.getstring().encode('utf-8'))
Saída Formato Exemplo
Nome do arquivo {uuid8}_{DDMMAAAA}_{DDMMAAAA}.TXT a1b2c3d4_01012025_31122025.TXT
Protocolo Idem sem .TXT a1b2c3d4_01012025_31122025
Situação Texto fixo PROCESSADO
Arquivo Base64 do TXT completo Binário para download

Dependências de Cadastro — Consolidado

Entidade Campo Registros que usam Obrigatório?
res.company l10n_br_cnpj 0000, I030 Sim
res.company name 0000, I030, J900 Sim
res.company state_id.code 0000, 0007 Sim
res.company l10n_br_ie 0000, 0007 Sim
res.company l10n_br_municipio_id 0000, I030 Sim
res.company l10n_br_im 0000 Não (fallback vazio)
res.company l10n_br_nire I030 Não (fallback vazio)
res.company l10n_br_data_abertura I030 Recomendado
res.company l10n_br_contador_partner_id J930 Sim (bloqueia)
res.company l10n_br_sped_ecd_registros Todos Sim (controle)
account.account group_id I050, I155, I200 Sim (bloqueia)
account.account l10n_br_conta_referencial I051 Sim* (exceto cod_nat 05/09)
account.account l10n_br_cod_nat I050, I355, J100, J150 Recomendado
account.account code I050, I155, I250, I355 Sim (Odoo nativo)
account.group code_prefix_start I050, I052, J100, J150 Sim (Odoo nativo)
account.group l10n_br_cod_nat J100, J150 Sim (filtro)
account.group parent_id I050, J100, J150 Recomendado (hierarquia)
res.partner (contador) name, l10n_br_cpf, l10n_br_crc J930 Sim

Referências