Repository: OCA/l10n-brazil
Pull request #3786: [16.0][IMP] Adicionado cadastro de Natureza Jurídica
Author: login: renatonlima
Labels: name: approved
name: merged 🎉
name: 16.0
Created: 2025-05-09T21:21:25Z | Merged: 2025-05-13T19:50:58Z

Esse PR implementa do cadastro de natureza jurídica e também faz algumas mudanças na visão da empresa e adapta o módulo l10n_br_crm_cnpj_search substituindo o campo legal_nature pelo campo relacional legal_nature_id

<img width="1440" alt="image" src="https://github.com/user-attachments/assets/8634d445-615a-4c15-befa-16ae0d421095" />

No cadastro de empresa eu coloquei o grupo do CNAE e a natureza jurídica acima, pois essas seriam informações que deveriam ser preenchida antes dos campos de regime tributário e impostos pois futuramente podemos deduzir ou filtrar o preenchimento de outros campos, como no simples nacional.


Diff:
diff --git a/l10n_br_cnpj_search/models/__init__.py b/l10n_br_cnpj_search/models/__init__.py
index 526ddc80c376..c3cce5af2327 100644
--- a/l10n_br_cnpj_search/models/__init__.py
+++ b/l10n_br_cnpj_search/models/__init__.py
@@ -3,5 +3,4 @@
 from . import l10n_br_base_party_mixin
 from . import res_config_settings
 from . import cnpj_webservice
-from . import res_partner
 from . import res_company
diff --git a/l10n_br_cnpj_search/models/cnpj_webservice.py b/l10n_br_cnpj_search/models/cnpj_webservice.py
index 09c960a5da14..5eafe81306ac 100644
--- a/l10n_br_cnpj_search/models/cnpj_webservice.py
+++ b/l10n_br_cnpj_search/models/cnpj_webservice.py
@@ -116,16 +116,27 @@ def _validate(self, response):
         if response.status_code != 200:
             raise ValidationError(_("%s") % response.reason)
 
+    @api.model
+    def _get_legal_nature(self, raw_code):
+        code = punctuation_rm(raw_code)
+        legal_nature_id = False
+        if code:
+            legal_nature_id = (
+                self.env["l10n_br_fiscal.legal.nature"]
+                .search([("code_unmasked", "=", code)])
+                .id
+            )
+        return legal_nature_id
+
     @api.model
     def _get_cnae(self, raw_code):
         code = punctuation_rm(raw_code)
         cnae_id = False
 
         if code:
-            formatted_code = code[0:4] + "-" + code[4] + "/" + code[5:]
             cnae_id = (
                 self.env["l10n_br_fiscal.cnae"]
-                .search([("code", "=", formatted_code)])
+                .search([("code_unmasked", "=", code)])
                 .id
             )
 
@@ -168,7 +179,7 @@ def _receitaws_import_data(self, data):
             "district": self.get_data(data, "bairro", title=True),
             "street_number": self.get_data(data, "numero"),
             "zip": self.get_data(data, "cep"),
-            "legal_nature": self.get_data(data, "natureza_juridica"),
+            "legal_nature_id": self._receitaws_get_legal_nature(data),
             "phone": phone,
             "mobile": mobile,
             "state_id": state_id,
@@ -221,6 +232,16 @@ def _get_state_city(self, data):
 
         return [state_id, city_id]
 
+    @api.model
+    def _receitaws_get_legal_nature(self, data):
+        legal_nature = data.get("natureza_juridica")
+        if legal_nature:
+            legal_nature = legal_nature.split(" - ")
+            if len(legal_nature) > 1:
+                legal_nature_code = legal_nature[0]
+                return self._get_legal_nature(legal_nature_code)
+        return False
+
     @api.model
     def _receitaws_get_cnae(self, data):
         if data.get("atividade_principal"):
@@ -280,7 +301,6 @@ def _serpro_import_data(self, data):
         name = fantasy_name if fantasy_name else legal_name
         phone, mobile = self._serpro_get_phones(data)
         address = data.get("endereco")
