-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathTituloEleitoral.py
More file actions
139 lines (105 loc) · 4.23 KB
/
TituloEleitoral.py
File metadata and controls
139 lines (105 loc) · 4.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from random import sample
from validate_docbr.DocumentBase import DocumentBase
class TituloEleitoral(DocumentBase):
"""Classe referente ao Título Eleitoral."""
def __init__(self) -> None:
self.digits = list(range(10))
self.first_check_digit_weights = list(range(2, 10))
self.second_check_digit_weights = list(range(7, 10))
self.first_check_digit_doc_slice = slice(0, 8)
self.second_check_digit_doc_slice = slice(8, 10)
def validate(self, doc: str = '') -> bool:
"""Valida o Título Eleitoral.
Args:
doc: Título Eleitoral a ser validado. Aceita com ou sem máscara.
Returns:
True se o Título Eleitoral for válido, False caso contrário.
"""
if not self._validate_input(doc, [' ']):
return False
doc_digits = list(map(int, self._only_digits(doc=doc)))
if len(doc_digits) != 12:
return False
first_check_digit = self._compute_first_check_digit(doc_digits=doc_digits)
second_check_digit = self._compute_second_check_digit(
doc_digits=doc_digits,
first_check_digit=first_check_digit
)
return first_check_digit == doc_digits[-2] \
and second_check_digit == doc_digits[-1]
def generate(self, mask: bool = False) -> str:
"""Gera um Título Eleitoral válido.
Args:
mask: Se True, retorna o Título formatado
(ex: ``XXXX XXXX XXXX``).
Returns:
Título Eleitoral gerado em formato string.
"""
document_digits = [sample(self.digits, 1)[0] for _ in range(8)]
state_identifier = self._generate_valid_state_identifier()
document_digits.extend(map(int, state_identifier))
first_check_digit = self._compute_first_check_digit(doc_digits=document_digits)
second_check_digit = self._compute_second_check_digit(
doc_digits=document_digits,
first_check_digit=first_check_digit
)
document_digits.extend([first_check_digit, second_check_digit])
document = ''.join(map(str, document_digits))
if mask:
return self.mask(doc=document)
return document
def mask(self, doc: str = '') -> str:
"""Coloca a máscara de Título Eleitoral no documento.
Args:
doc: Título Eleitoral com ou sem máscara.
Returns:
Título Eleitoral formatado no padrão ``XXXX XXXX XXXX``.
"""
doc = self._only_digits(doc)
return f'{doc[0:4]} {doc[4:8]} {doc[8:]}'
def _compute_first_check_digit(self, doc_digits: list[int]) -> int:
"""Calcula o primeiro dígito verificador.
Args:
doc_digits: Lista com os dígitos do Título Eleitoral.
Returns:
Primeiro dígito verificador.
"""
digits_to_consider = doc_digits[self.first_check_digit_doc_slice]
total = sum(
digit * weight
for digit, weight in zip(digits_to_consider, self.first_check_digit_weights)
)
if total % 11 == 10:
return 0
return total % 11
def _compute_second_check_digit(
self,
doc_digits: list[int],
first_check_digit: int
) -> int:
"""Calcula o segundo dígito verificador.
Args:
doc_digits: Lista com os dígitos do Título Eleitoral.
first_check_digit: Valor do primeiro dígito verificador.
Returns:
Segundo dígito verificador.
"""
digits_to_consider = doc_digits[self.second_check_digit_doc_slice] \
+ [first_check_digit]
total = sum(
digit * weight
for digit, weight in zip(
digits_to_consider,
self.second_check_digit_weights,
)
)
if total % 11 == 10:
return 0
return total % 11
def _generate_valid_state_identifier(self) -> str:
"""Gera um identificador de estado válido.
Returns:
Identificador de estado com 2 dígitos (``01`` a ``18``).
"""
state_identifier = str(sample(range(1, 19), 1)[0])
return state_identifier.zfill(2)