diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c37db5..876fb66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Utilitário `convert_name_to_uf` - Utilitário `is_valid_cnh` [#651](https://github.com/brazilian-utils/brutils-python/pull/651) +- Utilitário `is_valid_renavam` [#652](https://github.com/brazilian-utils/brutils-python/pull/652) ### Fixed diff --git a/README.md b/README.md index 6743cf8..231fcf7 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ False - [format\_legal\_process](#format_legal_process) - [remove\_symbols\_legal\_process](#remove_symbols_legal_process) - [generate\_legal\_process](#generate_legal_process) +- [RENAVAM](#renavam) + - [is_valid_renavam](#is_valid_renavam) - [Titulo Eleitoral](#titulo-eleitoral) - [is\_valid\_voter\_id](#is_valid_voter_id) - [format\_voter\_id](#format_voter_id) @@ -1375,6 +1377,33 @@ Exemplo: None ``` +## RENAVAM + +### is_valid_renavam + +Valida se os dígitos de verificação do RENAVAM fornecido +correspondem aos seus 10 dígitos iniciais. Esta função não verifica a existência do veículo; +ela apenas valida o formato da string e o dígito verificador. + +Argumentos: + +- renavam (str): O RENAVAM a ser validado, uma string de 11 dígitos. + +Retorna: + +- bool: Verdadeiro se o RENAVAM for válido + Falso caso contrário. + +Exemplo: + +```python +>>> from brutils import is_valid_renavam +>>> is_valid_renavam("86769597308") +True +>>> is_valid_renavam("12345678901") +False +``` + # Novos Utilitários e Reportar Bugs Caso queira sugerir novas funcionalidades ou reportar bugs, basta criar diff --git a/README_EN.md b/README_EN.md index b6d6ccf..3efef60 100644 --- a/README_EN.md +++ b/README_EN.md @@ -82,6 +82,8 @@ False - [format\_pis](#format_pis) - [remove\_symbols\_pis](#remove_symbols_pis) - [generate\_pis](#generate_pis) +- [RENAVAM](#renavam) + - [is_valid_renavam](#is_valid_renavam) - [Legal Process](#legal-process) - [is\_valid\_legal\_process](#is_valid_legal_process) - [format\_legal\_process](#format_legal_process) @@ -1379,6 +1381,32 @@ Example: None ``` +## RENAVAM + +### is_valid_renavam + +Validates whether the verification digit of the given RENAVAM +matches its first 10 digits. This function does not check if the vehicle exists; +it only validates the string format and the verification digit. + +Arguments: + +- renavam (str): The RENAVAM to be validated, a string of 11 digits. + +Returns: + +- bool: True if RENAVAM is valid, + False otherwise. + +Example: + +```python +>>> from brutils import is_valid_renavam +>>> is_valid_renavam("86769597308") +True +>>> is_valid_renavam("12345678901") +False + # Feature Request and Bug Report If you want to suggest new features or report bugs, simply create diff --git a/brutils/__init__.py b/brutils/__init__.py index b2fe994..7594fbd 100644 --- a/brutils/__init__.py +++ b/brutils/__init__.py @@ -74,6 +74,9 @@ from brutils.pis import is_valid as is_valid_pis from brutils.pis import remove_symbols as remove_symbols_pis +# RENAVAM Imports +from brutils.renavam import is_valid_renavam + # Voter ID Imports from brutils.voter_id import format_voter_id from brutils.voter_id import generate as generate_voter_id @@ -125,6 +128,8 @@ "generate_pis", "is_valid_pis", "remove_symbols_pis", + # RENAVAM + "is_valid_renavam", # Voter ID "format_voter_id", "generate_voter_id", diff --git a/brutils/renavam.py b/brutils/renavam.py new file mode 100644 index 0000000..a536245 --- /dev/null +++ b/brutils/renavam.py @@ -0,0 +1,56 @@ +RENAVAM_DV_WEIGHTS = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3] + + +def _validate_renavam_format(renavam: str): + if not isinstance(renavam, str): + return False + if len(renavam) != 11 or not renavam.isdigit(): + return False + if len(set(renavam)) == 1: + return False + return True + + +def _sum_weighted_digits(renavam: str) -> int: + base_digits = [int(d) for d in renavam[:-1][::-1]] + return sum(x * y for x, y in zip(base_digits, RENAVAM_DV_WEIGHTS)) + + +def _calculate_renavam_dv(renavam: str): + weighted_sum = _sum_weighted_digits(renavam) + dv = 11 - (weighted_sum % 11) + return 0 if dv >= 10 else dv + + +def is_valid_renavam(renavam: str) -> bool: + """ + Validates the Brazilian vehicle registration number (RENAVAM). + + This function takes a RENAVAM string and checks if it is valid. + A valid RENAVAM consists of exactly 11 digits, with the last digit as + a verification digit calculated from the previous 10 digits. + + Args: + renavam (str): The RENAVAM string to be validated. + + Returns: + bool: True if the RENAVAM is valid, False otherwise. + + Example: + >>> is_valid_renavam('86769597308') + True + >>> is_valid_renavam('12345678901') + False + >>> is_valid_renavam('1234567890a') + False + >>> is_valid_renavam('12345678 901') + False + >>> is_valid_renavam('12345678') + False + >>> is_valid_renavam('') + False + """ + if not _validate_renavam_format(renavam): + return False + + return _calculate_renavam_dv(renavam) == int(renavam[-1]) diff --git a/tests/test_renavam.py b/tests/test_renavam.py new file mode 100644 index 0000000..8ff900e --- /dev/null +++ b/tests/test_renavam.py @@ -0,0 +1,18 @@ +from unittest import TestCase + +from brutils.renavam import is_valid_renavam + + +class TestRENAVAM(TestCase): + def test_is_valid_renavam(self): + self.assertTrue(is_valid_renavam("86769597308")) + self.assertFalse(is_valid_renavam("12345678901")) + self.assertFalse(is_valid_renavam("1234567890a")) + self.assertFalse(is_valid_renavam("12345678 901")) + self.assertFalse(is_valid_renavam("12345678")) + self.assertFalse(is_valid_renavam("")) + self.assertFalse(is_valid_renavam("123456789012")) + self.assertFalse(is_valid_renavam("abcdefghijk")) + self.assertFalse(is_valid_renavam("12345678901!")) + self.assertFalse(is_valid_renavam("00000000000")) + self.assertFalse(is_valid_renavam("11111111111"))