|
|
| from __future__ import annotations |
|
|
| from dataclasses import dataclass, field |
| from datetime import date |
| from decimal import Decimal |
| from pathlib import Path |
| from typing import Optional |
|
|
| from src.calculators.irpj_csll import ( |
| ResultadoCSLL, |
| ResultadoIRPJ, |
| calcular_csll_lucro_presumido, |
| calcular_csll_lucro_real, |
| calcular_irpj_lucro_presumido, |
| calcular_irpj_lucro_real, |
| ) |
| from src.fiscal.entities import Empresa, PeriodoApuracao, RegimeTributario |
| from src.generators.sped_writer import ArquivoSPED, criar_registro |
|
|
| VERSAO_LEIAUTE = "009" |
|
|
|
|
| @dataclass |
| class DadosLucroReal: |
| lucro_contabil: Decimal |
| adicoes: Decimal = Decimal("0") |
| exclusoes: Decimal = Decimal("0") |
| compensacoes_prejuizo: Decimal = Decimal("0") |
| incentivos_fiscais: Decimal = Decimal("0") |
| csll_indedutivel: Decimal = Decimal("0") |
| multas_indedutíveis: Decimal = Decimal("0") |
| provisoes_indedutíveis: Decimal = Decimal("0") |
|
|
|
|
| @dataclass |
| class DadosLucroPresumido: |
| receita_venda_mercadorias: Decimal = Decimal("0") |
| receita_prestacao_servicos: Decimal = Decimal("0") |
| receita_outras_atividades: Decimal = Decimal("0") |
| ganhos_capital: Decimal = Decimal("0") |
| rendimentos_aplicacoes: Decimal = Decimal("0") |
| outras_receitas: Decimal = Decimal("0") |
| atividade_principal: str = "venda_mercadorias" |
|
|
|
|
| @dataclass |
| class ConfigECF: |
| versao: str = VERSAO_LEIAUTE |
| finalidade: str = "0" |
| situacao_especial: str = "" |
| ano_referencia: int = field(default_factory=lambda: date.today().year - 1) |
|
|
|
|
| class GeradorECF: |
| """ |
| Gera o arquivo ECF conforme leiaute da Receita Federal. |
| Obrigação anual: Lucro Real, Lucro Presumido e Lucro Arbitrado. |
| Prazo: último dia útil de julho do ano seguinte. |
| """ |
|
|
| def __init__( |
| self, |
| empresa: Empresa, |
| ano: int, |
| dados_lr: Optional[DadosLucroReal] = None, |
| dados_lp: Optional[DadosLucroPresumido] = None, |
| cfg: Optional[ConfigECF] = None, |
| contador: Optional[object] = None, |
| ): |
| self.empresa = empresa |
| self.ano = ano |
| self.dados_lr = dados_lr |
| self.dados_lp = dados_lp |
| self.cfg = cfg or ConfigECF(ano_referencia=ano) |
| self.contador = contador |
| self._arquivo = ArquivoSPED(f"ECF_{empresa.cnpj}_{ano}.txt") |
|
|
| def _bloco_0(self) -> None: |
| emp = self.empresa |
| end = emp.endereco |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0000", |
| self.cfg.versao, |
| self.cfg.finalidade, |
| emp.cnpj, |
| emp.regime_tributario.value, |
| emp.razao_social, |
| end.uf.value, |
| emp.ie, |
| end.cod_municipio, |
| self.cfg.situacao_especial, |
| "", |
| date(self.ano, 1, 1), |
| date(self.ano, 12, 31), |
| "N", |
| self.cfg.finalidade, |
| "1", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro("0001", "0")) |
|
|
| |
| ind_sit_ini = "0" |
| if emp.regime_tributario == RegimeTributario.LUCRO_REAL: |
| forma_trib = "3" |
| elif emp.regime_tributario == RegimeTributario.LUCRO_PRESUMIDO: |
| forma_trib = "6" |
| else: |
| forma_trib = "6" |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0010", |
| ind_sit_ini, |
| forma_trib, |
| "0", |
| "N", |
| "N", |
| "N", |
| "N", |
| "0", |
| "N", |
| "N", |
| "N", |
| "N", |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0020", |
| "0", |
| "0", |
| "0", |
| "0", |
| "0", |
| "0", |
| "1", |
| )) |
|
|
| if self.contador: |
| c = self.contador |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0930", |
| c.nome, |
| c.cpf, |
| c.crc, |
| c.cnpj_escritorio if hasattr(c, "cnpj_escritorio") else "", |
| c.contato.email if hasattr(c, "contato") else "", |
| c.contato.telefone if hasattr(c, "contato") else "", |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "0990", self._arquivo.total_linhas() + 1 |
| )) |
|
|
| def _bloco_c(self) -> None: |
| """Bloco C — Identificação e Caracterização da PJ.""" |
| self._arquivo.adicionar_linha_raw(criar_registro("C001", "0")) |
|
|
| emp = self.empresa |
| end = emp.endereco |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "C010", |
| emp.cnpj, |
| emp.razao_social, |
| emp.nome_fantasia or emp.razao_social, |
| end.logradouro, |
| end.numero, |
| end.complemento, |
| end.bairro, |
| end.cep, |
| end.municipio, |
| end.uf.value, |
| emp.contato.telefone, |
| emp.contato.email, |
| emp.ie, |
| end.cod_municipio, |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "C050", |
| "6201-5/00", |
| "1", |
| date(self.ano, 1, 1), |
| date(self.ano, 12, 31), |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "C990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_e(self) -> None: |
| """Bloco E — IRPJ e CSLL por tipo de receita.""" |
| self._arquivo.adicionar_linha_raw(criar_registro("E001", "0")) |
|
|
| |
| receita_total = Decimal("0") |
| if self.dados_lp: |
| receita_total = ( |
| self.dados_lp.receita_venda_mercadorias |
| + self.dados_lp.receita_prestacao_servicos |
| + self.dados_lp.receita_outras_atividades |
| ) |
| elif self.dados_lr: |
| pass |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "E010", |
| receita_total, |
| Decimal("0"), |
| Decimal("0"), |
| Decimal("0"), |
| Decimal("0"), |
| Decimal("0"), |
| receita_total, |
| Decimal("0"), |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "E990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_l(self, irpj: ResultadoIRPJ, csll: ResultadoCSLL) -> None: |
| """Bloco L — Lucro Real (LALUR/LACS).""" |
| self._arquivo.adicionar_linha_raw(criar_registro("L001", "0")) |
|
|
| if not self.dados_lr: |
| self._arquivo.adicionar_linha_raw(criar_registro("L990", "2")) |
| return |
|
|
| d = self.dados_lr |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L010", |
| date(self.ano, 1, 1), |
| date(self.ano, 12, 31), |
| "0", |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L020", |
| d.lucro_contabil, |
| d.lucro_contabil, |
| d.csll_indedutivel, |
| d.lucro_contabil + d.csll_indedutivel, |
| d.adicoes, |
| d.exclusoes, |
| irpj.lucro_real_ajustado, |
| irpj.lucro_real_ajustado - irpj.base_calculo, |
| irpj.base_calculo, |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L030", |
| d.lucro_contabil, |
| d.adicoes, |
| d.exclusoes, |
| csll.base_calculo, |
| csll.base_calculo, |
| csll.base_calculo, |
| )) |
|
|
| |
| if d.multas_indedutíveis > 0: |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L100", "054", "Multas Indedutíveis", d.multas_indedutíveis |
| )) |
| if d.provisoes_indedutíveis > 0: |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L100", "012", "Provisões Indedutíveis", d.provisoes_indedutíveis |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "L990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_n(self, irpj: ResultadoIRPJ, csll: ResultadoCSLL) -> None: |
| """Bloco N — Cálculo do IRPJ e da CSLL.""" |
| self._arquivo.adicionar_linha_raw(criar_registro("N001", "0")) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "N010", |
| date(self.ano, 1, 1), |
| date(self.ano, 12, 31), |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "N620", |
| irpj.base_calculo, |
| irpj.valor_base, |
| irpj.base_adicional, |
| irpj.valor_adicional, |
| irpj.valor_irpj_total, |
| irpj.incentivos_fiscais, |
| Decimal("0"), |
| irpj.irpj_a_recolher, |
| Decimal("0"), |
| Decimal("0"), |
| )) |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "N630", |
| csll.base_calculo, |
| csll.aliquota, |
| csll.valor_csll, |
| Decimal("0"), |
| csll.csll_a_recolher, |
| Decimal("0"), |
| csll.csll_a_recolher, |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "N990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_p(self, irpj: ResultadoIRPJ, csll: ResultadoCSLL) -> None: |
| """Bloco P — Lucro Presumido.""" |
| self._arquivo.adicionar_linha_raw(criar_registro("P001", "0")) |
|
|
| if not self.dados_lp: |
| self._arquivo.adicionar_linha_raw(criar_registro("P990", "2")) |
| return |
|
|
| d = self.dados_lp |
| |
| for trim, (di, df) in enumerate([ |
| (date(self.ano, 1, 1), date(self.ano, 3, 31)), |
| (date(self.ano, 4, 1), date(self.ano, 6, 30)), |
| (date(self.ano, 7, 1), date(self.ano, 9, 30)), |
| (date(self.ano, 10, 1), date(self.ano, 12, 31)), |
| ], 1): |
| |
| self._arquivo.adicionar_linha_raw(criar_registro("P010", di, df)) |
|
|
| |
| fator = Decimal("0.25") |
| rec_merc = d.receita_venda_mercadorias * fator |
| rec_serv = d.receita_prestacao_servicos * fator |
| rec_outras = d.receita_outras_atividades * fator |
|
|
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "P020", |
| rec_merc, |
| rec_serv, |
| rec_outras, |
| d.ganhos_capital * fator, |
| d.rendimentos_aplicacoes * fator, |
| d.outras_receitas * fator, |
| )) |
|
|
| |
| lp_merc = rec_merc * Decimal("0.08") |
| lp_serv = rec_serv * Decimal("0.32") |
| lp_outras = rec_outras * Decimal("0.08") |
| lp_total = lp_merc + lp_serv + lp_outras + d.ganhos_capital * fator + d.rendimentos_aplicacoes * fator |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "P030", |
| lp_merc, |
| lp_serv, |
| lp_outras, |
| lp_total, |
| lp_total, |
| )) |
|
|
| |
| lp_csll_merc = rec_merc * Decimal("0.12") |
| lp_csll_serv = rec_serv * Decimal("0.32") |
| lp_csll_total = lp_csll_merc + lp_csll_serv + d.ganhos_capital * fator |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "P100", |
| lp_csll_merc, |
| lp_csll_serv, |
| lp_csll_total, |
| lp_csll_total, |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "P990", self._arquivo.total_linhas() |
| )) |
|
|
| def _bloco_y(self) -> None: |
| """Bloco Y — Informações Gerais.""" |
| self._arquivo.adicionar_linha_raw(criar_registro("Y001", "0")) |
|
|
| |
| |
| |
| |
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "Y600", |
| self.empresa.cnpj, |
| "", |
| "SOCIO", |
| Decimal("100"), |
| date(self.ano, 1, 1), |
| date(self.ano, 12, 31), |
| )) |
|
|
| self._arquivo.adicionar_linha_raw(criar_registro( |
| "Y990", 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: |
| emp = self.empresa |
| dados_lr = self.dados_lr |
| dados_lp = self.dados_lp |
|
|
| if emp.regime_tributario == RegimeTributario.LUCRO_REAL and dados_lr: |
| irpj = calcular_irpj_lucro_real( |
| lucro_antes_ir=dados_lr.lucro_contabil, |
| adicoes=dados_lr.adicoes, |
| exclusoes=dados_lr.exclusoes, |
| compensacoes_prejuizo=dados_lr.compensacoes_prejuizo, |
| incentivos_fiscais=dados_lr.incentivos_fiscais, |
| ) |
| csll = calcular_csll_lucro_real( |
| lucro_antes_csll=dados_lr.lucro_contabil, |
| adicoes=dados_lr.adicoes, |
| exclusoes=dados_lr.exclusoes, |
| ) |
| else: |
| d = dados_lp or DadosLucroPresumido() |
| receita = ( |
| d.receita_venda_mercadorias |
| + d.receita_prestacao_servicos |
| + d.receita_outras_atividades |
| ) |
| irpj = calcular_irpj_lucro_presumido( |
| receita_bruta=receita, |
| outras_receitas=d.ganhos_capital + d.rendimentos_aplicacoes + d.outras_receitas, |
| atividade=d.atividade_principal, |
| ) |
| csll = calcular_csll_lucro_presumido( |
| receita_bruta=receita, |
| outras_receitas=d.ganhos_capital + d.rendimentos_aplicacoes + d.outras_receitas, |
| atividade="comercio_industria" if d.atividade_principal == "venda_mercadorias" else "servicos_em_geral", |
| ) |
|
|
| self._bloco_0() |
| self._bloco_c() |
| self._bloco_e() |
|
|
| if emp.regime_tributario == RegimeTributario.LUCRO_REAL: |
| self._bloco_l(irpj, csll) |
| else: |
| self._arquivo.adicionar_linha_raw(criar_registro("L001", "1")) |
| self._arquivo.adicionar_linha_raw(criar_registro("L990", "2")) |
| self._bloco_p(irpj, csll) |
|
|
| self._bloco_n(irpj, csll) |
| self._bloco_y() |
| self._bloco_9() |
|
|
| return self._arquivo.salvar(diretorio) |
|
|