-        nature = data.get("naturezaJuridica")
         cep = self.get_data(address, "cep")
 
         res = {
@@ -291,8 +311,7 @@ def _serpro_import_data(self, data):
             "street2": self.get_data(address, "complemento", title=True),
             "district": self.get_data(address, "bairro", title=True),
             "street_number": self.get_data(address, "numero"),
-            "legal_nature": self.get_data(nature, "codigo", title=True)
-            + self.get_data(nature, "descricao", title=True),
+            "legal_nature_id": self._serpro_get_legal_nature(data),
             "zip": cep,
             "phone": phone,
             "mobile": mobile,
@@ -388,9 +407,14 @@ def _get_city_id(self, cep):
 
         return cep_values.get("city_id")
 
+    @api.model
+    def _serpro_get_legal_nature(self, data):
+        legal_nature = data.get("naturezaJuridica")
+        legal_nature_code = self.get_data(legal_nature, "codigo")
+        return self._get_legal_nature(legal_nature_code)
+
     @api.model
     def _serpro_get_cnae(self, data):
         cnae_main = data.get("cnaePrincipal")
         cnae_code = self.get_data(cnae_main, "codigo")
-
         return self._get_cnae(cnae_code)
diff --git a/l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py b/l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py
index 738ac46c1747..5c1ae198735f 100644
--- a/l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py
+++ b/l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py
@@ -14,7 +14,10 @@ class PartyMixin(models.AbstractModel):
 
     cnae_main_id = fields.Many2one(comodel_name="l10n_br_fiscal.cnae")
 
-    legal_nature = fields.Char()
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+    )
 
     br_currency_id = fields.Many2one(
         comodel_name="res.currency",
diff --git a/l10n_br_cnpj_search/models/res_company.py b/l10n_br_cnpj_search/models/res_company.py
index 443f442cc182..059e504f5e37 100644
--- a/l10n_br_cnpj_search/models/res_company.py
+++ b/l10n_br_cnpj_search/models/res_company.py
@@ -12,8 +12,6 @@ class ResCompany(models.Model):
 
     mobile = fields.Char(related="partner_id.mobile")
 
-    legal_nature = fields.Char(related="partner_id.legal_nature")
-
     company_currency_id = fields.Many2one(
         "res.currency",
         related="currency_id",
diff --git a/l10n_br_cnpj_search/models/res_partner.py b/l10n_br_cnpj_search/models/res_partner.py
deleted file mode 100644
index 49ea1b97f5bd..000000000000
--- a/l10n_br_cnpj_search/models/res_partner.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2022 KMEE - Luis Felipe Mileo
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import fields, models
-
-
-class ResPartner(models.Model):
-    _inherit = "res.partner"
-
-    cnae_secondary_ids = fields.Many2many(
-        comodel_name="l10n_br_fiscal.cnae",
-        relation="res_partner_fiscal_cnae_rel",
-        column1="company_id",
-        column2="cnae_id",
-        domain="[('internal_type', '=', 'normal'), ('id', '!=', cnae_main_id)]",
-        string="Secondary CNAE",
-    )
diff --git a/l10n_br_cnpj_search/views/res_company_view.xml b/l10n_br_cnpj_search/views/res_company_view.xml
index 9e7f35e713b3..f364995ef2e7 100644
--- a/l10n_br_cnpj_search/views/res_company_view.xml
+++ b/l10n_br_cnpj_search/views/res_company_view.xml
@@ -6,12 +6,9 @@
         <field name="inherit_id" ref="l10n_br_fiscal.fiscal_res_company_form" />
         <field name="priority">99</field>
         <field name="arch" type="xml">
-            <field name="cnae_main_id" position="after">
-                <field name="cnae_secondary_ids" widget="many2many_tags" />
+            <field name="cnae_secondary_ids" position="after">
                 <field name="equity_capital" widget="monetary" />
-                <field name="legal_nature" />
             </field>
-
             <field name="cnpj_cpf" position="replace">
                 <label for="cnpj_cpf" string="CNPJ" />
                      <div class="o_row" colspan="1">
diff --git a/l10n_br_cnpj_search/views/res_partner_view.xml b/l10n_br_cnpj_search/views/res_partner_view.xml
index e1d1c36c98d4..777361495c43 100644
--- a/l10n_br_cnpj_search/views/res_partner_view.xml
+++ b/l10n_br_cnpj_search/views/res_partner_view.xml
@@ -9,10 +9,8 @@
         <field name="priority">99</field>
         <field name="inherit_id" ref="l10n_br_fiscal.partner_form" />
         <field name="arch" type="xml">
-            <field name="cnae_main_id" position="after">
-                <field name="cnae_secondary_ids" widget="many2many_tags" />
+            <field name="cnae_secondary_ids" position="after">
                 <field name="equity_capital" widget="monetary" />
-                <field name="legal_nature" />
             </field>
 
             <field name="cnpj_cpf" position="replace">
diff --git a/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.py b/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.py
index 354264abe383..8cd7691527ee 100644
--- a/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.py
+++ b/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.py
@@ -36,7 +36,7 @@ class PartnerCnpjSearchWizard(models.TransientModel):
     phone = fields.Char()
     mobile = fields.Char()
     email = fields.Char()
-    legal_nature = fields.Char()
+    legal_nature_id = fields.Many2one(comodel_name="l10n_br_fiscal.legal.nature")
     currency_id = fields.Many2one(
         comodel_name="res.currency",
         default=lambda self: self.env.ref("base.BRL"),
@@ -112,7 +112,7 @@ def action_update_partner(self):
             "phone": self.phone,
             "mobile": self.mobile,
             "email": self.email,
-            "legal_nature": self.legal_nature,
+            "legal_nature_id": self.legal_nature_id,
             "equity_capital": self.equity_capital,
             "cnae_main_id": self.cnae_main_id,
             "cnae_secondary_ids": self.cnae_secondary_ids,
diff --git a/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.xml b/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.xml
index ec7475d75ecf..240d1df99073 100644
--- a/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.xml
+++ b/l10n_br_cnpj_search/wizard/partner_cnpj_search_wizard.xml
@@ -40,7 +40,7 @@
                     </group>
 
                     <group name="Other Information" string="Other Information">
-                        <field name="legal_nature" />
+                        <field name="legal_nature_id" />
                         <field name="equity_capital" widget="monetary" />
                         <field name="cnae_main_id" string="Main CNAE" />
                         <field
diff --git a/l10n_br_crm_cnpj_search/models/crm_lead.py b/l10n_br_crm_cnpj_search/models/crm_lead.py
index 15d90a668bc7..00e7c46e6aed 100644
--- a/l10n_br_crm_cnpj_search/models/crm_lead.py
+++ b/l10n_br_crm_cnpj_search/models/crm_lead.py
@@ -32,7 +32,7 @@ def _prepare_customer_values(self, name, is_company, parent_id=False):
                     "inscr_est": self.inscr_est,
                     "inscr_mun": self.inscr_mun,
                     "suframa": self.suframa,
-                    "legal_nature": self.legal_nature,
+                    "legal_nature_id": self.legal_nature_id.id,
                     "equity_capital": self.equity_capital,
                     "cnae_main_id": self.cnae_main_id.id,
                     "cnae_secondary_ids": [(6, 0, self.cnae_secondary_ids.ids)],
diff --git a/l10n_br_crm_cnpj_search/views/crm_lead_form.xml b/l10n_br_crm_cnpj_search/views/crm_lead_form.xml
index 9fb9da7be2a4..35b84664176b 100644
--- a/l10n_br_crm_cnpj_search/views/crm_lead_form.xml
+++ b/l10n_br_crm_cnpj_search/views/crm_lead_form.xml
@@ -53,7 +53,7 @@
             <page name="lead" position="inside">
                 <group string="Fiscal">
                     <group>
-                        <field name="legal_nature" string="Natureza jurídica" />
+                        <field name="legal_nature_id" string="Natureza jurídica" />
                         <field name="equity_capital" string="Capital social" />
                     </group>
                     <group>
diff --git a/l10n_br_crm_cnpj_search/wizard/partner_cnpj_search_wizard.py b/l10n_br_crm_cnpj_search/wizard/partner_cnpj_search_wizard.py
index f908a02b6c13..bfc80b95aa03 100644
--- a/l10n_br_crm_cnpj_search/wizard/partner_cnpj_search_wizard.py
+++ b/l10n_br_crm_cnpj_search/wizard/partner_cnpj_search_wizard.py
@@ -41,7 +41,7 @@ def action_update_partner(self):
                 "phone": self.phone,
                 "mobile": self.mobile,
                 "email_from": self.email,
-                "legal_nature": self.legal_nature,
+                "legal_nature_id": self.legal_nature_id.id,
                 "equity_capital": self.equity_capital,
                 "cnae_main_id": self.cnae_main_id.id,
                 "cnae_secondary_ids": [(6, 0, self.cnae_secondary_ids.ids)]
diff --git a/l10n_br_fiscal/__manifest__.py b/l10n_br_fiscal/__manifest__.py
index d3b4b0971700..ac9bcbe01ed2 100644
--- a/l10n_br_fiscal/__manifest__.py
+++ b/l10n_br_fiscal/__manifest__.py
@@ -38,6 +38,7 @@
         "data/l10n_br_fiscal_server_action.xml",
         "data/ir_cron.xml",
         "data/l10n_br_fiscal_comment_data.xml",
+        "data/l10n_br_fiscal.legal.nature.csv",
         "data/l10n_br_fiscal.cnae.csv",
         "data/l10n_br_fiscal.cfop.csv",
         "data/l10n_br_fiscal_cfop_data.xml",
@@ -58,6 +59,7 @@
         "data/l10n_br_fiscal.cest.csv",
         "data/l10n_br_fiscal_icms_tax_definition_data.xml",
         # Views
+        "views/legal_nature_view.xml",
         "views/cnae_view.xml",
         "views/cfop_view.xml",
         "views/comment_view.xml",
diff --git a/l10n_br_fiscal/data/l10n_br_fiscal.legal.nature.csv b/l10n_br_fiscal/data/l10n_br_fiscal.legal.nature.csv
new file mode 100644
index 000000000000..0e6da13c1cf7
--- /dev/null
+++ b/l10n_br_fiscal/data/l10n_br_fiscal.legal.nature.csv
@@ -0,0 +1,82 @@
+"id","code","name"
+"legal_nature_1015","101-5","Órgão Público do Poder Executivo Federal"
+"legal_nature_1023","102-3","Órgão Público do Poder Executivo Estadual ou do Distrito Federal"
+"legal_nature_1031","103-1","Órgão Público do Poder Executivo Municipal"
+"legal_nature_1040","104-0","Órgão Público do Poder Legislativo Federal"
+"legal_nature_1058","105-8","Órgão Público do Poder Legislativo Estadual ou do Distrito Federal"
+"legal_nature_1066","106-6","Órgão Público do Poder Legislativo Municipal"
+"legal_nature_1074","107-4","Órgão Público do Poder Judiciário Federal"
+"legal_nature_1082","108-2","Órgão Público do Poder Judiciário Estadual"
+"legal_nature_1104","110-4","Autarquia Federal"
+"legal_nature_1112","111-2","Autarquia Estadual ou do Distrito Federal"
+"legal_nature_1120","112-0","Autarquia Municipal"
+"legal_nature_1139","113-9","Fundação Pública de Direito Público Federal"
+"legal_nature_1147","114-7","Fundação Pública de Direito Público Estadual ou do Distrito Federal"
+"legal_nature_1155","115-5","Fundação Pública de Direito Público Municipal"
+"legal_nature_1163","116-3","Órgão Público Autônomo Federal"
+"legal_nature_1171","117-1","Órgão Público Autônomo Estadual ou do Distrito Federal"
+"legal_nature_1180","118-0","Órgão Público Autônomo Municipal"
+"legal_nature_1198","119-8","Comissão Polinacional"
+"legal_nature_1201","120-1","Fundo Público"
+"legal_nature_1210","121-0","Consórcio Público de Direito Público (Associação Pública)"
+"legal_nature_1228","122-8","Consórcio Público de Direito Privado"
+"legal_nature_1236","123-6","Estado ou Distrito Federal"
+"legal_nature_1244","124-4","Município"
+"legal_nature_1252","125-2","Fundação Pública de Direito Privado Federal"
+"legal_nature_1260","126-0","Fundação Pública de Direito Privado Estadual ou do Distrito Federal"
+"legal_nature_1279","127-9","Fundação Pública de Direito Privado Municipal"
+"legal_nature_1287","128-7","Fundo Público da Administração Indireta Federal"
+"legal_nature_1295","129-5","Fundo Público da Administração Indireta Estadual ou do Distrito Federal"
+"legal_nature_1309","130-9","Fundo Público da Administração Indireta Municipal"
+"legal_nature_1317","131-7","Fundo Público da Administração Direta Federal"
+"legal_nature_1325","132-5","Fundo Público da Administração Direta Estadual ou do Distrito Federal"
+"legal_nature_1333","133-3","Fundo Público da Administração Direta Municipal"
+"legal_nature_2011","201-1","Empresa Pública"
+"legal_nature_2038","203-8","Sociedade de Economia Mista"
+"legal_nature_2046","204-6","Sociedade Anônima Aberta"
+"legal_nature_2054","205-4","Sociedade Anônima Fechada"
+"legal_nature_2062","206-2","Sociedade Empresária Limitada"
+"legal_nature_2070","207-0","Sociedade Empresária em Nome Coletivo"
+"legal_nature_2089","208-9","Sociedade Empresária em Comandita Simples"
+"legal_nature_2097","209-7","Sociedade Empresária em Comandita por Ações"
+"legal_nature_2127","212-7","Sociedade em Conta de Participação"
+"legal_nature_2135","213-5","Empresário (Individual)"
+"legal_nature_2143","214-3","Cooperativa"
+"legal_nature_2151","215-1","Consórcio de Sociedades"
+"legal_nature_2160","216-0","Grupo de Sociedades"
+"legal_nature_2178","217-8","Estabelecimento, no Brasil, de Sociedade Estrangeira"
+"legal_nature_2194","219-4","Estabelecimento de Empresa Binacional Argentino-Brasileira"
+"legal_nature_2216","221-6","Empresa Domiciliada no Exterior"
+"legal_nature_2224","222-4","Clube/Fundo de Investimento"
+"legal_nature_2232","223-2","Sociedade Simples Pura"
+"legal_nature_2240","224-0","Sociedade Simples Limitada"
+"legal_nature_2259","225-9","Sociedade Simples em Nome Coletivo"
+"legal_nature_2267","226-7","Sociedade Simples em Comandita Simples"
+"legal_nature_2275","227-5","Empresa Binacional"
+"legal_nature_2283","228-3","Consórcio de Empregadores"
+"legal_nature_2291","229-1","Consórcio Simples"
+"legal_nature_2321","232-1","Sociedade Unipessoal de Advocacia"
+"legal_nature_2330","233-0","Cooperativas de Consumo"
+"legal_nature_3034","303-4","Serviço Notarial e Registral (Cartório)"
+"legal_nature_3069","306-9","Fundação Privada"
+"legal_nature_3077","307-7","Serviço Social Autônomo"
+"legal_nature_3085","308-5","Condomínio Edilício"
+"legal_nature_3107","310-7","Comissão de Conciliação Prévia"
+"legal_nature_3115","311-5","Entidade de Mediação e Arbitragem"
+"legal_nature_3131","313-1","Entidade Sindical"
+"legal_nature_3204","320-4","Estabelecimento, no Brasil, de Fundação ou Associação Estrangeiras"
+"legal_nature_3212","321-2","Fundação ou Associação domiciliada no exterior"
+"legal_nature_3220","322-0","Organização Religiosa"
+"legal_nature_3239","323-9","Comunidade Indígena"
+"legal_nature_3247","324-7","Fundo Privado"
+"legal_nature_3255","325-5","Órgão de Direção Nacional de Partido Político"
+"legal_nature_3263","326-3","Órgão de Direção Regional de Partido Político"
+"legal_nature_3271","327-1","Órgão de Direção Local de Partido Político"
+"legal_nature_3301","330-1","Organização Social (OS)"
+"legal_nature_3999","399-9","Associação Privada"
+"legal_nature_4014","401-4","Empresa Individual Imobiliária"
+"legal_nature_4090","409-0","Candidato a Cargo Político Eletivo"
+"legal_nature_4120","412-0","Produtor Rural (Pessoa Física)"
+"legal_nature_5010","501-0","Organização Internacional"
+"legal_nature_5029","502-9","Representação Diplomática Estrangeira"
+"legal_nature_5037","503-7","Outras Instituições Extraterritoriais"
diff --git a/l10n_br_fiscal/demo/company_demo.xml b/l10n_br_fiscal/demo/company_demo.xml
index 0ecc414a23a6..7abc78e51228 100644
--- a/l10n_br_fiscal/demo/company_demo.xml
+++ b/l10n_br_fiscal/demo/company_demo.xml
@@ -7,6 +7,7 @@
             name="fiscal_profile_id"
             ref="l10n_br_fiscal.partner_fiscal_profile_snc"
         />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
     </record>
 
     <!-- Empresa Lucro Presumido -->
@@ -15,6 +16,7 @@
             name="fiscal_profile_id"
             ref="l10n_br_fiscal.partner_fiscal_profile_cnt"
         />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
     </record>
 
     <!-- Empresa Simples Nacional -->
@@ -23,6 +25,7 @@
             name="fiscal_profile_id"
             ref="l10n_br_fiscal.partner_fiscal_profile_snc"
         />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
     </record>
 
     <!-- Sua Empresa -->
@@ -36,6 +39,7 @@
         />
         <field name="tax_ipi_id" ref="l10n_br_fiscal.tax_ipi_outros" />
         <field name="tax_icms_id" ref="l10n_br_fiscal.tax_icms_sn_com_credito" />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
         <field name="cnae_main_id" ref="l10n_br_fiscal.cnae_3101200" />
         <field name="document_type_id" ref="l10n_br_fiscal.document_55" />
     </record>
@@ -107,6 +111,7 @@
         <field name="is_industry" eval="True" />
         <field name="ripi" eval="True" />
         <field name="icms_regulation_id" ref="tax_icms_regulation" />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
         <field name="cnae_main_id" ref="l10n_br_fiscal.cnae_3101200" />
         <field name="piscofins_id" ref="l10n_br_fiscal.tax_pis_cofins_columativo" />
         <field name="document_type_id" ref="l10n_br_fiscal.document_55" />
@@ -196,6 +201,7 @@
         />
         <field name="tax_ipi_id" ref="l10n_br_fiscal.tax_ipi_outros" />
         <field name="tax_icms_id" ref="l10n_br_fiscal.tax_icms_sn_com_credito" />
+        <field name="legal_nature_id" ref="l10n_br_fiscal.legal_nature_2062" />
         <field name="cnae_main_id" ref="l10n_br_fiscal.cnae_3101200" />
         <field name="document_type_id" ref="l10n_br_fiscal.document_55" />
         <field name="annual_revenue">815000.00</field>
diff --git a/l10n_br_fiscal/models/__init__.py b/l10n_br_fiscal/models/__init__.py
index e10417f83eee..9edbedd64c41 100644
--- a/l10n_br_fiscal/models/__init__.py
+++ b/l10n_br_fiscal/models/__init__.py
@@ -12,6 +12,7 @@
 from . import ibpt
 from . import cfop
 from . import cst
+from . import legal_nature
 from . import cnae
 from . import nbs
 from . import service_type
diff --git a/l10n_br_fiscal/models/legal_nature.py b/l10n_br_fiscal/models/legal_nature.py
new file mode 100644
index 000000000000..2fd51433c5c8
--- /dev/null
+++ b/l10n_br_fiscal/models/legal_nature.py
@@ -0,0 +1,20 @@
+# Copyright (C) 2025  Renato Lima - Akretion <renato.lima@akretion.com.br>
+# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
+
+from odoo import fields, models
+
+
+class LegalNature(models.Model):
+    _name = "l10n_br_fiscal.legal.nature"
+    _inherit = "l10n_br_fiscal.data.abstract"
+    _description = "Legal Nature"
+
+    code = fields.Char(size=5)
+
+    _sql_constraints = [
+        (
+            "fiscal_legal_nature_code_uniq",
+            "unique (code)",
+            "Legal Nature already exists with this code !",
+        )
+    ]
diff --git a/l10n_br_fiscal/models/res_company.py b/l10n_br_fiscal/models/res_company.py
index da971a3a5ef8..50ffb34f1540 100644
--- a/l10n_br_fiscal/models/res_company.py
+++ b/l10n_br_fiscal/models/res_company.py
@@ -45,9 +45,15 @@ def _get_company_address_field_names(self):
         partner_fields = super()._get_company_address_field_names()
         return partner_fields + [
             "tax_framework",
+            "legal_nature_id",
             "cnae_main_id",
         ]
 
+    def _inverse_legal_nature_id(self):
+        """Write the l10n_br specific functional fields."""
+        for c in self:
+            c.partner_id.legal_nature_id = c.legal_nature_id
+
     def _inverse_cnae_main_id(self):
         """Write the l10n_br specific functional fields."""
         for c in self:
@@ -105,6 +111,13 @@ def _compute_simplified_tax(self):
                         record.currency_id.decimal_places,
                     )
 
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+        compute="_compute_address",
+        inverse="_inverse_legal_nature_id",
+    )
+
     cnae_main_id = fields.Many2one(
         comodel_name="l10n_br_fiscal.cnae",
         compute="_compute_address",
diff --git a/l10n_br_fiscal/models/res_partner.py b/l10n_br_fiscal/models/res_partner.py
index c029c1d65f8b..2106eaf4942b 100644
--- a/l10n_br_fiscal/models/res_partner.py
+++ b/l10n_br_fiscal/models/res_partner.py
@@ -33,12 +33,23 @@ def _default_fiscal_profile_id(self, is_company=False):
         tracking=True,
     )
 
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+    )
+
     cnae_main_id = fields.Many2one(
         comodel_name="l10n_br_fiscal.cnae",
         domain=[("internal_type", "=", "normal")],
         string="Main CNAE",
     )
 
