Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cria util de formatação de título eleitoral #247

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ False
- [format_processo_juridico](#format_processo_juridico)
- [remove\_symbols\_processo\_juridico](#remove_symbols_processo_juridico)
- [generate_processo_juridico](#generate_processo_juridico)
- [Título Eleitoral](#título-eleitoral)
- [format_titulo_eleitoral](#format_titulo_eleitoral)
- [is_valid_processo_juridico](#is_valid_processo_juridico)

## CPF
Expand Down Expand Up @@ -557,10 +559,22 @@ Gera um número de processo válido de acordo com o ano informado e o órgão. P
>>>
```

## Título Eleitoral

### format_titulo_eleitoral

Formata título eleitoral (se válido)
```python
>>> from brutils import format_titulo_eleitoral
>>> format_titulo_eleitoral('370834200183')
'3708 3420 01 83'
>>> format_titulo_eleitoral('107381280116')
'1073 8128 01 16'
```

## is_valid_processo_juridico

Verifica se o número de um processo informado por string é válido ou não.

```python
>>> from brutils import is_valid_processo_juridico
>>> is_valid_processo_juridico('10188748220234018200')
Expand All @@ -571,7 +585,6 @@ True
False
>>> is_valid_processo_juridico('455323423QQWEQWSsasd&*(()')
False
>>>
```

# Novos Utilitários e Reportar Bugs
Expand Down
17 changes: 15 additions & 2 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ False
- [format_processo_juridico](#format_processo_juridico)
- [remove\_symbols\_processo\_juridico](#remove_symbols_processo_juridico)
- [generate_processo_juridico](#generate_processo_juridico)
- [Voter Registration Number](#voter-registration-number)
- [format_titulo_eleitoral](#format_titulo_eleitoral)
- [is_valid_processo_juridico](#is_valid_processo_juridico)

## CPF
Expand Down Expand Up @@ -565,10 +567,22 @@ Generates a valid legal process number according to the arguments of _ano_ which
>>>
```

## Voter Registration Number

### format_titulo_eleitoral

Formats voter registration number (if valid)
```python
>>> from brutils import format_titulo_eleitoral
>>> format_titulo_eleitoral('370834200183')
'3708 3420 01 83'
>>> format_titulo_eleitoral('107381280116')
'1073 8128 01 16'
```

## is_valid_processo_juridico

Checks if a string containing a legal process number is valid or not.

```python
>>> from brutils import is_valid_processo_juridico
>>> is_valid_processo_juridico('10188748220234018200')
Expand All @@ -579,7 +593,6 @@ True
False
>>> is_valid_processo_juridico('455323423QQWEQWSsasd&*(()')
False
>>>
```

# Feature Request and Bug Report
Expand Down
2 changes: 2 additions & 0 deletions brutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@
is_valid_processo_juridico,
remove_symbols as remove_symbols_processo_juridico,
)

from brutils.voter_registration import format as format_titulo_eleitoral
77 changes: 77 additions & 0 deletions brutils/voter_registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import re
from typing import Optional

# FORMATTING
############


def format(voter_registration_number: str) -> Optional[str]:
"""
Formats a voter registration number with spaces
Returns None with invalid input
Ex: 017746811074 - > 0177 4681 10 74
117351120817 - > 1173 5112 08 17
6455327 - > 'None'
"""

if not isinstance(voter_registration_number, str) or not _is_valid(
voter_registration_number
):
return None

first_four = voter_registration_number[0:4]
second_four = voter_registration_number[4:8]
federal_unit_numbers = voter_registration_number[8:10]
check_digits = voter_registration_number[10:12]

return f"{first_four} {second_four} {federal_unit_numbers} {check_digits}"


# OPERATIONS
############


def _is_valid(voter_registration_number: str) -> bool:
"""
Checks if the number check digit calculation is correct
Also checks if the Federal Unit identifier is valid (1 - 28)
"""
if not re.match(r"^\d{12}$", voter_registration_number):
return False

fu_identifier = int(voter_registration_number[8:10])

if not (1 <= fu_identifier <= 28):
return False

check_digits = voter_registration_number[10:12]
calculated_check_digits = _calculate_check_digits(voter_registration_number)

return check_digits == calculated_check_digits


def _calculate_check_digits(
voter_registration_number: str,
): # type: (str) -> str
"""
Calculates voter registration number check digits
"""
first_digit_sum = sum(
int(digit) * (index + 2)
for index, digit in enumerate(voter_registration_number[:8])
)
calculated_first_digit = first_digit_sum % 11

if calculated_first_digit == 10:
calculated_first_digit = 0

second_digit_sum = sum(
int(digit) * (index + 7)
for index, digit in enumerate(voter_registration_number[8:11])
)
calculated_second_digit = second_digit_sum % 11

if calculated_second_digit == 10:
calculated_second_digit = 0

return f"{calculated_first_digit}{calculated_second_digit}"
71 changes: 71 additions & 0 deletions tests/test_voter_registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import unittest
from brutils import format_titulo_eleitoral


class TestVoterRegistrationFormat(unittest.TestCase):
def test_valid_number(self):
# Specific number
response = format_titulo_eleitoral("370834200183")
self.assertEqual(
response, "3708 3420 01 83", "AssertionError for 370834200183"
)

def test_valid_numbers_type_and_regexp(self):
# Valid voter registration numbers
valid_numbers = [
"370834200183",
"107381280116",
"587816450175",
"260577100132",
"248146750108",
]
for n in valid_numbers:
try:
formatted = format_titulo_eleitoral(n)
self.assertIsInstance(formatted, str)
self.assertRegex(formatted, r"^(\d{4} \d{4} \d{2} \d{2})$")
except: # noqa: E722
print(f"AssertionError for number: {n}")
raise AssertionError

def test_invalid_registration_numbers(self):
# Invalid voter registration numbers should return None
invalid_numbers = [
"123",
"370834200181",
"107381280111",
"587816450179",
"goiaba",
]
for n in invalid_numbers:
try:
self.assertEqual(format_titulo_eleitoral(n), None)
except: # noqa: E722
print(f"AssertionError for number: {n}")
raise AssertionError

def test_non_string_input(self):
# Non-string input should also return None
non_strings = [None, 123, True, ["test@example.com"]]
for value in non_strings:
self.assertEqual(format_titulo_eleitoral(value), None)

def test_empty_string(self):
# Empty string should return None too
self.assertEqual(format_titulo_eleitoral(""), None)

def test_invalid_fu(self):
# Document with invalid UF should fail
self.assertEqual(format_titulo_eleitoral("370834209983"), None)

def test_mods_equal_zero(self):
# Ensure that digit calculation works when sum equals 10
valid_numbers = ["175526800205", "417667660230"]
for n in valid_numbers:
try:
formatted = format_titulo_eleitoral(n)
self.assertIsInstance(formatted, str)
self.assertRegex(formatted, r"^(\d{4} \d{4} \d{2} \d{2})$")
except: # noqa: E722
print(f"AssertionError for number: {n}")
raise AssertionError