Welcome to the CNPJ Insight project!

How to run

If you want to run locally, you can download the SQLite database in this drive, otherwise, you can check out the cloud-deployed version in http://20.195.169.122:8000/.

Just let the database file in the root folder of the project. If you want to start a new database, you can migrate.

Production

docker-compose -f docker-compose.prod.yml up --build

Access: http://localhost:1337

Development

docker-compose -f docker-compose.yml up --build

Access: http://localhost:8000

In order to run the tests you need to run the following command:

docker-compose -f docker-compose.yml run --rm web python manage.py test

If you have any problems with the docker-compose, try to using the branch dockerless.

Stop

docker-compose down -v

API Reference

Admin

AccountInline

Bases: StackedInline

Admin interface for Account model.

Source code in cnpj/admin.py
class AccountInline(admin.StackedInline):
    """Admin interface for Account model."""

    model: Type[Model] = Account
    can_delete: bool = False
    verbose_name_plural: str = 'Contas'

CNAEsAdmin

Bases: ModelAdmin

Admin interface for CNAEs model.

Source code in cnpj/admin.py
@admin.register(CNAEs)
class CNAEsAdmin(admin.ModelAdmin):
    """Admin interface for CNAEs model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

CustomizedUserAdmin

Bases: UserAdmin

Admin interface for User model with Account inline.

Source code in cnpj/admin.py
class CustomizedUserAdmin(UserAdmin):
    """Admin interface for User model with Account inline."""

    inlines: Tuple[Type[AccountInline], ...] = (AccountInline, )

EstabelecimentosAdmin

Bases: ModelAdmin

Admin interface for Estabelecimentos model.

Source code in cnpj/admin.py
@admin.register(Estabelecimentos)
class EstabelecimentosAdmin(admin.ModelAdmin):
    """Admin interface for Estabelecimentos model."""

    list_display: Tuple[str, str, str] = ('cnpj_basico_id', 'nome_fantasia',
                                          'municipio')
    list_per_page: int = 10

MotivosAdmin

Bases: ModelAdmin

Admin interface for Motivos model.

Source code in cnpj/admin.py
@admin.register(Motivos)
class MotivosAdmin(admin.ModelAdmin):
    """Admin interface for Motivos model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

MunicipiosAdmin

Bases: ModelAdmin

Admin interface for Municipios model.

Source code in cnpj/admin.py
@admin.register(Municipios)
class MunicipiosAdmin(admin.ModelAdmin):
    """Admin interface for Municipios model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

NaturezasAdmin

Bases: ModelAdmin

Admin interface for Naturezas model.

Source code in cnpj/admin.py
@admin.register(Naturezas)
class NaturezasAdmin(admin.ModelAdmin):
    """Admin interface for Naturezas model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

PaisesAdmin

Bases: ModelAdmin

Admin interface for Paises model.