+    cnae_secondary_ids = fields.Many2many(
+        comodel_name="l10n_br_fiscal.cnae",
+        domain="[('internal_type', '=', 'normal'), ('id', '!=', cnae_main_id)]",
+        string="Secondary CNAEs",
+    )
+
     ind_ie_dest = fields.Selection(
         selection=NFE_IND_IE_DEST,
         string="Contribuinte do ICMS",
diff --git a/l10n_br_fiscal/security/ir.model.access.csv b/l10n_br_fiscal/security/ir.model.access.csv
index 4cbb169787f5..2216836226b1 100644
--- a/l10n_br_fiscal/security/ir.model.access.csv
+++ b/l10n_br_fiscal/security/ir.model.access.csv
@@ -1,4 +1,7 @@
 "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"l10n_br_fiscal_legal_nature_user","Legal Nature for User","model_l10n_br_fiscal_legal_nature","l10n_br_fiscal.group_user",1,0,0,0
+"l10n_br_fiscal_legal_nature_manager","Legal Nature for Manager","model_l10n_br_fiscal_legal_nature","l10n_br_fiscal.group_manager",1,0,0,0
+"l10n_br_fiscal_legal_nature_maintenance","Legal Nature for Data Maintenance","model_l10n_br_fiscal_legal_nature","l10n_br_fiscal.group_data_maintenance",1,1,1,1
 "l10n_br_fiscal_cnae_user","CNAE for User","model_l10n_br_fiscal_cnae","l10n_br_fiscal.group_user",1,0,0,0
 "l10n_br_fiscal_cnae_manager","CNAE for Manager","model_l10n_br_fiscal_cnae","l10n_br_fiscal.group_manager",1,0,0,0
 "l10n_br_fiscal_cnae_maintenance","CNAE for Data Maintenance","model_l10n_br_fiscal_cnae","l10n_br_fiscal.group_data_maintenance",1,1,1,1
diff --git a/l10n_br_fiscal/views/l10n_br_fiscal_action.xml b/l10n_br_fiscal/views/l10n_br_fiscal_action.xml
index 388fd5d1cf62..270b635fd07f 100644
--- a/l10n_br_fiscal/views/l10n_br_fiscal_action.xml
+++ b/l10n_br_fiscal/views/l10n_br_fiscal_action.xml
@@ -15,6 +15,23 @@
         </field>
     </record>
 
+    <!-- Legal Nature -->
+    <record id="legal_nature_action" model="ir.actions.act_window">
+        <field name="name">Legal Nature</field>
+        <field name="type">ir.actions.act_window</field>
+        <field name="res_model">l10n_br_fiscal.legal.nature</field>
+        <field name="view_mode">tree,form</field>
+        <field name="view_id" ref="legal_nature_tree" />
+        <field name="help" type="html">
+            <p class="o_view_nocontent_smiling_face">
+              Add a new Legal Nature
+            </p><p>
+              A Legal nature is necessary to determine the
+              fiscal definitions for your company.
+            </p>
+        </field>
+    </record>
+
     <!-- CNAE -->
     <record id="cnae_action" model="ir.actions.act_window">
         <field name="name">CNAE</field>
diff --git a/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml b/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml
index c5bfbf53a443..23682cc81dbe 100644
--- a/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml
+++ b/l10n_br_fiscal/views/l10n_br_fiscal_menu.xml
@@ -254,13 +254,22 @@
         sequence="10"
     />
 
+    <!-- Legal Nature -->
+    <menuitem
+        id="legal_nature_menu"
+        action="legal_nature_action"
+        groups="l10n_br_fiscal.group_manager"
+        parent="partners_config_menu"
+        sequence="10"
+    />
+
     <!-- CNAE -->
     <menuitem
         id="cnae_menu"
         action="cnae_action"
         groups="l10n_br_fiscal.group_manager"
         parent="partners_config_menu"
-        sequence="10"
+        sequence="20"
     />
 
     <!-- Partner Profile -->
diff --git a/l10n_br_fiscal/views/legal_nature_view.xml b/l10n_br_fiscal/views/legal_nature_view.xml
new file mode 100644
index 000000000000..c1f7573582e3
--- /dev/null
+++ b/l10n_br_fiscal/views/legal_nature_view.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+
+    <record id="legal_nature_search" model="ir.ui.view">
+        <field name="name">l10n_br_fiscal.legal.nature.search</field>
+        <field name="model">l10n_br_fiscal.legal.nature</field>
+        <field name="arch" type="xml">
+            <search string="Legal Nature">
+                <field name="code" />
+                <field name="name" />
+            </search>
+        </field>
+    </record>
+
+    <record id="legal_nature_tree" model="ir.ui.view">
+        <field name="name">l10n_br_fiscal.legal.nature.tree</field>
+        <field name="model">l10n_br_fiscal.legal.nature</field>
+        <field name="arch" type="xml">
+            <tree>
+                <field name="code" />
+                <field name="name" />
+            </tree>
+        </field>
+    </record>
+
+    <record id="legal_nature_form" model="ir.ui.view">
+        <field name="name">l10n_br_fiscal.legal.nature.form</field>
+        <field name="model">l10n_br_fiscal.legal.nature</field>
+        <field name="arch" type="xml">
+            <form string="Legal Nature">
+                <field name="id" invisible="1" />
+                <sheet>
+                    <group>
+                        <field name="code" />
+                        <field name="name" />
+                    </group>
+                </sheet>
+            </form>
+        </field>
+    </record>
+
+</odoo>
diff --git a/l10n_br_fiscal/views/res_company_view.xml b/l10n_br_fiscal/views/res_company_view.xml
index 87958cdac43f..3b21c47dbfa6 100644
--- a/l10n_br_fiscal/views/res_company_view.xml
+++ b/l10n_br_fiscal/views/res_company_view.xml
@@ -15,6 +15,21 @@
                     <notebook>
                         <page name="tax_framework" string="Tax Framework">
                             <field name="id" invisible="1" />
+                            <group string="CNAE and Legal Nature">
+                                <field
+                                    name="legal_nature_id"
+                                    options="{'no_create': True, 'no_create_edit': True}"
+                                />
+                                <field
+                                    name="cnae_main_id"
+                                    options="{'no_create': True, 'no_create_edit': True}"
+                                />
+                                <field
+                                    name="cnae_secondary_ids"
+                                    widget="many2many_tags"
+                                    options="{'no_create': True, 'no_create_edit': True}"
+                                />
+                            </group>
                             <group string="Tax Framework">
                                 <field name="tax_framework" />
                                 <field name="accountant_id" />
@@ -63,20 +78,6 @@
                                     />
                                 </group>
                             </group>
-                            <group string="CNAE">
-                                <field
-                                    name="cnae_main_id"
-                                    options="{'no_create': True, 'no_create_edit': True}"
-                                />
-                            </group>
-                            <group colspan="4" string="Secondary CNAE">
-                                <field
-                                    colspan="4"
-                                    nolabel="1"
-                                    name="cnae_secondary_ids"
-                                    options="{'no_create': True}"
-                                />
-                            </group>
                         </page>
                         <page name="taxes" string="Taxes">
                             <group name="normal_taxes" string="Default Taxes">
diff --git a/l10n_br_fiscal/views/res_partner_view.xml b/l10n_br_fiscal/views/res_partner_view.xml
index 00aad1d3cd2a..6da8c62ca4d6 100644
--- a/l10n_br_fiscal/views/res_partner_view.xml
+++ b/l10n_br_fiscal/views/res_partner_view.xml
@@ -29,10 +29,19 @@
                         force_save="1"
                         attrs="{'readonly': [('fiscal_profile_id', '!=', False)]}"
                     />
+                    <field
+                        name="legal_nature_id"
+                        options="{'no_create': True, 'no_create_edit': True}"
+                    />
                     <field
                         name="cnae_main_id"
                         options="{'no_create': True, 'no_create_edit': True}"
                     />
+                    <field
+                        name="cnae_secondary_ids"
+                        widget="many2many_tags"
+                        options="{'no_create': True, 'no_create_edit': True}"
+                    />
                     <field name="ind_final" />
                 </group>
             </group>


Reviews:
user: login: mileo
body: só não entendi a mudança de versão do spec ai no meio.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-13T11:15:25Z
user: login: CristianoMafraJunior
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T11:23:30Z
user: login: antoniospneto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T13:19:14Z
user: login: antoniospneto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T13:22:06Z
user: login: renatonlima
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T14:21:13Z
user: login: antoniospneto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T15:07:02Z
user: login: renatonlima
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-13T15:51:18Z
user: login: antoniospneto
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-13T16:18:32Z
user: login: CristianoMafraJunior
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-13T16:21:42Z
user: login: marcelsavegnago
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-13T18:19:52Z
user: login: rvalyi
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-13T19:23:12Z

Review comments:
diff_hunk: @@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <odoo>
-    <record model="ir.ui.view" id="crm_lead_cnpj_search_form_view">
+    <record model="ir.ui.view" id="crm_idad_cnpj_search_form_view">
path: l10n_br_crm_cnpj_search/views/crm_lead_form.xml
user: login: CristianoMafraJunior
body: Esta certo alterar o ID da view?
created_at: 2025-05-13T11:23:24Z
author_association: MEMBER
diff_hunk: @@ -33,12 +33,26 @@ def _default_fiscal_profile_id(self, is_company=False):
         tracking=True,
     )
 
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+    )
+
     cnae_main_id = fields.Many2one(
         comodel_name="l10n_br_fiscal.cnae",
         domain=[("internal_type", "=", "normal")],
         string="Main CNAE",
     )
 
