|
|
| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
| from datetime import date |
| from decimal import Decimal |
| from pathlib import Path |
| from typing import Optional |
|
|
| from src.fiscal.entities import Empresa, LancamentoContabil, PeriodoApuracao |
| from src.generators.sped_writer import ArquivoSPED, criar_registro |
|
|
| VERSAO_LEIAUTE = "010" |
|
|
|
|
| @dataclass |
| class PlanoContas: |
| codigo: str |
| descricao: str |
| nivel: int |
| tipo: str |
| natureza: str |
|
|
|
|
| @dataclass |
| class ConfigECD: |
| versao: str = VERSAO_LEIAUTE |
| finalidade: str = "G" |
| hash_anterior: str = "" |
| tipo_escrituracao: str = "G" |
| indicador_sit_especial: str = "" |
|
|
|
|
| class GeradorECD: |
| |
|
|
| def __init__( |
| self, |
| periodo: PeriodoApuracao, |
| plano_contas: Optional[list[PlanoContas]] = None, |
| cfg: Optional[ConfigECD] = None, |
| contador: Optional[object] = None, |
| ): |
| self.periodo = periodo |
| self.plano_contas = plano_contas or self._plano_contas_padrao() |
| self.cfg = cfg or ConfigECD() |
| self.contador = contador |
| self._arquivo = ArquivoSPED( |
| f"ECD_{periodo.empresa.cnpj}_{periodo.data_inicio.year}.txt" |
| ) |
|
|
| def _plano_contas_padrao(self) -> list[PlanoContas]: |
| return [ |
| PlanoContas("1", "ATIVO", 1, "S", "D"), |
| PlanoContas("1.1", "ATIVO CIRCULANTE", 2, "S", "D"), |
| PlanoContas("1.1.1", "CAIXA E EQUIVALENTES", 3, "S", "D"), |
| PlanoContas("1.1.1.01", "CAIXA", 4, "A", "D"), |
| PlanoContas("1.1.1.02", "BANCOS CONTA MOVIMENTO", 4, "A", "D"), |
| PlanoContas("1.1.2", "CONTAS A RECEBER", 3, "S", "D"), |
| PlanoContas("1.1.2.01", "CLIENTES", 4, "A", "D"), |
| PlanoContas("1.1.3", "ESTOQUES", 3, "S", "D"), |
| PlanoContas("1.1.3.01", "MERCADORIAS", 4, "A", "D"), |
| PlanoContas("1.2", "ATIVO NÃO CIRCULANTE", 2, "S", "D"), |
| PlanoContas("1.2.1", "IMOBILIZADO", 3, "S", "D"), |
| PlanoContas("1.2.1.01", "MÓVEIS E UTENSÍLIOS", 4, "A", "D"), |
| PlanoContas("1.2.1.02", "EQUIPAMENTOS", 4, "A", "D"), |
| PlanoContas("2", "PASSIVO", 1, "S", "C"), |
| PlanoContas("2.1", "PASSIVO CIRCULANTE", 2, "S", "C"), |
| PlanoContas("2.1.1", "FORNECEDORES", 3, "S", "C"), |
| PlanoContas("2.1.1.01", "FORNECEDORES NACIONAIS", 4, "A", "C"), |
| PlanoContas("2.1.2", "OBRIGAÇÕES FISCAIS", 3, "S", "C"), |
| PlanoContas("2.1.2.01", "ICMS A RECOLHER", 4, "A", "C"), |
| PlanoContas("2.1.2.02", "PIS A RECOLHER", 4, "A", "C"), |
| PlanoContas("2.1.2.03", "COFINS A RECOLHER", 4, "A", "C"), |
| PlanoContas("2.1.2.04", "IRPJ A RECOLHER", 4, "A", "C"), |
| PlanoContas("2.1.2.05", "CSLL A RECOLHER", 4, "A", "C"), |
| PlanoContas("2.1.3", "OBRIGAÇÕES TRABALHISTAS", 3, "S", "C"), |
| PlanoContas("2.1.3.01", "SALÁRIOS A PAGAR", 4, "A", "C"), |
| PlanoContas("2.2", "PASSIVO NÃO CIRCULANTE", 2, "S", "C"), |
| PlanoContas("3", "PATRIMÔNIO LÍQUIDO", 1, "S", "C"), |
| PlanoContas("3.1", "CAPITAL SOCIAL", 2, "S", "C"), |
| PlanoContas("3.1.01", "CAPITAL SUBSCRITO E INTEGRALIZADO", 3, "A", "C"), |
| PlanoContas("3.2", "RESERVAS E LUCROS", 2, "S", "C"), |
| PlanoContas("3.2.01", "LUCROS ACUMULADOS", 3, "A", "C"), |
| PlanoContas("4", "RECEITAS", 1, "S", "C"), |
| PlanoContas("4.1", "RECEITA OPERACIONAL BRUTA", 2, "S", "C"), |
| PlanoContas("4.1.01", "VENDAS DE MERCADORIAS", 3, "A", "C"), |
| PlanoContas("4.1.02", "PRESTAÇÃO DE SERVIÇOS", 3, "A", "C"), |
| PlanoContas("4.2", "DEDUÇÕES DA RECEITA", 2, "S", "D"), |
| PlanoContas("4.2.01", "DEVOLUÇÕES DE VENDAS", 3, "A", "D"), |
| PlanoContas("4.2.02", "IMPOSTOS SOBRE VENDAS", 3, "A", "D"), |
| PlanoContas("5", "CUSTOS", 1, "S", "D"), |
| PlanoContas("5.1", "CUSTO DE MERCADORIAS VENDIDAS", 2, "S", "D"), |
| PlanoContas("5.1.01", "CMV - MERCADORIAS", 3, "A", "D"), |
| PlanoContas("6", "DESPESAS OPERACIONAIS", 1, "S", "D"), |
| PlanoContas("6.1", "DESPESAS ADMINISTRATIVAS", 2, "S", "D"), |
| PlanoContas("6.1.01", "SALÁRIOS E ORDENADOS", 3, "A", "D"), |
| PlanoContas("6.1.02", "ENCARGOS SOCIAIS", 3, "A", "D"), |
| PlanoContas("6.1.03", "ALUGUÉIS", 3, "A", "D"), |
| PlanoContas("6.1.04", "SERVIÇOS DE TERCEIROS", 3, "A", "D"), |
| PlanoContas("6.2", "DESPESAS COMERCIAIS", 2, "S", "D"), |
| PlanoContas("6.2.01", "FRETES E CARRETOS", 3, "A", "D"), |
| PlanoContas("6.2.02", "COMISSÕES", 3, "A", "D"), |
| PlanoContas("6.3", "DESPESAS FINANCEIRAS", 2, "S", "D"), |
| PlanoContas("6.3.01", "JUROS E ENCARGOS", 3, "A", "D"), |
| ] |
|
|
| def _bloco_0(self) -> None: |
| emp = self.periodo.empresa |
| end = emp.endereco |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0000", |
| self.cfg.versao, |
| self.cfg.tipo_escrituracao, |
| "G", |
| emp.cnpj, |
| emp.regime_tributario.value, |
| emp.razao_social, |
| end.uf.value, |
| emp.ie, |
| end.cod_municipio, |
| self.cfg.indicador_sit_especial, |
| "", |
| self.periodo.data_inicio, |
| self.periodo.data_fim, |
| "N", |
| self.cfg.finalidade, |
| "1", |
| "", |
| "", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro("0001", "0")) |
|
|
| |
| if self.contador: |
| c = self.contador |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0007", |
| c.cpf, |
| "2", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0990", self._arquivo.total_linhas() + 1 |
| )) |
|
|
| def _bloco_i(self) -> None: |
| |
| self._arquivo.adicionar_linha_raw(criar_registro("I001", "0")) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I010", |
| "G", |
| "", |
| "", |
| "", |
| "", |
| "", |
| self.periodo.data_inicio, |
| self.periodo.data_fim, |
| "", |
| "", |
| "", |
| "1", |
| "1", |
| "1", |
| "1", |
| "1", |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I020", |
| "EMPRESA", |
| self.periodo.empresa.cnpj, |
| "1", |
| "1", |
| )) |
|
|
| |
| for conta in self.plano_contas: |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I050", |
| conta.codigo, |
| conta.codigo, |
| conta.nivel, |
| conta.tipo, |
| conta.natureza, |
| conta.descricao, |
| "", |
| "", |
| "", |
| )) |
|
|
| |
| for conta in [c for c in self.plano_contas if c.tipo == "A"]: |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I100", |
| conta.codigo, |
| "0", |
| Decimal("0"), |
| Decimal("0"), |
| Decimal("0"), |
| "0", |
| Decimal("0"), |
| )) |
|
|
| |
| for i, lanc in enumerate(self.periodo.lancamentos, 1): |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I200", |
| str(i).zfill(6), |
| lanc.data, |
| "01", |
| lanc.historico, |
| Decimal("0"), |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I250", |
| lanc.debito_conta, |
| "D", |
| lanc.valor, |
| "01", |
| lanc.historico, |
| "", |
| "", |
| )) |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I250", |
| lanc.credito_conta, |
| "C", |
| lanc.valor, |
| "01", |
| lanc.historico, |
| "", |
| "", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "I990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_j(self) -> None: |
| |
| self._arquivo.adicionar_linha_raw(criar_registro("J001", "0")) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "J005", |
| self.periodo.data_fim, |
| "0", |
| "0", |
| "0", |
| )) |
|
|
| |
| for conta in self.plano_contas[:10]: |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "J100", |
| conta.codigo, |
| conta.codigo, |
| conta.descricao, |
| conta.nivel, |
| conta.tipo, |
| conta.natureza, |
| Decimal("0"), |
| "0", |
| Decimal("0"), |
| "0", |
| "", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "J990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_9(self) -> None: |
| self._arquivo.adicionar_linha_raw(criar_registro("9001", "0")) |
| qt = self._arquivo.total_linhas() + 3 |
| self._arquivo.adicionar_linha_raw(criar_registro("9900", "0000", "1")) |
| self._arquivo.adicionar_linha_raw(criar_registro("9990", qt)) |
| self._arquivo.adicionar_linha_raw(criar_registro("9999", qt + 1)) |
|
|
| def gerar(self, diretorio: str | Path = ".") -> Path: |
| self._bloco_0() |
| self._bloco_i() |
| self._bloco_j() |
| self._bloco_9() |
| return self._arquivo.salvar(diretorio) |
|
|