Source code in cnpj/admin.py
@admin.register(Paises)
class PaisesAdmin(admin.ModelAdmin):
    """Admin interface for Paises model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

QualificacoesAdmin

Bases: ModelAdmin

Admin interface for Qualificacoes model.

Source code in cnpj/admin.py
@admin.register(Qualificacoes)
class QualificacoesAdmin(admin.ModelAdmin):
    """Admin interface for Qualificacoes model."""

    list_display: Tuple[str, str] = ('codigo', 'descricao')
    search_fields: Tuple[str, str] = ('codigo', 'descricao')
    list_filter: Tuple[str, str] = ('codigo', 'descricao')
    ordering: Tuple[str, str] = ('codigo', 'descricao')
    list_per_page: int = 10

Apps

CnpjConfig

Bases: AppConfig

Configuration for the Cnpj application.

Source code in cnpj/apps.py
class CnpjConfig(AppConfig):
    """Configuration for the Cnpj application."""

    default_auto_field: str = 'django.db.models.BigAutoField'
    name: str = 'cnpj'

Documents

EmpresasDocument

Bases: Document

Document class for Empresas model.

This class represents a document that will be stored in Elasticsearch. It includes the index name and settings, and the fields that will be included in the document.

Source code in cnpj/documents.py
@registry.register_document
class EmpresasDocument(Document):
    """Document class for Empresas model.

    This class represents a document that will be stored in Elasticsearch.
    It includes the index name and settings, and the fields that will be
    included in the document.
    """

    class Index:
        """Index class for EmpresasDocument.

        This class includes the name of the index 
        in Elasticsearch and its settings.
        """

        name: str = "empresas"
        settings: dict = {"number_of_shards": 1, "number_of_replicas": 1}

    class Django:
        """Django class for EmpresasDocument.

        This class includes the model that the document
        represents and the fields that will be included
        in the document.
        """

        model: type = Empresas
        fields: List[str] = ["razao_social_limpa"]
Django

Django class for EmpresasDocument.

This class includes the model that the document represents and the fields that will be included in the document.

Source code in cnpj/documents.py
class Django:
    """Django class for EmpresasDocument.

    This class includes the model that the document
    represents and the fields that will be included
    in the document.
    """

    model: type = Empresas
    fields: List[str] = ["razao_social_limpa"]
Index

Index class for EmpresasDocument.

This class includes the name of the index in Elasticsearch and its settings.

Source code in cnpj/documents.py
class Index:
    """Index class for EmpresasDocument.

    This class includes the name of the index 
    in Elasticsearch and its settings.
    """

    name: str = "empresas"
    settings: dict = {"number_of_shards": 1, "number_of_replicas": 1}

Forms

UserRegistrationForm

Bases: UserCreationForm

Form for registering a new user.

Inherits from UserCreationForm and adds an email field.

Source code in cnpj/forms.py
class UserRegistrationForm(UserCreationForm):
    """Form for registering a new user.

    Inherits from UserCreationForm and adds an email field.
    """
    email: forms.EmailField = forms.EmailField()

    class Meta:
        model: type = User
        fields: list[str] = ["username", "email", "password1", "password2"]

Models

Account

Bases: Model

Model representing a user account.

Source code in cnpj/models.py
class Account(Model):
    """
    Model representing a user account.
    """
    user: OneToOneField[User] = OneToOneField(User, on_delete=CASCADE)
    search_history: JSONField = JSONField(null=True, default=list)
    favorite_list: JSONField = JSONField(null=True, default=list)

    class Meta:
        """
        Meta class for Account model.
        verbose_name: Human readable singular name for the model.
        verbose_name_plural: Human readable plural name for the model.
        """
        verbose_name = 'Conta'
        verbose_name_plural = 'Contas'
Meta

Meta class for Account model. verbose_name: Human readable singular name for the model. verbose_name_plural: Human readable plural name for the model.

Source code in cnpj/models.py
class Meta:
    """
    Meta class for Account model.
    verbose_name: Human readable singular name for the model.
    verbose_name_plural: Human readable plural name for the model.
    """
    verbose_name = 'Conta'
    verbose_name_plural = 'Contas'

BaseModel

Bases: ABC

Abstract base class representing common structure for models.

Source code in cnpj/models.py
class BaseModel(ABC):
    """Abstract base class representing common structure for models."""
    codigo = models.PositiveIntegerField(primary_key=True)
    descricao = models.TextField(null=True, default=None)

    @abstractmethod
    def __str__(self) -> str:
        return f"{self.codigo}"

CNAEs

Bases: Model

Model representing CNAEs (National Classification of Economic Activities).

Source code in cnpj/models.py
class CNAEs(Model):
    """Model representing CNAEs (National Classification
    of Economic Activities).
    """
    codigo = PositiveIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Empresas

Bases: Model

Model representing companies.

Source code in cnpj/models.py
class Empresas(Model):
    """Model representing companies."""
    cnpj_basico = PositiveBigIntegerField(primary_key=True)
    razao_social = CharField(max_length=RAZAO_SOCIAL_LENGTH,
                             null=True, default=None, db_index=True)
    natureza_juridica = ForeignKey(Naturezas, related_name="empresas",
                                   on_delete=PROTECT)
    qualificacao_resposavel = ForeignKey(Qualificacoes,
                                         related_name="empresas",
                                         on_delete=PROTECT)
    capital_social = FloatField()
    porte_empresa = PositiveSmallIntegerField(null=True, default=None)
    ente_federativo_responsavel = TextField(null=True, default=None)
    razao_social_limpa = TextField(
        max_length=RAZAO_SOCIAL_LENGTH, null=True, default=None, db_index=True
    )

    def __str__(self) -> str:
        return f"{self.cnpj_basico}"

Estabelecimentos

Bases: Model

Model representing establishments.

Source code in cnpj/models.py
class Estabelecimentos(Model):
    """Model representing establishments."""
    cnpj_basico_id = PositiveBigIntegerField(primary_key=True)
    cnpj_ordem = PositiveSmallIntegerField()
    cnpj_dv = PositiveSmallIntegerField()
    matriz_filial = PositiveSmallIntegerField()
    nome_fantasia = TextField(null=True, default=None)
    situacao_cadastral = PositiveSmallIntegerField()
    data_situacao_cadastral = DateField(null=True, default=None)
    motivo_situacao_cadastral = ForeignKey(
        Motivos, related_name="estabelecimentos", on_delete=PROTECT
    )
    nome_cidade_exterior = TextField(null=True, default=None)
    pais = ForeignKey(
        Paises, null=True, default=None, related_name="estabelecimentos",
        on_delete=PROTECT
    )
    data_inicio_atividade = DateField(null=True, default=None)
    cnae_fiscal_principal = ForeignKey(CNAEs, related_name="estabelecimentos",
                                       on_delete=PROTECT)
    cnae_fiscal_secundaria = TextField(null=True, default=None)
    tipo_logradouro = TextField(null=True, default=None)
    logradouro = TextField(null=True, default=None)
    numero = TextField(null=True, default=None)
    complemento = TextField(null=True, default=None)
    bairro = TextField(null=True, default=None)
    cep = TextField(null=True, default=None)
    uf = CharField(max_length=UF_LENGTH)
    municipio = ForeignKey(Municipios, related_name="estabelecimentos",
                           on_delete=PROTECT)
    ddd1 = TextField(null=True, default=None)
    telefone1 = TextField(null=True, default=None)
    ddd2 = TextField(null=True, default=None)
    telefone2 = TextField(null=True, default=None)
    ddd_fax = TextField(null=True, default=None)
    fax = TextField(null=True, default=None)
    correio_eletronico = TextField(null=True, default=None)
    situacao_especial = TextField(null=True, default=None)
    data_situacao_especial = DateField(null=True, default=None)
    cnpj_completo = TextField(null=True, default=None)

    def __str__(self):
        return f"{self.cnpj_basico_id}"

Motivos

Bases: Model

Model representing reasons.

Source code in cnpj/models.py
class Motivos(Model):
    """Model representing reasons."""
    codigo = PositiveSmallIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Municipios

Bases: Model

Model representing municipalities.

Source code in cnpj/models.py
class Municipios(Model):
    """Model representing municipalities."""
    codigo = PositiveSmallIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Naturezas

Bases: Model

Model representing legal natures.

Source code in cnpj/models.py
class Naturezas(Model):
    """Model representing legal natures."""
    codigo = PositiveSmallIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Paises

Bases: Model

Model representing countries.

Source code in cnpj/models.py
class Paises(Model):
    """Model representing countries."""
    codigo = PositiveSmallIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Qualificacoes

Bases: Model

Model representing qualifications.

Source code in cnpj/models.py
class Qualificacoes(Model):
    """Model representing qualifications."""
    codigo = PositiveSmallIntegerField(primary_key=True)
    descricao = TextField(null=True, default=None)

    def __str__(self) -> str:
        return f"{self.codigo}"

Simples

Bases: Model

Model representing Simples.

Source code in cnpj/models.py
class Simples(Model):
    """Model representing Simples."""
    cnpj_basico = ForeignKey(Empresas, related_name="simples",
                             primary_key=True, on_delete=PROTECT)
    opcao_simples = BooleanField()
    data_opcao_simples = DateField(null=True, default=None)
    data_exclusao_simples = DateField(null=True, default=None)
    opcao_mei = BooleanField()
    data_opcao_mei = DateField(null=True, default=None)
    data_exclusao_mei = DateField(null=True, default=None)

    def __str__(self):
        return f"{self.cnpj_basico}"

Socios

Bases: Model

Model representing partners.

Source code in cnpj/models.py
class Socios(Model):
    """Model representing partners."""
    cnpj_basico = ForeignKey(Empresas, related_name="socios",
                             on_delete=PROTECT)
    identificador_socio = PositiveSmallIntegerField()
    nome_socio = CharField(max_length=SOCIO_LENGTH, null=True, default=None,
                           db_index=True)
    cnpj_cpf_socio = CharField(max_length=CPNJ_CPF_SOCIO_LENGTH, null=True,
                               default=None)
    qualificacao_socio = ForeignKey(Qualificacoes, related_name="socios",
                                    on_delete=PROTECT)
    data_entrada_sociedade = DateField()
    pais = ForeignKey(Paises, null=True, default=None, related_name="socios",
                      on_delete=PROTECT)
    representante_legal = CharField(max_length=REPRESENTANTE_LEGAL_LENGTH,
                                    null=True, default=None)
    nome_representante = TextField(null=True, default=None)
    qualificacao_representante_legal = ForeignKey(
        Qualificacoes,
        related_name="socios_representante",
        on_delete=PROTECT,
    )
    faixa_etaria = PositiveSmallIntegerField()

    class Meta:
        """
        Meta class for Socios model.
        unique_together: Fields that should be unique together.
        verbose_name: Human readable singular name for the model.
        verbose_name_plural: Human readable plural name for the model.
        """
        unique_together = [("cnpj_basico", "nome_socio")]
        verbose_name = "Sócio"
        verbose_name_plural = "Sócios"

    def __str__(self) -> str:
        return f"{self.cnpj_basico}({self.nome_socio})"
Meta

Meta class for Socios model. unique_together: Fields that should be unique together. verbose_name: Human readable singular name for the model. verbose_name_plural: Human readable plural name for the model.

Source code in cnpj/models.py
class Meta:
    """
    Meta class for Socios model.
    unique_together: Fields that should be unique together.
    verbose_name: Human readable singular name for the model.
    verbose_name_plural: Human readable plural name for the model.
    """
    unique_together = [("cnpj_basico", "nome_socio")]
    verbose_name = "Sócio"
    verbose_name_plural = "Sócios"

create_user_account(sender, instance, created, **kwargs)

Create a user account when a new user is created.

Source code in cnpj/models.py
@receiver(post_save, sender=User)
def create_user_account(sender: Model, instance: User, created: bool,
                        **kwargs: Optional[dict]) -> None:
    """
    Create a user account when a new user is created.
    """
    if created:
        Account.objects.create(user=instance)

Structure

boolean(value, _=False)

Convert value to boolean if possible, else return None.

Source code in cnpj/structure.py
def boolean(value: Any, _: bool = False) -> Optional[bool]:
    """Convert value to boolean if possible, else return None."""

    if value is None or value.strip().lower() in ["", "null", "none"]:
        return None

    return value.strip().lower() in ["s", "sim", "y", "yes", "t", "true", "1"]

char(value, _=False)

Convert value to string if possible, else return None.

Source code in cnpj/structure.py
def char(value: Any, _: bool = False) -> Optional[str]:
    """Convert value to string if possible, else return None."""

    if value is None or value.strip().lower() in ["", "null", "none"]:
        return None

    return value.strip()

date(value, _=False)

Convert value to date string if possible, else return None.

Source code in cnpj/structure.py
def date(value: Any, _: bool = False) -> Optional[str]:
    """Convert value to date string if possible, else return None."""

    if value is None or value.strip().lower() in\
            ["", "null", "none", "0", "00000000"]:

        return None
    return value.strip()

float_(value, _=False)

Convert value to float if possible, else return None.

Source code in cnpj/structure.py
def float_(value: Any, _: bool = False) -> Optional[float]:
    """Convert value to float if possible, else return None."""

    if value is None or value.strip().lower() in ["", "null", "none"]:
        return None

    return float(value.replace(",", "."))

foreign_key(model, key)

Return a function that gets or creates a model instance.

Source code in cnpj/structure.py
def foreign_key(model: Type[Model], key: str) ->\
     Callable[[Any], Optional[Union[Model, int]]]:

    """Return a function that gets or creates a model instance."""

    def get(value: Any,
            return_pk: bool = False) -> Optional[Union[Model, int]]:

        if value is None or value.strip().lower() in ["", "null", "none"]:
            return None

        if return_pk:
            return int(value)

        # Get or create a model instance using the provided key
        instance, _ = model.objects.get_or_create(**{key: value})

        return instance

    return get

integer(value, _=False)

Convert value to integer if possible, else return None.

Source code in cnpj/structure.py
def integer(value: Any, _: bool = False) -> Optional[int]:
    """Convert value to integer if possible, else return None."""

    if value is None or value.strip().lower() in ["", "null", "none"]:
        return None

    return int(value)

text(value, _=False)

Convert value to string if possible, else return None.

Source code in cnpj/structure.py
def text(value: Any, _: bool = False) -> Optional[str]:
    """Convert value to string if possible, else return None."""

    if value is None or value.strip().lower() in ["", "null", "none"]:
        return None

    return value.strip()

Tests

TestUrls

Bases: SimpleTestCase

Source code in cnpj/tests/test_urls.py
class TestUrls(SimpleTestCase):
    def test_home_url_resolves(self):
        """
        Test if the home URL resolves to the correct view function.
        """
        url = reverse("home")
        self.assertEquals(resolve(url).func, home)

    def test_search_results_url_resolves(self):
        """
        Test if the search_results URL resolves to the correct view function.
        """
        url = reverse("search_results")
        self.assertEquals(resolve(url).func, search_results)

    def test_analysis_url_resolves(self):
        """
        Test if the analysis URL with an argument resolves to the correct view function.
        """
        url = reverse("analysis", args=[1])
        self.assertEquals(resolve(url).func, analysis)

    def test_register_url_resolves(self):
        """
        Test if the register URL resolves to the correct view function.
        """
        url = reverse("register")
        self.assertEquals(resolve(url).func, register)

    def test_profile_url_resolves(self):
        """
        Test if the profile URL resolves to the correct view function.
        """
        url = reverse("profile")
        self.assertEquals(resolve(url).func, profile)

    def test_search_compare_url_resolves(self):
        """
        Test if the search_compare URL with an argument resolves to the correct view function.
        """
        url = reverse("search_compare", args=[1])
        self.assertEquals(resolve(url).func, search_compare)

    def test_comparison_url_resolves(self):
        """
        Test if the comparison URL with two arguments resolves to the correct view function.
        """
        url = reverse("comparison", args=[1, 2])
        self.assertEquals(resolve(url).func, comparison)
test_analysis_url_resolves()

Test if the analysis URL with an argument resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_analysis_url_resolves(self):
    """
    Test if the analysis URL with an argument resolves to the correct view function.
    """
    url = reverse("analysis", args=[1])
    self.assertEquals(resolve(url).func, analysis)
test_comparison_url_resolves()

Test if the comparison URL with two arguments resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_comparison_url_resolves(self):
    """
    Test if the comparison URL with two arguments resolves to the correct view function.
    """
    url = reverse("comparison", args=[1, 2])
    self.assertEquals(resolve(url).func, comparison)
test_home_url_resolves()

Test if the home URL resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_home_url_resolves(self):
    """
    Test if the home URL resolves to the correct view function.
    """
    url = reverse("home")
    self.assertEquals(resolve(url).func, home)
test_profile_url_resolves()

Test if the profile URL resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_profile_url_resolves(self):
    """
    Test if the profile URL resolves to the correct view function.
    """
    url = reverse("profile")
    self.assertEquals(resolve(url).func, profile)
test_register_url_resolves()

Test if the register URL resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_register_url_resolves(self):
    """
    Test if the register URL resolves to the correct view function.
    """
    url = reverse("register")
    self.assertEquals(resolve(url).func, register)
test_search_compare_url_resolves()

Test if the search_compare URL with an argument resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_search_compare_url_resolves(self):
    """
    Test if the search_compare URL with an argument resolves to the correct view function.
    """
    url = reverse("search_compare", args=[1])
    self.assertEquals(resolve(url).func, search_compare)
test_search_results_url_resolves()

Test if the search_results URL resolves to the correct view function.

Source code in cnpj/tests/test_urls.py
def test_search_results_url_resolves(self):
    """
    Test if the search_results URL resolves to the correct view function.
    """
    url = reverse("search_results")
    self.assertEquals(resolve(url).func, search_results)

TestViews

Bases: TestCase

Source code in cnpj/tests/test_views.py
class TestViews(TestCase):

    def test_home_GET(self):
        """
        Test the GET request for the home view.

        This test verifies that the home view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'home.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        response = client.get(reverse('home'))

        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'home.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_search_results_GET(self):
        """
        Test the GET request for the search results view.

        This test verifies that the search results view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'search_results.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        response = client.get(reverse('search_results'))

        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'search_results.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_analysis_GET(self):
        """
        Test the GET request for the analysis view.

        This test verifies that the analysis view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'details.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        non_existing_pk = 999

        response = client.get(reverse('analysis', args=[non_existing_pk]))
        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'details.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_register_GET(self):
        """
        Test the GET request for the register view.

        This test verifies that the register view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'registration/register.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        response = client.get(reverse('register'))

        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'registration/register.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_profile_GET(self):
        """
        Test the GET request for the profile view.

        This test verifies that the profile view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'profile.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        # Use reverse without any arguments since 'profile' URL pattern doesn't take any
        response = client.get(reverse('profile'))

        # Check that the response status code is 200
        self.assertEquals(response.status_code, 200)

        self.assertTemplateUsed(response, 'profile.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_search_compare_GET(self):
        """
        Test the GET request for the search compare view.

        This test verifies that the search compare view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'search_compare.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        non_existing_pk = 12345678

        # Use reverse with kwargs to create the URL
        url = reverse('search_compare', kwargs={"pk": non_existing_pk})

        response = client.get(url)
        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'search_compare.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')

    def test_comparison_GET(self):
        """
        Test the GET request for the comparison view.

        This test verifies that the comparison view returns a response with a status code of 200.
        It also checks that the correct templates are used: 'comparison.html', 'base.html', 'navbar.html', and 'footer.html'.
        """
        client = Client()

        non_existing_pk1 = 12345678
        non_existing_pk2 = 87654321

        response = client.get(reverse('comparison',
                                        kwargs={'pk1': non_existing_pk1,
                                                'pk2': non_existing_pk2}))
        self.assertEquals(response.status_code, 200)
        self.assertTemplateUsed(response, 'comparison.html')
        self.assertTemplateUsed(response, 'base.html')
        self.assertTemplateUsed(response, 'navbar.html')
        self.assertTemplateUsed(response, 'footer.html')
test_analysis_GET()

Test the GET request for the analysis view.

This test verifies that the analysis view returns a response with a status code of 200. It also checks that the correct templates are used: 'details.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_analysis_GET(self):
    """
    Test the GET request for the analysis view.

    This test verifies that the analysis view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'details.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    non_existing_pk = 999

    response = client.get(reverse('analysis', args=[non_existing_pk]))
    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'details.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_comparison_GET()

Test the GET request for the comparison view.

This test verifies that the comparison view returns a response with a status code of 200. It also checks that the correct templates are used: 'comparison.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_comparison_GET(self):
    """
    Test the GET request for the comparison view.

    This test verifies that the comparison view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'comparison.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    non_existing_pk1 = 12345678
    non_existing_pk2 = 87654321

    response = client.get(reverse('comparison',
                                    kwargs={'pk1': non_existing_pk1,
                                            'pk2': non_existing_pk2}))
    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'comparison.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_home_GET()

Test the GET request for the home view.

This test verifies that the home view returns a response with a status code of 200. It also checks that the correct templates are used: 'home.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_home_GET(self):
    """
    Test the GET request for the home view.

    This test verifies that the home view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'home.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    response = client.get(reverse('home'))

    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'home.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_profile_GET()

Test the GET request for the profile view.

This test verifies that the profile view returns a response with a status code of 200. It also checks that the correct templates are used: 'profile.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_profile_GET(self):
    """
    Test the GET request for the profile view.

    This test verifies that the profile view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'profile.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    # Use reverse without any arguments since 'profile' URL pattern doesn't take any
    response = client.get(reverse('profile'))

    # Check that the response status code is 200
    self.assertEquals(response.status_code, 200)

    self.assertTemplateUsed(response, 'profile.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_register_GET()

Test the GET request for the register view.

This test verifies that the register view returns a response with a status code of 200. It also checks that the correct templates are used: 'registration/register.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_register_GET(self):
    """
    Test the GET request for the register view.

    This test verifies that the register view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'registration/register.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    response = client.get(reverse('register'))

    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'registration/register.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_search_compare_GET()

Test the GET request for the search compare view.

This test verifies that the search compare view returns a response with a status code of 200. It also checks that the correct templates are used: 'search_compare.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_search_compare_GET(self):
    """
    Test the GET request for the search compare view.

    This test verifies that the search compare view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'search_compare.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    non_existing_pk = 12345678

    # Use reverse with kwargs to create the URL
    url = reverse('search_compare', kwargs={"pk": non_existing_pk})

    response = client.get(url)
    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'search_compare.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')
test_search_results_GET()

Test the GET request for the search results view.

This test verifies that the search results view returns a response with a status code of 200. It also checks that the correct templates are used: 'search_results.html', 'base.html', 'navbar.html', and 'footer.html'.

Source code in cnpj/tests/test_views.py
def test_search_results_GET(self):
    """
    Test the GET request for the search results view.

    This test verifies that the search results view returns a response with a status code of 200.
    It also checks that the correct templates are used: 'search_results.html', 'base.html', 'navbar.html', and 'footer.html'.
    """
    client = Client()

    response = client.get(reverse('search_results'))

    self.assertEquals(response.status_code, 200)
    self.assertTemplateUsed(response, 'search_results.html')
    self.assertTemplateUsed(response, 'base.html')
    self.assertTemplateUsed(response, 'navbar.html')
    self.assertTemplateUsed(response, 'footer.html')

Utils

calculate_dv_cnpj(cnpj_base)

Calculates the verification digits (DV) for a given CNPJ base.

Parameters:
  • cnpj_base (int) –

    The CNPJ base to calculate the DV for.

Returns:
  • str( str ) –

    The complete CNPJ with the two verification digits.

Source code in cnpj/utils.py
def calculate_dv_cnpj(cnpj_base: int) -> str:
    """
    Calculates the verification digits (DV) for a given CNPJ base.

    Args:
        cnpj_base (int): The CNPJ base to calculate the DV for.

    Returns:
        str: The complete CNPJ with the two verification digits.
    """
    # Weight for DV calculation
    weight: np.ndarray = np.array([5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])

    if isinstance(cnpj_base, int):
        cnpj_base = str(cnpj_base)

    cnpj_base: np.ndarray = np.array(list(cnpj_base + "0001"), dtype=int)

    # Calculate the first verification digit
    sum_: int = np.sum(cnpj_base * weight)
    remainder: int = sum_ % 11
    dv1: int = 0 if remainder < 2 else 11 - remainder

    # Add the first DV to the CNPJ base
    cnpj_with_dv1: np.ndarray = np.concatenate((cnpj_base, np.array([dv1])))

    # Update the weight for the calculation of the second DV
    weight = np.array([6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2])

    # Calculate the second verification digit
    sum_: int = np.sum(cnpj_with_dv1 * weight)
    remainder: int = sum_ % 11
    dv2: int = 0 if remainder < 2 else 11 - remainder

    result: np.ndarray = np.concatenate((cnpj_with_dv1, np.array([dv2])))

    # Convert result to string
    result_str: str = "".join(str(x) for x in result)

    # Return the complete CNPJ with the two verification digits
    return result_str

confiability_score(cnpj_base)

Calculate the reliability score of a company based on its CNPJ.

Parameters: cnpj_base (int): The base CNPJ of the company.

Returns: str: The reliability score of the company, categorized as "Baixo" (Low), "Médio" (Medium), or "Alto" (High).

Source code in cnpj/utils.py
def confiability_score(cnpj_base: int) -> str:
    """
    Calculate the reliability score of a company based on its CNPJ.

    Parameters:
    cnpj_base (int): The base CNPJ of the company.

    Returns:
    str: The reliability score of the company, categorized as
    "Baixo" (Low), "Médio" (Medium), or "Alto" (High).
    """

    empresa_data_econo: dict = econodata_scrapping(cnpj_base)
    empresa_data_gov: Union[dict, None] = \
        Empresas.objects.filter(cnpj_basico=cnpj_base).values().first()

    if empresa_data_gov is None:
        return "Baixo"

    # Get today's date
    today: datetime.date = datetime.date.today()

    # Get the company date of creation
    opening_date_str: str = empresa_data_econo['data_abertura']
    opening_date: datetime.date = \
        datetime.datetime.strptime(opening_date_str, '%d/%m/%Y').date()

    # Difference in days between today and the company's opening date
    degree_1: int = (today - opening_date).days

    capital: float = empresa_data_gov['capital_social']

    port: float = empresa_data_gov['porte_empresa']

    # Get the number of employees
    no_employees_str: str = empresa_data_econo['n_funcionarios']
    no_employees_list: list = re.findall(r'\d+', no_employees_str)
    no_employees: int = max(map(int, no_employees_list), default=0)

    # Make a score based on the company age
    if degree_1 <= 365:
        degree_1 = 1
    elif degree_1 <= 365*3:
        degree_1 = 2
    elif degree_1 <= 365*5:
        degree_1 = 3
    elif degree_1 <= 365*10:
        degree_1 = 4
    else:
        degree_1 = 5

    # Make a score based on the number of employees
    if no_employees <= 10:
        degree_2 = 1
    elif no_employees <= 100:
        degree_2 = 2
    elif no_employees <= 1000:
        degree_2 = 3
    elif no_employees <= 5000:
        degree_2 = 4
    else:
        degree_2 = 5

    # Make a score based on the company capital
    if capital <= 100:
        degree_3 = 1
    elif capital <= 1000:
        degree_3 = 2
    elif capital <= 10000:
        degree_3 = 3
    elif capital <= 100000:
        degree_3 = 4
    else:
        degree_3 = 5

    # Calculate the overall score
    score: float = (degree_1 + degree_2 + degree_3 + port) / 4

    # Categorize the score
    if score < 2:
        result = "Baixo"
    elif score < 3.5:
        result = "Médio"
    else:
        result = "Alto"

    return result

econodata_scrapping(cnpj_base)

Scrapes data from the Econodata website based on the provided CNPJ number.

Parameters:
  • cnpj_base (int) –

    The base CNPJ number.

Returns:
  • dict( dict ) –

    A dictionary containing the scraped data, including: - cnpj_completo (str): The complete CNPJ number. - nome_fantasia (str): The company's trading name. - atividade_economica (str): The company's economic activity. - porte (str): The company's size. - cnae (str): The company's CNAE code. - n_funcionarios (str): The number of employees in the company. - data_abertura (str): The company's date of establishment. - situacao (str): The company's status. - natureza (str): The company's nature. - cep (str): The company's postal code. - rua (str): The company's street address. - bairro (str): The company's neighborhood. - cidade (str): The company's city. - pais (str): The company's country.

Source code in cnpj/utils.py
def econodata_scrapping(cnpj_base: int) -> dict:
    """
    Scrapes data from the Econodata website based on the provided CNPJ number.

    Args:
        cnpj_base (int): The base CNPJ number.

    Returns:
        dict: A dictionary containing the scraped data, including:
            - cnpj_completo (str): The complete CNPJ number.
            - nome_fantasia (str): The company's trading name.
            - atividade_economica (str): The company's economic activity.
            - porte (str): The company's size.
            - cnae (str): The company's CNAE code.
            - n_funcionarios (str): The number of employees in the company.
            - data_abertura (str): The company's date of establishment.
            - situacao (str): The company's status.
            - natureza (str): The company's nature.
            - cep (str): The company's postal code.
            - rua (str): The company's street address.
            - bairro (str): The company's neighborhood.
            - cidade (str): The company's city.
            - pais (str): The company's country.
    """
    cnpj_completo = calculate_dv_cnpj(cnpj_base)

    website = requests.get(
        f"https://www.econodata.com.br/consulta-empresa/{cnpj_completo}",
        timeout=10
        )

    soup = BeautifulSoup(website.content, 'html.parser')

    dom = etree.HTML(str(soup), parser=etree.HTMLParser(encoding='utf-8'))
    try:
        empresa_data = {
            "cnpj_completo": dom.xpath(
                '//*[@id="receita-section"]/div[2]/div[2]/div[1]/div/div[2]/p'
            )[0].text,
            "nome_fantasia": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[1]/div/div/div[3]/div[2]/h1'
            )[0].text,
            "atividade_economica": dom.xpath(
                '//*[@id="detalhes-section"]/div[2]/div[2]/div[1]/div[2]/\
                    div[2]/div/div/div/div[1]/u/a'
            )[0].text,
            "porte": dom.xpath(
                '//*[@id="detalhes-section"]/div[2]/div[2]/div[3]/div[2]/div[2]/p'
            )[0].text,
            "cnae": dom.xpath(
                '//*[@id="detalhes-section"]/div[2]/div[2]/div[2]/div[2]/\
                    div[2]/div/div/u/a'
            )[0].text,
            "n_funcionarios": dom.xpath(
                '//*[@id="detalhes-section"]/div[2]/div[2]/div[4]/div[2]/div[2]/p'
            )[0].text,
            "data_abertura": dom.xpath(
                '//*[@id="receita-section"]/div[2]/div[2]/div[4]/div/div[2]/p'
            )[0].text,
            "situacao": dom.xpath(
                '//*[@id="receita-section"]/div[2]/div[2]/div[6]/div/div[2]/p'
            )[0].text,
            "natureza": dom.xpath(
                '//*[@id="receita-section"]/div[2]/div[2]/div[5]/div/div[2]/p'
            )[0].text,
            "cep": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[2]/div[2]/div/div[1]/\
                    div[2]/div[2]/div[4]/span'
            )[0].text,
            "rua": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[2]/div[2]/div/div[1]/\
                    div[2]/div[2]/div[1]/span'
            )[0].text,
            "bairro": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[2]/div[2]/div/div[1]/\
                    div[2]/div[2]/div[2]/span'
            )[0].text,
            "cidade": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[2]/div[2]/div/div[1]/\
                    div[2]/div[2]/div[3]/span'
            )[0].text,
            "pais": dom.xpath(
                '//*[@id="__nuxt"]/div/div[1]/div/div[2]/div[2]/div/div[1]/\
                    div[2]/div[2]/div[5]/span'
            )[0].text
        }
    except IndexError:
        empresa_data = {
            "cnpj_completo": None,
            "nome_fantasia": None,
            "atividade_economica": None,
            "porte": None,
            "cnae": None,
            "n_funcionarios": None,
            "data_abertura": None,
            "situacao": None,
            "natureza": None,
            "cep": None,
            "rua": None,
            "bairro": None,
            "cidade": None,
            "pais": None,
        }

    return empresa_data

Views

analysis(request, pk)

View function for analyzing details of a company.

Parameters:
  • request (HttpRequest) –

    The HTTP request object.

  • pk (int) –

    The primary key of the company.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def analysis(request, pk: int) -> HttpResponse:
    """
    View function for analyzing details of a company.

    Args:
        request (HttpRequest): The HTTP request object.
        pk (int): The primary key of the company.

    Returns:
        HttpResponse: The HTTP response object.
    """

    # Fetch the company information from the database
    empresa: Empresas | None = \
        Empresas.objects.filter(cnpj_basico=pk).first()

    if empresa is None:
        return render(request, 'details.html', {})

    # Fetch related establishments from the database
    estabelecimentos: QuerySet = \
        Estabelecimentos.objects.filter(cnpj_basico_id=pk)

    # Perform web scraping using Econodata API
    scrapping: dict = econodata_scrapping(pk)

    # Calculate the reliability score for the company
    confiability: str = confiability_score(pk)

    # Prepare the context data for rendering the template
    context: dict = {
        'empresa': empresa,
        'estabelecimentos': estabelecimentos,
        'scrapping': scrapping,
        'confiability': confiability,
    }

    # Update the search history if the user is authenticated
    if request.user.is_authenticated:
        request.user.account.search_history.append(empresa.cnpj_basico)
        request.user.account.save()

    # Render the details template with the context data
    return render(request, 'details.html', context)

comparison(request, pk1, pk2)

Compare two companies based on their primary keys.

Parameters:
  • request (HttpRequest) –

    The HTTP request object.

  • pk1 (int) –

    The primary key of the first company.

  • pk2 (int) –

    The primary key of the second company.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def comparison(request: HttpRequest, pk1: int, pk2: int) -> HttpResponse:
    """
    Compare two companies based on their primary keys.

    Args:
        request (HttpRequest): The HTTP request object.
        pk1 (int): The primary key of the first company.
        pk2 (int): The primary key of the second company.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Fetch the information of the first selected company
    first_empresa: Empresas | None = \
        Empresas.objects.filter(cnpj_basico=pk1).first()

    # Fetch the information of the second selected company
    second_empresa: Empresas | None = \
        Empresas.objects.filter(cnpj_basico=pk2).first()

    if first_empresa and second_empresa:

        # Fetch web scraping data for the first company
        first_empresa_scrapping: dict = econodata_scrapping(pk1)

        # Fetch web scraping data for the second company
        second_empresa_scrapping: dict = econodata_scrapping(pk2)

        # Calculate reliability score for the first company
        first_empresa_confiability = confiability_score(pk1)

        # Calculate reliability score for the second company
        second_empresa_confiability = confiability_score(pk2)

        # Prepare the context data for rendering the template
        context: dict = {
            'first_empresa': first_empresa,
            'second_empresa': second_empresa,
            'first_empresa_scrapping': first_empresa_scrapping,
            'second_empresa_scrapping': second_empresa_scrapping,
            'first_empresa_confiability': first_empresa_confiability,
            'second_empresa_confiability': second_empresa_confiability,
        }
    else:
        context: dict = {}

    # Render the comparison template with the context data
    return render(request, 'comparison.html', context)

home(request)

Display a random selection of 10 companies on the home page.

Parameters:
  • request (HttpRequest) –

    The HTTP request object.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def home(request) -> HttpResponse:
    """
    Display a random selection of 10 companies on the home page.

    Args:
        request (HttpRequest): The HTTP request object.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Retrieve a random selection of 10 companies from the database
    empresas: QuerySet = Empresas.objects.order_by('?')[:10]

    # Prepare the context data for rendering the template
    context: dict = {
        'empresas': empresas,
    }

    # Render the home template with the context data
    return render(request, 'home.html', context)

profile(response)

Display user profile information, including search history.

Parameters:
  • response (HttpRequest) –

    The HTTP request object.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def profile(response: HttpRequest) -> HttpResponse:
    """
    Display user profile information, including search history.

    Args:
        response (HttpRequest): The HTTP request object.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Check if the user is authenticated
    if response.user.is_authenticated:
        # Retrieve the search history from the user's account
        search_history: list = response.user.account.search_history

        # Fetch companies based on search history
        empresas = Empresas.objects.filter(cnpj_basico__in=search_history)

        # Sort companies based on the order in the search history
        empresas = sorted(empresas,
                          key=lambda empresa:
                          -search_history.index(empresa.cnpj_basico))
    else:
        # If the user is not authenticated, set empresas to an empty list
        empresas = []

    # Prepare the context data for rendering the template
    context: dict = {"empresas": empresas}

    # Render the profile template with the context data
    return render(response, "profile.html", context)

register(response)

Handle user registration.

Parameters:
  • response (HttpRequest) –

    The HTTP request object.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def register(response: HttpRequest) -> HttpResponse:
    """
    Handle user registration.

    Args:
        response (HttpRequest): The HTTP request object.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Check if the form is submitted via POST method
    if response.method == "POST":
        # Create a UserRegistrationForm instance with the submitted data
        form: UserRegistrationForm = UserRegistrationForm(response.POST)

        # Check if the form is valid
        if form.is_valid():
            # Save the user registration data
            form.save()
            # Redirect to the login page after successful registration
            return redirect("/accounts/login")
    else:
        # Create a new instance of UserRegistrationForm
        form: UserRegistrationForm = UserRegistrationForm()

    # Prepare the context data for rendering the template
    context: dict = {"form": form}

    # Render the registration template with the context data
    return render(response, "registration/register.html", context)

search_compare(request, pk)

Allow users to compare a selected company with others based on a search query.

Parameters:
  • request (HttpRequest) –

    The HTTP request object.

  • pk (int) –

    The primary key of the selected company.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def search_compare(request, pk) -> HttpResponse:
    """
    Allow users to compare a selected company
    with others based on a search query.

    Args:
        request (HttpRequest): The HTTP request object.
        pk (int): The primary key of the selected company.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Fetch the information of the first selected company
    first_empresa: Empresas | None = \
        Empresas.objects.filter(cnpj_basico=pk).first()

    # Prepare the context data for rendering the template
    # if first_empresa is not None:
        # Prepare the context data for rendering the template
    context: dict = {'first_empresa': first_empresa}
    # else:
    #     # If the first_empresa is None, set context to an empty dictionary
    #     solver_empresa = Empresas.objects.order_by('?').first()
    #     context: dict = {'first_empresa': solver_empresa}

    # Check if a search query is provided
    if request.GET.get('q'):
        # Extract the search query from the request parameters
        query: str | None = request.GET.get('q')

        # Perform case-insensitive search on cnpj_basico and razao_social
        empresas_list: QuerySet = Empresas.objects.filter(
            Q(cnpj_basico__icontains=query) |
            Q(razao_social__icontains=query)
        )

        # Update the context based on the search query
        context['empresas_list'] = empresas_list

    # Render the search_compare template with the context data
    return render(request, 'search_compare.html', context)

search_results(request)

Display search results based on the given query.

Parameters:
  • request (HttpRequest) –

    The HTTP request object.

Returns:
  • HttpResponse( HttpResponse ) –

    The HTTP response object.

Source code in cnpj/views.py
def search_results(request: HttpRequest) -> HttpResponse:
    """
    Display search results based on the given query.

    Args:
        request (HttpRequest): The HTTP request object.

    Returns:
        HttpResponse: The HTTP response object.
    """
    # Extract the search query from the request parameters
    query: str = request.GET.get('q', '')

    # Perform case-insensitive search on cnpj_basico and razao_social fields
    empresas_list: QuerySet = Empresas.objects.filter(
        Q(cnpj_basico__icontains=query) | Q(razao_social__icontains=query)
    )

    # Prepare the context data for rendering the template
    context = {
        'empresas_list': empresas_list,
    }

    # Render the search results template with the context data
    return render(request, 'search_results.html', context)

Coverage

See in detail the coverage in coverage_report.pdf.

Name                        Stmts   Miss  Cover   Missing
---------------------------------------------------------
cnpj/__init__.py                0      0   100%
cnpj/admin.py                  60      0   100%
cnpj/apps.py                    4      0   100%
cnpj/cron.py                    6      6     0%   1-9
cnpj/documents.py              15      0   100%
cnpj/forms.py                   8      0   100%
cnpj/models.py                124     12    90%   36, 45, 54, 63, 74, 83, 104, 149, 164, 203, 230-231
cnpj/structure.py              41     41     0%   1-142
cnpj/tests/__init__.py          0      0   100%
cnpj/tests/test_forms.py        0      0   100%
cnpj/tests/test_models.py       0      0   100%
cnpj/tests/test_urls.py        25      0   100%
cnpj/tests/test_views.py       69      0   100%
cnpj/urls.py                    3      0   100%
cnpj/utils.py                  83     71    14%   61-90, 117-197, 212-286
cnpj/views.py                  72     23    68%   124-147, 173-180, 216-222, 282-291, 337-349
cnpj_insight/__init__.py        0      0   100%
cnpj_insight/asgi.py            9      9     0%   10-34
cnpj_insight/settings.py       29      0   100%
cnpj_insight/urls.py            4      0   100%
cnpj_insight/wsgi.py            4      4     0%   10-14
manage.py                      12      2    83%   12-13
media/__init__.py               0      0   100%
static/__init__.py              0      0   100%
staticfiles/__init__.py         0      0   100%
templates/__init__.py           0      0   100%
---------------------------------------------------------
TOTAL                         568    168    70%