diff --git a/l10n_br_sped_base/models/sped_mixin.py b/l10n_br_sped_base/models/sped_mixin.py index 38587e6e6a74..a1fe02e8dd63 100644 --- a/l10n_br_sped_base/models/sped_mixin.py +++ b/l10n_br_sped_base/models/sped_mixin.py @@ -16,6 +16,7 @@ "ecf": "9", "efd_icms_ipi": "17", "efd_pis_cofins": "6", + "fake": "9", # tests; similar to ecd } MAX_REGISTER_NAME = 40 diff --git a/l10n_br_sped_base/tests/__init__.py b/l10n_br_sped_base/tests/__init__.py new file mode 100644 index 000000000000..1d2a10513dfe --- /dev/null +++ b/l10n_br_sped_base/tests/__init__.py @@ -0,0 +1 @@ +from . import test_sped_base diff --git a/l10n_br_sped_base/tests/demo_fake.txt b/l10n_br_sped_base/tests/demo_fake.txt new file mode 100644 index 000000000000..162c2cba425f --- /dev/null +++ b/l10n_br_sped_base/tests/demo_fake.txt @@ -0,0 +1,97 @@ +|0000|LECD|01012021|31122021|EMPRESA TESTE LIVRO RAZAO AUXILIAR|11111111000191|ES|ISENTO|3205200|1256535||0|0|0||0|1||N|N|0|0|1| +|0001|0| +|0007|00|| +|0990|4| +|I001|0| +|I010|Z|9.00| +|I012|1|LIVRO DIÁRIO COM ESCRITURAÇÃO RESUMIDA|0|| +|I015|1.01.01.01| +|I015|1.05.05.05| +|I015|1.07.07.07| +|I015|1.09.09.09| +|I030|TERMO DE ABERTURA|1|RAZAO_AUXILIAR_DAS_SUBCONTAS|99|EMPRESA TESTE LIVRO RAZAO AUXILIAR||11111111000191|15021978||BRASILIA|31122021| +|I050|01012015|01|S|1|1.01.01.01||Ativo Sintética 1| +|I050|01012015|01|S|1|1.05.05.05||Ativo Sintética 2| +|I050|01012015|01|S|1|1.07.07.07||Ativo Sintética 3| +|I050|01012015|01|S|1|1.09.09.09||Ativo Sintética 4| +|I510|NAT_SUB_CNT|NATUREZA DA SUBCONTA CORRELATA|C|2||11| +|I510|COD_SUB_CNT|CÓDIGO DA SUBCONTA VINCULADA AO ITEM|C|20||11| +|I510|COD_CCUS|CÓDIGO DO CENTRO DE CUSTOS VINCULADO AO ITEM|C|20||11| +|I510|CNPJ_INVTD|CNPJ DA INVESTIDA|N|14||11| +|I510|COD_PATR_ITEM|CÓDIGO DE IDENTIFICAÇÃO DO ITEM|C|10||11| +|I510|QTD|QUANTIDADE|N|15||11| +|I510|IDENT_ITEM|IDENTIFICADOR DO ITEM|C|30||11| +|I510|DESCR_ITEM|DESCRICAO DO ITEM|C|50||11| +|I510|DATA_RECT_INI|DATA DO RECONHECIMENTO CONTÁBIL INICIAL DO ITEM|C|8||11| +|I510|SLD_ITEM_INI|SALDO INICIAL DA CONTA CONTÁBIL|N|19|2|11| +|I510|IND_SLD_ITEM_INI|INDICADOR DO SALDO INICIAL|C|1||11| +|I510|REAL_ITEM|PARCELA DE REALIZAÇÃO DO ITEM|N|19|2|11| +|I510|IND_REAL_ITEM|INDICADOR DA PARCELA DE REALIZAÇÃO|C|1||11| +|I510|SLD_ITEM_FIN|SALDO FINAL DA CONTA CONTÁBIL QUE REGISTRA O ITEM|N|19|2|11| +|I510|IND_SLD_ITEM_FIN|INDICADOR DO SALDO FINAL|C|1||11| +|I510|SLD_SCNT_INI|SALDO INICIAL DA SUBCONTA REPRESENTATIVA DO ITEM|N|19|2|11| +|I510|IND_SLD_SCNT_INI|INDICADOR DO SALDO INICIAL|C|1||11| +|I510|DEB_SCNT|VALOR REGISTRADO A DEBITO NA SUBCONTA|N|19|2|11| +|I510|CRED_SCNT|VALOR REGISTRADO A CREDITO NA SUBCONTA|N|19|2|11| +|I510|SLD_SCNT_FIN|SALDO FINAL DA SUBCONTA REPRESENTATIVA DO ITEM|N|19|2|11| +|I510|IND_SLD_SCNT_FIN|INDICADOR DO SALDO FINAL|C|1||11| +|I510|DATA_LCTO|DATA DO LANÇAMENTO CONTÁBIL|C|8||11| +|I510|NR_LCTO|IDENTIFICAÇÃO DO LANÇAMENTO|C|20||11| +|I510|VLR_LCTO|VALOR DO LANÇAMENTO|N|19|2|11| +|I510|IND_VLR_LCTO|INDICADOR DO VALOR DO LANÇAMENTO|C|1||11| +|I510|IND_ADOC_INI|INDICADOR DA ADOÇÃOO INICIAL|C|1||11| +|I550|70|1.01.01.01|||AA|1|MATRC CARTORIO AA|TERRENO RUA AA|01042019|100000,00|D|0|D|100000,00|D|0|D|10000,00|0|10000,00|D|15012021|AV700|10000,00|D|2| +|I550|70|1.01.01.01|X77||BB|1|MATRC CARTORIO AB|TERRENO RUA BB|02062019|80000,00|D|0|D|80000,00|D|0|D|0|10000,00|10000,00|C|15012021|AV701|10000,00|C|2| +|I550|70|1.01.01.01|X77||BB|1|MATRC CARTORIO AB|TERRENO RUA BB|02062019|80000,00|D|0|D|80000,00|D|10000,00|C|0|40000,00|50000,00|C|18012021|AV810|43000,00|C|2| +|I550|70|1.01.01.01|||CC|1|MATRC CARTORIO AC|TERRENO RUA CC|02012019|30000,00|D|0|D|30000,00|D|0|C|0|3000,00|3000,00|C|18012021|AV810|43000,00|C|2| +|I550|70|1.01.01.01|X77||BB|1|MATRC CARTORIO AB|TERRENO RUA BB|02062019|80000,00|D|0|D|80000,00|D|50000,00|C|50000,00|0|0|C|22012021|AV990|50000,00|D|2| +|I555|70|1.01.01.01|||AA|1|MATRIC CARTORIO AA|TERRENO RUA AA|01042019|100000,00|D|0|D|100000,00|D|0|D|10000,00|0|10000,00|D|||||| +|I555|70|1.01.01.01|X77||BB|0|MATRIC CARTORIO AB|TERRENO RUA AB|02062019|80000,00|D|0|D|80000,00|D|0|C|50000,00|50000,00|0|C|||||| +|I555|70|1.01.01.01|||CC|1|MATRIC CARTORIO AC|TERRENO RUA AC|02012019|30000,00|D|0|D|30000,00|D|0|D|0|3000,00|3000,00|C|||||| +|I550|76|1.05.05.05|12||602B|1|MODELO 16K NR SERIE 7680096|TORNO MECÂNICO|12012020|0|C|0|C|12000,00|C|0|D|2000,00|0|2000,00|D|31122021|LC210|7000,00|D|2| +|I550|76|1.05.05.05|12||603B|1|MODELO 13C NR SERIE 2342536|TORNO MECÂNICO|14012020|20000,00|C|0|C|40000,00|C|5000,00|D|5000,00|0|10000,00|D|31122021|LC210|7000,00|D|2| +|I555|76|1.05.05.05|12||602B|1|MODELO 16K NR SERIE 7680096|TORNO MECÂNICO|12012020|0|C|0|C|12000,00|C|0|D|2000,00|0|2000,00|D|||||| +|I555|76|1.05.05.05|12||603B|1|MODELO 13C NR SERIE 2342536|TORNO MECÂNICO|14012020|20000,00|C|0|C|40000,00|C|5000,00|D|5000,00|0|10000,00|D|||||| +|I550|60|1.07.07.07|12|77777777000191|123456|20000|NELORE MACHO ATÉ 12 MESES|BOVINO PARA ABATE|13122018|0|D|0|D|2000000,00|D|0|D|1200000,00|0|1200000,00|D|31102021|XV500|3000000,00|C|2| +|I550|60|1.07.07.07|12|77777777000191|123456|35000|NELORE FÊMEA 25/36 MESES|BOVINO PARA ABATE|13122018|0|D|0|D|7000000,00|D|0|D|0|4200000,00|4200000,00|C|31102021|XV500|3000000,00|C|2| +|I550|60|1.07.07.07|12|77777777000191|123456|10000|NELORE MACHO ATÉ 12 MESES|BOVINO PARA ABATE|13122018|2000000,00|D|1000000,00|C|1000000,00|D|1200000,00|D|0|600000,00|600000,00|D|22112021|XV637|600000,00|C|2| +|I555|60|1.07.07.07|12|77777777000191|123456|35000|NELORE FÊMEA 25/36 MESES|BOVINO PARA ABATE|13122018|0|D|0|D|7000000,00|D|0|D|0|4200000,00|4200000,00|C|||||| +|I555|60|1.07.07.07|12|77777777000191|123456|10000|NELORE MACHO ATÉ 12 MESES|BOVINO PARA ABATE|13122018|0|D|1000000,00|C|1000000,00|D|0|D|1200000,00|600000,00|600000,00|D|||||| +|I550|65|1.09.09.09||77777777000191|477BG|1|MATRC 456 - CARTÓRIO XX|GALPÃO INDUSTRIAL - SÃO PAULO/SP|31122018|3000000,00|D|0|D|3000000,00|D|0|D|1000000,00|0|1000000,00|D|04012021|896PR|5000000,00|D|2| +|I550|65|1.09.09.09||77777777000191|500AC|300|ON-EMP. 33.333.333/0001-91|AÇÕES|31122018|12000000,00|D|0|D|12000000,00|D|0|D|4000000,00|0|4000000,00|D|04012021|896PR|5000000,00|D|2| +|I550|65|1.09.09.09||77777777000191|477BG|1|MATRC 456 - CARTÓRIO XX|GALPÃO INDUSTRIAL - SÃO PAULO/SP|31122018|3000000,00|D|240000,00|C|2760000,00|D|1000000,00|D|0|80000,00|920000,00|D|31102021|937PR|80000,00|C|2| +|I550|65|1.09.09.09||77777777000191|500AC|150|ON-EMP. 33.333.333/0001-91|AÇÕES|31122019|12000000,00|D|6000000,00|C|6000000,00|D|4000000,00|D|0|2000000,00|2000000,00|D|31102021|938PR|2000000,00|C|2| +|I550|65|1.09.09.09||77777777000191|500AC|0|ON-EMP. 33.333.333/0001-91|AÇÕES|31122019|6000000,00|D|6000000,00|C|0|D|2000000,00|D|0|2000000,00|0|D|07112021|950PR|2000000,00|C|2| +|I555|65|1.09.09.09||77777777000191|477BG|1|MATRC 456 - CARTÓRIO XX|GALPÃO INDUSTRIAL - SÃO PAULO/SP|31122018|3000000,00|D|240000,00|C|2760000,00|D|0|D|1000000,00|80000,00|920000,00|D|||||| +|I555|65|1.09.09.09||77777777000191|500AC|0|ON-EMP. 33.333.333/0001-91|AÇÕES|31122018|12000000,00|D|12000000,00|C|12000000,00|D|0|D|4000000,00|4000000,00|0|D|||||| +|I990|63| +|J001|0| +|J900|TERMO DE ENCERRAMENTO|1|RAZAO_AUXILIAR_DAS_SUBCONTAS|EMPRESA TESTE LIVRO RAZAO AUXILIAR|99|01012021|31122021| +|J930|FULANO|45422460510|DIRETOR|203|4566|EMAIL|FONE|DF|DF/2018/1|01122018|S| +|J930|BELTRANO|77487527379|CONTADOR|900|78090|EMAIL|FONE|DF|DF/2018/1|01122018|N| +|J990|5| +|9001|0| +|9900|0000|1| +|9900|0001|1| +|9900|0007|1| +|9900|0990|1| +|9900|I001|1| +|9900|I010|1| +|9900|I012|1| +|9900|I015|4| +|9900|I030|1| +|9900|I050|4| +|9900|I510|26| +|9900|I550|15| +|9900|I555|9| +|9900|I990|1| +|9900|J001|1| +|9900|J900|1| +|9900|J930|2| +|9900|J990|1| +|9900|9001|1| +|9900|9900|22| +|9900|9990|1| +|9900|9999|1| +|9990|25| +|9999|97| diff --git a/l10n_br_sped_base/tests/sped_fake.py b/l10n_br_sped_base/tests/sped_fake.py new file mode 100644 index 000000000000..1c20cedc34a1 --- /dev/null +++ b/l10n_br_sped_base/tests/sped_fake.py @@ -0,0 +1,236 @@ +# Copyright 2024 - TODAY, Akretion - Raphael Valyi +# License AGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html). +# Generated by https://github.com/akretion/sped-extractor and xsdata-odoo +# and simplified manually for tests +# flake8: noqa: B950 + +import textwrap + +from erpbrasil.base import misc +from lxml.builder import E + +from odoo import api, fields, models + +from odoo.addons.l10n_br_sped_base.models.sped_mixin import ( + EDITABLE_ON_DRAFT, + LAYOUT_VERSIONS, +) + + +class Registro0000(models.Model): + "ABERTURA DO ARQUIVO DIGITAL E IDENTIFICAÇÃO DO EMPRESÁRIO OU DA SOCIEDADE EMPRESÁRIA" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.0000" + _inherit = ["l10n_br_sped.fake.9.0000"] + _odoo_model = "res.company" + + IND_SIT_ESP = fields.Selection( + selection=[ + ("0", "0 - Abertura"), + ("1", "1 - Cisão"), + ("2", "2 - Fusão"), + ("3", "3 - Incorporação"), + ("4", "4 - Extinção"), + ("5", "5 - Transformação"), + ("6", "6 - Transferência de Sede"), + ], + string="Indicador de situação especial", + ) + + IND_SIT_INI_PER = fields.Selection( + default="0", + selection=[ + ("0", "0 - Normal"), + ("1", "1 - Abertura"), + ("2", "2 - Cisão/Fusão"), + ("3", "3 - Obrigatoriedade no curso do ano"), + ], + string="Indicador de situação do inicio do período", + ) + + IND_FIN_ESC = fields.Selection( + default="0", + selection=[ + ("0", "0 - Original"), + ("1", "1 - Substituta da escrituração com NIRE"), + ("2", "2 - Substituta da escrituração sem NIRE"), + ("3", "3 - Substituta da escrituração com troca de NIRE"), + ], + string="Indicador de finalidade da escrituração", + ) + + # not a register 0000 field, but used for i010 register + ind_esc = fields.Selection( + selection=[ + ("G", "G - Diário completo"), + ("R", "R - Escrituração Resumida"), + ("A", "A - Auxiliar"), + ("B", "B - Diários e Balanços"), + ("Z", "Z - Razão Auxiliar"), + ], + default="G", + string="Forma de escritura contábil", + ) + + @api.model + def _append_top_view_elements(self, group, inline=False): + super()._append_top_view_elements(group) + group.append(E.field(name="ind_esc", required="1", attrs=EDITABLE_ON_DRAFT)) + + @api.model + def _odoo_domain(self, parent_record, declaration): + return [("id", "=", declaration.company_id.id)] + + @api.model + def _map_from_odoo(self, record, parent_record, declaration, index=0): + return { + "LECD": "LECD", + # "DT_INI": (will use the declaration field directly), + # "DT_FIN": (will use the declaration field directly), + "NOME": record.legal_name, + "CNPJ": misc.punctuation_rm(record.cnpj_cpf), + "UF": record.state_id.code, + "IE": misc.punctuation_rm(record.inscr_est), + "COD_MUN": record.city_id.ibge_code, + "IM": misc.punctuation_rm(record.inscr_mun or ""), + # "IND_SIT_ESP": (will use the declaration field directly), + # "IND_SIT_INI_PER": (will use the declaration field directly), + "IND_NIRE": 0, # TODO + # "IND_FIN_ESC" + "COD_HASH_SUB": 0, # TODO + "IND_GRANDE_PORTE": 0, # TODO + "TIP_ECD": 0, # TODO + "COD_SCP": 0, # TODO + "IDENT_MF": 0, # TODO + "IND_ESC_CONS": 0, # TODO + "IND_CENTRALIZADA": 0, # TODO + "IND_MUDANC_PC": 0, # TODO + "COD_PLAN_REF": 0, # TODO + } + + +class Registro0007(models.Model): + "OUTRAS INSCRIÇÕES CADASTRAIS DA PESSOA JURÍDICA" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.0007" + _inherit = "l10n_br_sped.fake.9.0007" + + +class RegistroI010(models.Model): + "IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i010" + _inherit = "l10n_br_sped.fake.9.i010" + + IND_ESC = fields.Selection(related="declaration_id.ind_esc", readonly=False) + + @api.model + def _map_from_odoo(self, record, parent_record, declaration, index=0): + return { + "COD_VER_LC": LAYOUT_VERSIONS["ecd"], + } + + +class RegistroI012(models.Model): + "LIVROS AUXILIARES AO DIÁRIO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i012" + _inherit = "l10n_br_sped.fake.9.i012" + + +class RegistroI015(models.Model): + """IDENTIFICAÇÃO DAS CONTAS DA ESCRITURAÇÃO RESUMIDA A QUE SE REFERE A + ESCRITURAÇÃO AUXILIAR""" + + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i015" + _inherit = "l10n_br_sped.fake.9.i015" + + +class RegistroI030(models.Model): + "TERMO DE ABERTURA" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i030" + _inherit = "l10n_br_sped.fake.9.i030" + + +class RegistroI050(models.Model): + "PLANO DE CONTAS" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i050" + _inherit = "l10n_br_sped.fake.9.i050" + + +class RegistroI510(models.Model): + """DEFINIÇÃO DOS CAMPOS DO LIVRO RAZÃO AUXILIAR COM LEIAUTE + PARAMETRIZÁVEL""" + + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i510" + _inherit = "l10n_br_sped.fake.9.i510" + + +class RegistroI550(models.Model): + "DETALHES DO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i550" + _inherit = "l10n_br_sped.fake.9.i550" + + RZ_CONT = fields.Char() # according to pdf specification + + @api.model + def _read_register_line(self, line, version): + vals = {"RZ_CONT": "|".join(line.split("|")[2:][:-1])} + return vals + + def _generate_register_text(self, sped, version, line_count, count_by_register): + code = self._name[-4:].upper() + if len(self): + count_by_register[code] += len(self) + for rec in self: + sped.write("\n|%s|" % (code,)) + sped.write(rec.RZ_CONT) + sped.write("|") + line_count[0] += 1 + rec.reg_I555_ids._generate_register_text( + sped, version, line_count, count_by_register + ) + return sped + + +class RegistroI555(models.Model): + "TOTAIS NO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.i555" + _inherit = "l10n_br_sped.fake.9.i555" + + RZ_CONT_TOT = fields.Char() # according to pdf specification + + @api.model + def _read_register_line(self, line, version): + vals = {"RZ_CONT_TOT": "|".join(line.split("|")[2:][:-1])} + return vals + + def _generate_register_text(self, sped, version, line_count, count_by_register): + code = self._name[-4:].upper() + if len(self): + count_by_register[code] += len(self) + for rec in self: + sped.write("\n|%s|" % (code,)) + sped.write(rec.RZ_CONT_TOT or "") + sped.write("|") + line_count[0] += 1 + + +class RegistroJ900(models.Model): + "TERMO DE ENCERRAMENTO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.j900" + _inherit = "l10n_br_sped.fake.9.j900" + + +class RegistroJ930(models.Model): + "SIGNATÁRIOS DA ESCRITURAÇÃO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.j930" + _inherit = "l10n_br_sped.fake.9.j930" diff --git a/l10n_br_sped_base/tests/sped_fake_spec_9.py b/l10n_br_sped_base/tests/sped_fake_spec_9.py new file mode 100644 index 000000000000..6451430bfd5b --- /dev/null +++ b/l10n_br_sped_base/tests/sped_fake_spec_9.py @@ -0,0 +1,757 @@ +# Copyright 2024 - TODAY, Akretion - Raphael Valyi +# License AGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html). +# Generated by https://github.com/akretion/sped-extractor and xsdata-odoo +# and simplified manually for tests +# flake8: noqa: B950 + +import textwrap + +from odoo import fields, models + + +class Registro0000(models.AbstractModel): + """ABERTURA DO ARQUIVO DIGITAL E IDENTIFICAÇÃO DO EMPRESÁRIO OU DA + SOCIEDADE EMPRESÁRIA""" + + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.0000" + _inherit = "l10n_br_sped.declaration" + _sped_level = 0 + + LECD = fields.Char( + string="Texto fixo contendo “LECD”", required=True, sped_length="4" + ) + + DT_INI = fields.Date( + string="Data inicial das informações contidas no arquivo", + required=True, + sped_length="8", + ) + + DT_FIN = fields.Date( + string="Data final das informações contidas no arquivo", + required=True, + sped_length="8", + ) + + NOME = fields.Char(string="Nome empresarial da pessoa jurídica", required=True) + + CNPJ = fields.Char( + string="Número de inscrição da pessoa jurídica no CNPJ", + required=True, + xsd_type="numeric_code", + sped_length="14", + help=( + "Número de inscrição da pessoa jurídica no CNPJ. Observação: Esse " + "CNPJ é sempre da Sócia Ostensiva, no caso do arquivo da SCP." + ), + ) + + UF = fields.Char( + string="Sigla da unidade da federação da pessoa jurídica", + required=True, + sped_length="2", + ) + + IE = fields.Char(string="Inscrição Estadual da pessoa jurídica") + + COD_MUN = fields.Char( + string="Código do município do domicílio fiscal", + xsd_type="numeric_code", + sped_length="7", + help=( + "Código do município do domicílio fiscal da pessoa jurídica, " + "conforme tabela do IBGE – Instituto Brasileiro de Geografia e " + "Estatística." + ), + ) + + IM = fields.Char(string="Inscrição Municipal da pessoa jurídica") + + IND_SIT_ESP = fields.Char( + string="Indicador de situação especial", + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de situação especial (conforme tabela publicada pelo " "Sped)." + ), + ) + + IND_SIT_INI_PER = fields.Char( + string="Indicador de situação no início do período", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de situação no início do período (conforme tabela " + "publicada pelo Sped)." + ), + ) + + IND_NIRE = fields.Char( + string="Indicador de existência de NIRE", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de existência de NIRE: 0 – Empresa não possui registro " + "na Junta Comercial (não possui NIRE) 1 – Empresa possui registro " + "na Junta Comercial (possui NIRE)" + ), + ) + + IND_FIN_ESC = fields.Char( + string="Indicador de finalidade da escrituração", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de finalidade da escrituração: 0 - Original 1 – " "Substituta" + ), + ) + + COD_HASH_SUB = fields.Char( + string="Hash da escrituração substituída", sped_length="4" + ) + + IND_GRANDE_PORTE = fields.Char( + string="Indicador de entidade sujeita", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de entidade sujeita a auditoria independente: 0 – " + "Empresa não é entidade sujeita a auditoria independente. 1 – " + "Empresa é entidade sujeita a auditoria independente – Ativo Total" + " superior a R$ 240.000.000,00 ou Receita Bruta Anual superior " + "R$300.000.000,00." + ), + ) + + TIP_ECD = fields.Integer( + string="Indicador do tipo de ECD", + required=True, + sped_length="1", + help=( + "Indicador do tipo de ECD: 0 – ECD de empresa não participante de " + "SCP como sócio ostensivo. 1 – ECD de empresa participante de SCP " + "como sócio ostensivo. 2 – ECD da SCP." + ), + ) + + COD_SCP = fields.Char( + string="CNPJ da SCP", + xsd_type="numeric_code", + sped_length="14", + help=( + "CNPJ da SCP (Art. 4º, XVII, da IN RFB nº 1.863, de 27 de dezembro" + " de 2018). Observação: Só deve ser preenchido pela própria SCP " + "com o CNPJ da SCP (Não é preenchido pelo sócio ostensivo)." + ), + ) + + IDENT_MF = fields.Char( + string="Identificação de moeda funcional", + required=True, + sped_length="1", + help=( + "Identificação de moeda funcional: Indica que a escrituração " + "abrange valores com base na moeda funcional (art. 287 da " + "Instrução Normativa RFB nº 1.700, de 14 de março de 2017). " + "Observação: Deverá ser utilizado o registro I020 para informação " + "de campos adicionais, conforme instruções do item 1.24." + ), + ) + + IND_ESC_CONS = fields.Char( + string="Escriturações Contábeis Consolidadas", + required=True, + sped_length="1", + help=( + "Escriturações Contábeis Consolidadas: (Deve ser preenchido pela " + "empresa controladora obrigada a informar demonstrações contábeis " + "consolidadas, nos termos da Lei nº 6.404/76 e/ou do " + "Pronunciamento Técnico CPC 36 – Demonstrações Consolidadas) S – " + "Sim N – Não" + ), + ) + + IND_CENTRALIZADA = fields.Char( + string="Indicador da modalidade", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador da modalidade de escrituração centralizada ou " + "descentralizada: 0 – Escrituração Centralizada 1 – Escrituração " + "Descentralizada" + ), + ) + + IND_MUDANC_PC = fields.Char( + string="Indicador de mudança de plano de contas", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Indicador de mudança de plano de contas: 0 – Não houve mudança no" + " plano de contas. 1 – Houve mudança no plano de contas." + ), + ) + + COD_PLAN_REF = fields.Char( + string="O Código do Plano de Contas Referencial", + sped_length="2", + help=( + "O Código do Plano de Contas Referencial que será utilizado para o" + " mapeamento de todas as contas analíticas: 1 – PJ em Geral – " + "Lucro Real 2 – PJ em Geral – Lucro Presumido 3 – Financeiras – " + "Lucro Real 4 – Seguradoras – Lucro Real 5 – Imunes e Isentas em " + "Geral 6 – Imunes e Isentas – Financeiras 7 – Imunes e Isentas – " + "Seguradoras 8 – Entidades Fechadas de Previdência Complementar 9 " + "– Partidos Políticos 10 – Financeiras – Lucro Presumido " + "bservação: Caso a pessoa jurídica não realize o mapeamento para " + "os planos referenciais na ECD, este campo deve ficar em branco." + ), + ) + + +class Registro0007(models.AbstractModel): + "OUTRAS INSCRIÇÕES CADASTRAIS DA PESSOA JURÍDICA" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.0007" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 2 + + COD_ENT_REF = fields.Char( + string="Código da instituição responsável", + required=True, + help=( + "Código da instituição responsável pela administração do cadastro " + "(conforme tabela publicada pelo Sped)." + ), + ) + + COD_INSCR = fields.Char( + string="Código cadastral da pessoa jurídica", + help=( + "Código cadastral da pessoa jurídica na instituição identificada " + "no campo 02." + ), + ) + + +class RegistroI010(models.AbstractModel): + "IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i010" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 2 + + IND_ESC = fields.Char( + string="G R A B Z Indicador da forma", + required=True, + sped_length="1", + help=( + "G R A B Z Indicador da forma de escrituração contábil: - Livro " + "Diário (Completo sem escrituração auxiliar). - Livro Diário com " + "Escrituração Resumida (com escrituração auxiliar). - Livro Diário" + " Auxiliar ao Diário com Escrituração Resumida. - Livro Balancetes" + " Diários e Balanços. – Razão Auxiliar (Livro Contábil Auxiliar " + "conforme leiaute definido nos registros I500 a I555)." + ), + ) + + COD_VER_LC = fields.Char( + string="Código da Versão do Leiaute Contábil", required=True + ) + + reg_I012_ids = fields.One2many( + "l10n_br_sped.fake.i012", + "reg_I012_ids_RegistroI010_id", + string="I012 LIVROS AUXILIARES AO DIÁRIO", + sped_card="0:N", + sped_required=True, + ) + + reg_I030_ids = fields.One2many( + "l10n_br_sped.fake.i030", + "reg_I030_ids_RegistroI010_id", + string="I030 TERMO DE ABERTURA", + sped_card="1", + sped_required=True, + ) + + reg_I050_ids = fields.One2many( + "l10n_br_sped.fake.i050", + "reg_I050_ids_RegistroI010_id", + string="I050 PLANO DE CONTAS", + sped_card="1:N", + sped_required=True, + ) + + reg_I510_ids = fields.One2many( + "l10n_br_sped.fake.i510", + "reg_I510_ids_RegistroI010_id", + string="I510", + sped_card="0:N", + sped_required=True, + help=( + "I510 DEFINIÇÃO DOS CAMPOS DO LIVRO RAZÃO AUXILIAR COM LEIAUTE " + "PARAMETRIZÁVEL" + ), + ) + + reg_I550_ids = fields.One2many( + "l10n_br_sped.fake.i550", + "reg_I550_ids_RegistroI010_id", + string="I550", + sped_card="0:N", + sped_required=True, + help=("I550 DETALHES DO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL"), + ) + + +class RegistroI012(models.AbstractModel): + "LIVROS AUXILIARES AO DIÁRIO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i012" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + NUM_ORD = fields.Integer( + string="Número de ordem do instrumento associado", required=True + ) + + NAT_LIVR = fields.Char( + string="Natureza do livro associado; finalidade", + required=True, + sped_length="8", + help=( + "Natureza do livro associado; finalidade a que se destina o " "instrumento." + ), + ) + + TIPO = fields.Char( + string="Tipo de escrituração do livro associado", + required=True, + xsd_type="numeric_code", + sped_length="1", + help=( + "Tipo de escrituração do livro associado: 0 – digital (incluído no" + " Sped). 1 – outros." + ), + ) + + COD_HASH_AUX = fields.Char( + string="Código Hash do arquivo correspondente", + sped_length="4", + help=( + "Código Hash do arquivo correspondente ao livro auxiliar utilizado" + " na assinatura digital." + ), + ) + + reg_I012_ids_RegistroI010_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i010", + string="IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL", + required=True, + ondelete="cascade", + ) + + reg_I015_ids = fields.One2many( + "l10n_br_sped.fake.i015", + "reg_I015_ids_RegistroI012_id", + string="I015", + sped_card="1:N", + sped_required=True, + help=( + "I015 IDENTIFICAÇÃO DAS CONTAS DA ESCRITURAÇÃO RESUMIDA A QUE SE " + "REFERE A ESCRITURAÇÃO AUXILIAR" + ), + ) + + +class RegistroI015(models.AbstractModel): + """IDENTIFICAÇÃO DAS CONTAS DA ESCRITURAÇÃO RESUMIDA A QUE SE REFERE A + ESCRITURAÇÃO AUXILIAR""" + + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i015" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 4 + + COD_CTA_RES = fields.Char( + string="Código da(s) conta(s) analítica(s) do Livro Diário", + required=True, + help=( + "Código da(s) conta(s) analítica(s) do Livro Diário com " + "Escrituração Resumida (R) que recebe os lançamentos globais (deve" + " corresponder a uma conta sintética no livro auxiliar)." + ), + ) + + reg_I015_ids_RegistroI012_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i012", + string="LIVROS AUXILIARES AO DIÁRIO", + required=True, + ondelete="cascade", + ) + + +class RegistroI030(models.AbstractModel): + "TERMO DE ABERTURA" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i030" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + DNRC_ABERT = fields.Char( + string="Texto fixo contendo “TERMO DE ABERTURA”", + required=True, + sped_length="17", + ) + + NUM_ORD = fields.Integer( + string="Número de ordem do instrumento de escrituração", required=True + ) + + NAT_LIVR = fields.Char( + string="Natureza do livro; finalidade a que se destina", + required=True, + sped_length="8", + help=("Natureza do livro; finalidade a que se destina o instrumento."), + ) + + QTD_LIN = fields.Integer( + string="Quantidade total de linhas do arquivo digital", required=True + ) + + NOME = fields.Char(string="Nome empresarial", required=True) + + NIRE = fields.Char( + string="Número de Identificação do Registro de Empresas", + xsd_type="numeric_code", + sped_length="11", + help=("Número de Identificação do Registro de Empresas da Junta " "Comercial."), + ) + + CNPJ = fields.Char( + string="Número de inscrição no CNPJ", + required=True, + xsd_type="numeric_code", + sped_length="14", + ) + + DT_ARQ = fields.Date( + string="Data do arquivamento dos atos constitutivos", sped_length="8" + ) + + DT_ARQ_CONV = fields.Date( + string="Data de arquivamento do ato de conversão", + sped_length="8", + help=( + "Data de arquivamento do ato de conversão de sociedade simples em " + "sociedade empresária." + ), + ) + + DESC_MUN = fields.Char(string="Município") + + DT_EX_SOCIAL = fields.Date( + string="Data de encerramento do exercício social", + required=True, + sped_length="8", + ) + + reg_I030_ids_RegistroI010_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i010", + string="IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL", + required=True, + ondelete="cascade", + ) + + +class RegistroI050(models.AbstractModel): + "PLANO DE CONTAS" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i050" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + DT_ALT = fields.Date( + string="Data da inclusão/alteração", required=True, sped_length="8" + ) + + COD_NAT = fields.Char( + string="Código da natureza da conta/grupo de contas", + required=True, + sped_length="2", + help=( + "Código da natureza da conta/grupo de contas, conforme tabela " + "publicada pelo Sped." + ), + ) + + IND_CTA = fields.Char( + string="Indicador do tipo de conta: S", + required=True, + sped_length="1", + help=( + "Indicador do tipo de conta: S - Sintética (grupo de contas) A - " + "Analítica (conta)" + ), + ) + + NIVEL = fields.Integer( + string="Nível da conta analítica/grupo de contas", required=True + ) + + COD_CTA = fields.Char( + string="Código da conta analítica/grupo de contas", required=True + ) + + COD_CTA_SUP = fields.Char( + string="Código da conta sintética /grupo de contas", + help=( + "Código da conta sintética /grupo de contas de nível imediatamente" + " superior." + ), + ) + + CTA = fields.Char(string="Nome da conta analítica/grupo de contas", required=True) + + reg_I050_ids_RegistroI010_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i010", + string="IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL", + required=True, + ondelete="cascade", + ) + + +class RegistroI510(models.AbstractModel): + """DEFINIÇÃO DOS CAMPOS DO LIVRO RAZÃO AUXILIAR COM LEIAUTE + PARAMETRIZÁVEL""" + + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i510" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + NM_CAMPO = fields.Char( + string="Nome do campo", + required=True, + sped_length="16", + help="Nome do campo, sem espaços em branco ou caractere especial.", + ) + + DESC_CAMPO = fields.Char( + string="Descrição do campo", + required=True, + sped_length="5", + help=("Descrição do campo (utilizada na visualização do Livro Auxiliar)"), + ) + + TIPO_CAMPO = fields.Char( + string="Tipo do campo", + required=True, + sped_length="1", + help="Tipo do campo: “N” – Numérico; “C” – Caractere.", + ) + + TAM_CAMPO = fields.Char( + string="Tamanho do campo", + required=True, + xsd_type="numeric_code", + sped_length="3", + ) + + DEC_CAMPO = fields.Char( + string="Quantidade de casas decimais para campos tipo “N”", + xsd_type="numeric_code", + sped_length="2", + ) + + COL_CAMPO = fields.Char( + string="Largura da coluna no relatório", + required=True, + xsd_type="numeric_code", + sped_length="3", + help=("Largura da coluna no relatório (em quantidade de caracteres)."), + ) + + reg_I510_ids_RegistroI010_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i010", + string="IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL", + required=True, + ondelete="cascade", + ) + + +class RegistroI550(models.AbstractModel): + "DETALHES DO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i550" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + reg_I550_ids_RegistroI010_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i010", + string="IDENTIFICAÇÃO DA ESCRITURAÇÃO CONTÁBIL", + required=True, + ondelete="cascade", + ) + + reg_I555_ids = fields.One2many( + "l10n_br_sped.fake.i555", + "reg_I555_ids_RegistroI550_id", + string="I555", + sped_card="0:N", + sped_required=True, + help=("I555 TOTAIS NO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL"), + ) + + +class RegistroI555(models.AbstractModel): + "TOTAIS NO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.i555" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 4 + + reg_I555_ids_RegistroI550_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.i550", + string="reg_I555_ids_RegistroI550_id", + required=True, + ondelete="cascade", + help="DETALHES DO LIVRO RAZÃO AUXILIAR COM LEIAUTE PARAMETRIZÁVEL", + ) + + +class RegistroJ900(models.AbstractModel): + "TERMO DE ENCERRAMENTO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.j900" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 2 + + DNRC_ENCER = fields.Char( + string="Texto fixo contendo “TERMO DE ENCERRAMENTO”", + required=True, + sped_length="21", + ) + + NUM_ORD = fields.Integer( + string="Número de ordem do instrumento de escrituração", required=True + ) + + NAT_LIVRO = fields.Char( + string="Natureza do livro; finalidade a que se destinou", + required=True, + sped_length="8", + help=("Natureza do livro; finalidade a que se destinou o instrumento."), + ) + + NOME = fields.Char(string="Nome empresarial", required=True, sped_length="(*)") + + QTD_LIN = fields.Integer( + string="Quantidade total de linhas do arquivo digital", required=True + ) + + DT_INI_ESCR = fields.Date( + string="Data de início da escrituração", required=True, sped_length="8" + ) + + DT_FIN_ESCR = fields.Date( + string="Data de término da escrituração", required=True, sped_length="8" + ) + + reg_J930_ids = fields.One2many( + "l10n_br_sped.fake.j930", + "reg_J930_ids_RegistroJ900_id", + string="J930 SIGNATÁRIOS DA ESCRITURAÇÃO", + sped_card="1:N", + sped_required=True, + ) + + +class RegistroJ930(models.AbstractModel): + "SIGNATÁRIOS DA ESCRITURAÇÃO" + _description = textwrap.dedent(" %s" % (__doc__,)) + _name = "l10n_br_sped.fake.9.j930" + _inherit = "l10n_br_sped.mixin.fake" + _sped_level = 3 + + IDENT_NOM = fields.Char(string="Nome do signatário", required=True) + + IDENT_CPF_CNPJ = fields.Char( + string="CPF ou CNPJ", + required=True, + xsd_type="numeric_code", + sped_length="CPF (11) CNPJ(14)", + ) + + IDENT_QUALIF = fields.Char( + string="Qualificação do assinante", + required=True, + help="Qualificação do assinante, conforme tabela.", + ) + + COD_ASSIN = fields.Char( + string="Código de qualificação do assinante", + required=True, + sped_length="3", + help="Código de qualificação do assinante, conforme tabela.", + ) + + IND_CRC = fields.Char( + string="Número de inscrição do contabilista", + help=( + "Número de inscrição do contabilista no Conselho Regional de " + "Contabilidade." + ), + ) + + EMAIL = fields.Char(string="Email do signatário", sped_length="6") + + FONE = fields.Char(string="Telefone do signatário", sped_length="14") + + UF_CRC = fields.Char( + string="Indicação da unidade da federação que expediu", + sped_length="2", + help="Indicação da unidade da federação que expediu o CRC.", + ) + + NUM_SEQ_CRC = fields.Char( + string="Número da Certidão de Regularidade Profissional", + help=( + "Número da Certidão de Regularidade Profissional do Contador no " + "seguinte formato: UF/ano/número" + ), + ) + + DT_CRC = fields.Date( + string="Data de validade da Certidão", + sped_length="8", + help=( + "Data de validade da Certidão de Regularidade Profissional do " "Contador" + ), + ) + + IND_RESP_LEGAL = fields.Char( + string="Identificação do signatário que será validado", + required=True, + sped_length="1", + help=( + "Identificação do signatário que será validado como responsável " + "pela assinatura da ECD, conforme atos societários: S – Sim N – " + "Não" + ), + ) + + reg_J930_ids_RegistroJ900_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.j900", + string="TERMO DE ENCERRAMENTO", + required=True, + ondelete="cascade", + ) diff --git a/l10n_br_sped_base/tests/sped_mixin_fake.py b/l10n_br_sped_base/tests/sped_mixin_fake.py new file mode 100644 index 000000000000..33440a3184e5 --- /dev/null +++ b/l10n_br_sped_base/tests/sped_mixin_fake.py @@ -0,0 +1,18 @@ +# Copyright 2024 - TODAY, Akretion - Raphael Valyi +# License AGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html). +# Generated by https://github.com/akretion/sped-extractor and xsdata-odoo + +from odoo import fields, models + + +class SpecMixinFAKE(models.AbstractModel): + _name = "l10n_br_sped.mixin.fake" + _description = "l10n_br_sped.mixin.fake" + _inherit = "l10n_br_sped.mixin" + + declaration_id = fields.Many2one( + comodel_name="l10n_br_sped.fake.0000", + required=True, + ) + + state = fields.Selection(related="declaration_id.state") diff --git a/l10n_br_sped_base/tests/test_sped_base.py b/l10n_br_sped_base/tests/test_sped_base.py new file mode 100644 index 000000000000..4c1c616222f7 --- /dev/null +++ b/l10n_br_sped_base/tests/test_sped_base.py @@ -0,0 +1,153 @@ +# Copyright 2024 Akretion - Raphael Valyi +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html). + +from os import path + +from odoo_test_helper import FakeModelLoader + +from odoo.tests import SavepointCase + +from odoo.addons import l10n_br_sped_base + + +class TestSpedBase(SavepointCase, FakeModelLoader): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + + # import simpilified equivalent of SPED ECD models: + from .sped_fake import ( + Registro0000, + Registro0007, + RegistroI010, + RegistroI012, + RegistroI015, + RegistroI030, + RegistroI050, + RegistroI510, + RegistroI550, + RegistroI555, + RegistroJ900, + RegistroJ930, + ) + from .sped_fake_spec_9 import ( + Registro0000 as AbstractRegistro0000, + Registro0007 as AbstractRegistro0007, + RegistroI010 as AbstractRegistroI010, + RegistroI012 as AbstractRegistroI012, + RegistroI015 as AbstractRegistroI015, + RegistroI030 as AbstractRegistroI030, + RegistroI050 as AbstractRegistroI050, + RegistroI510 as AbstractRegistroI510, + RegistroI550 as AbstractRegistroI550, + RegistroI555 as AbstractRegistroI555, + RegistroJ900 as AbstractRegistroJ900, + RegistroJ930 as AbstractRegistroJ930, + ) + from .sped_mixin_fake import SpecMixinFAKE + + cls.loader.update_registry( + ( + SpecMixinFAKE, + AbstractRegistro0000, + AbstractRegistro0007, + AbstractRegistroI010, + AbstractRegistroI012, + AbstractRegistroI015, + AbstractRegistroI030, + AbstractRegistroI050, + AbstractRegistroI510, + AbstractRegistroI550, + AbstractRegistroI555, + AbstractRegistroJ900, + AbstractRegistroJ930, + Registro0000, + Registro0007, + RegistroI010, + RegistroI012, + RegistroI015, + RegistroI030, + RegistroI050, + RegistroI510, + RegistroI550, + RegistroI555, + RegistroJ900, + RegistroJ930, + ) + ) + demo_path = path.join(l10n_br_sped_base.__path__[0], "tests") + cls.file_path = path.join(demo_path, "demo_fake.txt") + sped_mixin = cls.env["l10n_br_sped.mixin"] + sped_mixin._flush_registers("fake") + cls.declaration = sped_mixin._import_file(cls.file_path, "fake") + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + super(TestSpedBase, cls).tearDownClass() + + def test_generate_sped(self): + sped = self.declaration._generate_sped_text() + with open(self.file_path) as f: + target_content = f.read() + # print(sped) + self.assertEqual(sped.strip(), target_content.strip()) + + def test_register_tree_view(self): + arch = self.env["l10n_br_sped.fake.i010"].fields_view_get(view_type="tree")[ + "arch" + ] + self.assertIn( # link to declaration + '