+    cnae_secondary_ids = fields.Many2many(
+        comodel_name="l10n_br_fiscal.cnae",
+        relation="res_partner_fiscal_cnae_rel",
+        column1="company_id",
+        column2="cnae_id",
+        domain="[('internal_type', '=', 'normal'), ('id', '!=', cnae_main_id)]",
+        string="Secondary CNAE",
path: l10n_br_fiscal/models/res_partner.py
user: login: antoniospneto
body: ```suggestion
        string="Secondary CNAEs",
```
por ser um many2many acho que pode ser no plural aqui
created_at: 2025-05-13T13:19:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,12 +33,26 @@ def _default_fiscal_profile_id(self, is_company=False):
         tracking=True,
     )
 
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+    )
+
     cnae_main_id = fields.Many2one(
         comodel_name="l10n_br_fiscal.cnae",
         domain=[("internal_type", "=", "normal")],
         string="Main CNAE",
     )
 
+    cnae_secondary_ids = fields.Many2many(
+        comodel_name="l10n_br_fiscal.cnae",
+        relation="res_partner_fiscal_cnae_rel",
+        column1="company_id",
+        column2="cnae_id",
path: l10n_br_fiscal/models/res_partner.py
user: login: antoniospneto
body: aqui eu acho que podia deixar em branco, pra ORM criar com a propria convenção.
por exemplo ali o column1 já ia ficar errado, pois o correto é partner_id não company_id.
created_at: 2025-05-13T13:22:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -33,12 +33,26 @@ def _default_fiscal_profile_id(self, is_company=False):
         tracking=True,
     )
 
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
+    )
+
     cnae_main_id = fields.Many2one(
         comodel_name="l10n_br_fiscal.cnae",
         domain=[("internal_type", "=", "normal")],
         string="Main CNAE",
     )
 
