diff --git a/CHANGELOG.md b/CHANGELOG.md index b1546edc..ef1216c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Utilitário `convert_code_to_uf` [#397](https://github.com/brazilian-utils/brutils-python/pull/410) +- Utilitário `is_valid_renavam` [#430](https://github.com/brazilian-utils/brutils-python/pull/440) + ## [2.2.0] - 2024-09-12 ### Added diff --git a/README.md b/README.md index 73769b04..5718ba61 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ False - [generate_voter_id](#generate_voter_id) - [IBGE](#ibge) - [convert_code_to_uf](#convert_code_to_uf) +- [RENAVAM](#renavam) + - [is_valid_renavam](#is_valid_renavam) ## CPF @@ -1109,6 +1111,37 @@ Exemplo: >>> ``` +## RENAVAM + +### is_valid_renavam +Valida o número de registro dos veículos brasileiros (RENAVAM). + +Essa função recebe a string do RENAVAM e veirifíca se está válido. +Um renavam válido é constituído por 11 digitos, onde o último é o digito verificador que é calculado por meio dos 10 digitos anteriores. + +Args: + * renavam (str): A string do RENAVAM para ser validado. + +Retorna: + * bool: Verdadeiro caso o RENAVAM seja válido, Falso caso contrário. + +Exemplo: +```python + >>> is_valid_renavam('12345678900') + True + >>> is_valid_renavam('12345678901') + False + >>> is_valid_renavam('1234567890a') + False + >>> is_valid_renavam('12345678 901') + False + >>> is_valid_renavam('12345678') # Less than 11 digits + False + >>> is_valid_renavam('') # Empty string + False + >>> is_valid_renavam(None) # None + False +``` # Novos Utilitários e Reportar Bugs @@ -1139,4 +1172,4 @@ Vamos construir juntos! 🚀🚀 [github-discussions-doc]: https://docs.github.com/pt/discussions [github-discussions]: https://github.com/brazilian-utils/brutils-python/discussions [github-issues-doc]: https://docs.github.com/pt/issues/tracking-your-work-with-issues/creating-an-issue -[github-issues]: https://github.com/brazilian-utils/brutils-python/issues +[github-issues]: https://github.com/brazilian-utils/brutils-python/issues \ No newline at end of file diff --git a/README_EN.md b/README_EN.md index 7917b673..6fe11b21 100644 --- a/README_EN.md +++ b/README_EN.md @@ -89,7 +89,8 @@ False - [generate_voter_id](#generate_voter_id) - [IBGE](#ibge) - [convert_code_to_uf](#convert_code_to_uf) - +- [RENAVAM](#renavam) + - [is_valid_renavam](#is_valid_renavam) ## CPF ### is_valid_cpf @@ -1112,6 +1113,39 @@ Exemplo: >>> ``` +## RENAVAM + +### is_valid_renavam +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: +```python + >>> is_valid_renavam('12345678900') + True + >>> is_valid_renavam('12345678901') + False + >>> is_valid_renavam('1234567890a') + False + >>> is_valid_renavam('12345678 901') + False + >>> is_valid_renavam('12345678') # Less than 11 digits + False + >>> is_valid_renavam('') # Empty string + False + >>> is_valid_renavam(None) # None + False +``` + # Feature Request and Bug Report If you want to suggest new features or report bugs, simply create @@ -1141,4 +1175,4 @@ Let's build it together 🚀🚀 [github-discussions-doc]: https://docs.github.com/en/discussions [github-discussions]: https://github.com/brazilian-utils/brutils-python/discussions [github-issues-doc]: https://docs.github.com/en/issues/tracking-your-work-with-issues/creating-an-issue -[github-issues]: https://github.com/brazilian-utils/brutils-python/issues +[github-issues]: https://github.com/brazilian-utils/brutils-python/issues \ No newline at end of file diff --git a/brutils/__init__.py b/brutils/__init__.py index 6959a0d0..f5ccf068 100644 --- a/brutils/__init__.py +++ b/brutils/__init__.py @@ -111,6 +111,11 @@ 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, @@ -172,4 +177,6 @@ "is_valid_voter_id", # IBGE "convert_code_to_uf", + # RENAVAM + "is_valid_renavam", ] diff --git a/brutils/renavam.py b/brutils/renavam.py new file mode 100644 index 00000000..c64e1d36 --- /dev/null +++ b/brutils/renavam.py @@ -0,0 +1,47 @@ +def is_valid_renavam(renavam): # type: (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('12345678900') + True + >>> is_valid_renavam('12345678901') + False + >>> is_valid_renavam('1234567890a') + False + >>> is_valid_renavam('12345678 901') + False + >>> is_valid_renavam('12345678') # Less than 11 digits + False + >>> is_valid_renavam('') # Empty string + False + >>> is_valid_renavam(None) # None + False + """ + if renavam and len(renavam) == 11 and renavam.isnumeric(): + check_digit = int(renavam[-1:]) + renavam_digitis = [int(d) for d in renavam] + renavam_digitis = renavam_digitis[:-1] + multipliers = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3] + sum_digits = sum( + digit * multipliers[i] + for i, digit in enumerate(renavam_digitis[::-1]) + ) + remainder_division = sum_digits % 11 + if remainder_division <= 1: + check_digit_calculated = 0 + else: + check_digit_calculated = 11 - remainder_division + if check_digit == check_digit_calculated: + return True + return False diff --git a/tests/test_renavam.py b/tests/test_renavam.py new file mode 100644 index 00000000..d3e7e1d2 --- /dev/null +++ b/tests/test_renavam.py @@ -0,0 +1,38 @@ +from unittest import TestCase + +from brutils.renavam import is_valid_renavam + + +class TestRENAVAM(TestCase): + def test_is_valid_renavam(self): + # Testes para RENAVAM válidos + self.assertFalse(is_valid_renavam("12345678901")) + self.assertFalse(is_valid_renavam("09945438645")) + self.assertFalse(is_valid_renavam("94521237655")) + self.assertFalse(is_valid_renavam("45403264305")) + self.assertFalse(is_valid_renavam("45403471665")) + self.assertFalse(is_valid_renavam("34743721835")) + self.assertFalse(is_valid_renavam("69277208515")) + + self.assertTrue(is_valid_renavam("12345678900")) + self.assertTrue(is_valid_renavam("92876838150")) + self.assertTrue(is_valid_renavam("65720648534")) + self.assertTrue(is_valid_renavam("63601073019")) + self.assertTrue(is_valid_renavam("09945438641")) + self.assertTrue(is_valid_renavam("94521237651")) + self.assertTrue(is_valid_renavam("45403264308")) + self.assertTrue(is_valid_renavam("45403471664")) + self.assertTrue(is_valid_renavam("34743721831")) + self.assertTrue(is_valid_renavam("69277208510")) + + # Testes para entradas inválidas + self.assertFalse(is_valid_renavam("1234567890a")) # Contém letra + self.assertFalse(is_valid_renavam("12345678 901")) # Contém espaço + self.assertFalse(is_valid_renavam("12345678")) # Menos de 11 dígitos + self.assertFalse(is_valid_renavam("")) # String vazia + self.assertFalse(is_valid_renavam("123456789012")) # Mais de 11 dígitos + self.assertFalse(is_valid_renavam("abcdefghijk")) # Apenas letras + self.assertFalse( + is_valid_renavam("12345678901!") + ) # Contém caractere especial + self.assertFalse(is_valid_renavam(None)) # Contém caractere especial