+    cnae_secondary_ids = fields.Many2many(
+        comodel_name="l10n_br_fiscal.cnae",
+        relation="res_partner_fiscal_cnae_rel",
+        column1="company_id",
+        column2="cnae_id",
path: l10n_br_fiscal/models/res_partner.py
user: login: renatonlima
body: Esse campo eu havia movido do módulo l10n_br_cnpj_search para o l10n_br_fiscal e concordo com você, removi os argumentos que define o m2m para deixar o ORM gerenciar esses atributos
created_at: 2025-05-13T14:21:12Z
author_association: MEMBER
diff_hunk: @@ -14,7 +14,10 @@ class PartyMixin(models.AbstractModel):
 
     cnae_main_id = fields.Many2one(comodel_name="l10n_br_fiscal.cnae")
 
-    legal_nature = fields.Char()
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
path: l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py
user: login: antoniospneto
body: Acho que aqui vai dar warning da string ser redundante não? 
created_at: 2025-05-13T15:01:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <odoo>
-    <record model="ir.ui.view" id="crm_lead_cnpj_search_form_view">
+    <record model="ir.ui.view" id="crm_idad_cnpj_search_form_view">
path: l10n_br_crm_cnpj_search/views/crm_lead_form.xml
user: login: antoniospneto
body: @renatonlima faltou arrumar aqui tbm
created_at: 2025-05-13T15:05:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,7 +14,10 @@ class PartyMixin(models.AbstractModel):
 
     cnae_main_id = fields.Many2one(comodel_name="l10n_br_fiscal.cnae")
 
-    legal_nature = fields.Char()
+    legal_nature_id = fields.Many2one(
+        comodel_name="l10n_br_fiscal.legal.nature",
+        string="Legal Nature",
path: l10n_br_cnpj_search/models/l10n_br_base_party_mixin.py
user: login: renatonlima
body: Essa é uma classe abstrata com o mesmo nome do campo, então a string não vai ser redundante, só teria esse warning se tivesse dos campos diferentes com a mesma string
created_at: 2025-05-13T15:51:18Z
author_association: MEMBER

PR comments:
user: login: OCA-git-bot
created_at: 2025-05-09T21:21:30Z
body: Hi @rvalyi,
some modules you are maintaining are being modified, check this out!
author_association: CONTRIBUTOR
user: login: renatonlima
created_at: 2025-05-13T14:24:55Z
body: @mileo

Eu fiz o rebase da branch agora só tem os commits no PR
author_association: MEMBER
user: login: rvalyi
created_at: 2025-05-13T19:23:36Z
body: /ocabot merge minor
author_association: MEMBER
user: login: OCA-git-bot
created_at: 2025-05-13T19:23:42Z
body: Hey, thanks for contributing! Proceeding to merge this for you.
Prepared branch [16.0-ocabot-merge-pr-3786-by-rvalyi-bump-minor](https://github.com/OCA/l10n-brazil/commits/16.0-ocabot-merge-pr-3786-by-rvalyi-bump-minor), awaiting test results.
author_association: CONTRIBUTOR
user: login: OCA-git-bot
created_at: 2025-05-13T19:50:59Z
body: Congratulations, your PR was merged at 13979dd4cb954d0439020b48203d6aac34c522e4. Thanks a lot for contributing to OCA. ❤️
author_association: CONTRIBUTOR
user: login: marcos-mendez
created_at: 2025-05-26T18:08:55Z
body: Ao atualizar este modulo me deparei com um outro erro:

odoo.tools.convert: while parsing /opt/oca/l10n-brazil/l10n_br_fiscal/data/l10n_br_fiscal_icms_tax_definition_data.xml:4222
Definição Tributária já existe para este ICMS e Grupo Tributário !

View error context:
'-no context-'
 
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/odoo/tools/convert.py", line 698, in _tag_root
    f(rec)
  File "/usr/lib/python3/dist-packages/odoo/tools/convert.py", line 599, in _tag_record
    record = model._load_records([data], self.mode == 'update')
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/models.py", line 4452, in _load_records
    records = self._load_records_create([data['values'] for data in to_create])
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/models.py", line 4363, in _load_records_create
    return self.create(values)
           ^^^^^^^^^^^^^^^^^^^
  File "<decorator-gen-230>", line 2, in create
  File "/usr/lib/python3/dist-packages/odoo/api.py", line 431, in _model_create_multi
    return create(self, arg)
           ^^^^^^^^^^^^^^^^^
  File "/opt/oca/l10n-brazil/l10n_br_fiscal/models/tax_definition.py", line 377, in create
    create_super = super().create(vals_list)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<decorator-gen-50>", line 2, in create
  File "/usr/lib/python3/dist-packages/odoo/api.py", line 431, in _model_create_multi
    return create(self, arg)
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/addons/mail/models/mail_thread.py", line 258, in create
    threads = super(MailThread, self).create(vals_list)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<decorator-gen-18>", line 2, in create
  File "/usr/lib/python3/dist-packages/odoo/api.py", line 431, in _model_create_multi
    return create(self, arg)
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/addons/base/models/ir_fields.py", line 670, in create
    recs = super().create(vals_list)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<decorator-gen-0>", line 2, in create
  File "/usr/lib/python3/dist-packages/odoo/api.py", line 431, in _model_create_multi
    return create(self, arg)
           ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/models.py", line 4019, in create
    records = self._create(data_list)
              ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/odoo/models.py", line 4271, in _create
    records._validate_fields(name for data in data_list for name in data['stored'])
  File "/usr/lib/python3/dist-packages/odoo/models.py", line 1373, in _validate_fields
    check(self)
  File "/opt/oca/l10n-brazil/l10n_br_fiscal/models/tax_definition.py", line 525, in _check_icms
    raise ValidationError(

Não deveria ser:

<record id="tax_icms_01" model="l10n_br_fiscal.tax.definition" forcecreate="0">
  <field name="..." />
</record>

Ou seja só atualizar quando há mudanças?

Estou perguntando pois eu não sei se é o normal atualizar sempre estes campos (mesmo eles já estando definidos anteriormente
author_association: NONE
user: login: marcos-mendez
created_at: 2025-05-26T19:12:18Z
body: Perdão o meu comentário:

<record id="tax_icms_01" model="l10n_br_fiscal.tax.definition" forcecreate="0">
  <field name="..." />
</record>
author_association: NONE
user: login: rvalyi
created_at: 2025-05-27T13:30:12Z
body: @marcos-mendez no banco vc provavelmente tinha alguma entrada de l10n_br_fiscal.tax.definition para uma das aliquotas que foi adicionada aqui neste outro PR https://github.com/OCA/l10n-brazil/pull/3768

Tem duas saidas:

1. a melhor: vc pesquisa ou usa breakpoint() para identifiar e ai vc remove as entradas do seu banco antes de dar o update.
2. a porca que pode te salvar um certo tempo: vc roda um "fork" sem esse commit ou sem o registro que deu problema no XML. Seria uma solução de emergência apenas. 

Esse problema da atualização dos dados fiscais que podem ter sido completados manualmente é um problema mais genérico. Eu comecei a bolar esse PR para ajudar nisso https://github.com/OCA/l10n-brazil/pull/3777

cc @rodmad85 que tb teve o mesmo problema.
author_association: MEMBER