geekcom / validator-docs

Validação de CPF, CNPJ, CNH, NIS, DDD, Título Eleitoral e Cartão Nacional de Saúde com Laravel.
MIT License
564 stars 96 forks source link

Melhorar validação de certidão de nascimento #139

Closed enzo-santos closed 8 months ago

enzo-santos commented 10 months ago

De acordo com este site, este é o algoritmo para se calcular o dígito verificador de uma certidão de nascimento:

(exemplo: 104539015520131000120210000123)

[...]

O Número de Matrícula tem a configuração aaaaaa.bb.cc.dddd.e.fffff.ggg.hhhhhhh-ii, onde:

[...]

ii indica o Dígito Verificador DV, cujo cálculo obedece ao seguinte esquema, dentro do critério de DV MÓDULO 11 já conhecido:

1  0  4  5  3  9  0  1  5  5  2  0  1  3  1  0  0  0  1  2  0  2  1  0  0  0  0  1  2  3 = 2               
x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x 
2  3  4  5  6  7  8  9 10  0  1  2  3  4  5  6  7  8  9 10  0  1  2  3  4  5  6  7  8  9
----------------------------------------------------------------------------------------                   
2+ 0+16+25+18+63+ 0+ 9+50+ 0+ 2+ 0+ 3+12+ 5+ 0+ 0+ 0+ 9+20+ 0+ 2+ 2+ 0+ 0+ 0+ 0+ 7+16+27 = 288

288÷11=26, com resto 2 (este é o 1º dígito do DV) - Nota: se o resto for "10", o DV será "1"

1  0  4  5  3  9  0  1  5  5  2  0  1  3  1  0  0  0  1  2  0  2  1  0  0  0  0  1  2  3  2 = 1
x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x  x
1  2  3  4  5  6  7  8  9 10  0  1  2  3  4  5  6  7  8  9 10  0  1  2  3  4  5  6  7  8  9
-------------------------------------------------------------------------------------------
1+ 0+12+20+15+54+ 0+ 8+45+50+ 0+ 0+ 2+ 9+ 4+ 0+ 0+ 0+ 8+18+ 0+ 0+ 1+ 0+ 0+ 0+ 0+ 6+14+24+18 = 309

309÷11=28, com resto 1 (este é o 2º dígito do DV) - Nota: se o resto for "10", o DV será "1"

Portanto, o Número de Matrícula+DV = 104539.01.55.2013.1.00012.021.0000123-21.

Em pseudocódigo, ficaria mais ou menos assim:

soma0 = 0
soma1 = 0

i = 0
para cada digito nos 30 primeiros digitos da certidao
    soma0 += digito * (i + 2)
    soma1 += digito * (i + 1)
    i += 1

d0 = soma0 % 11
se d0 == 10 
    d0 = 1

d1 = (soma1 + 9*d0) % 11
se d1 == 10 
    d1 = 1

dv = d0*10 + d1

Para tornar a validação mais precisa, bastaria comparar o Dígito Verificador calculado com os últimos dois dígitos da certidão:

dvEsperado = d0*10 + d1
dvAtual = ultimos 2 digitos da certidao como inteiro
valido = dvAtual == dvEsperado

Não encontrei nenhuma descrição desse método em documentos oficiais. No entanto, por prestar serviços a um órgão público, tenho acesso a uma base considerável de certidões de nascimento e o algoritmo conseguiu validar todos. No entanto, se alguém quiser contribuir com a discussão, pode ficar à vontade!

Isso iria melhorar bastante a validação atual, que pelo que entendi é feita somente por uma expressão regular.

geekcom commented 9 months ago

Olá @enzo-santos, muito obrigado pela contribuição por aqui, a validação de certidão é feita por meio de da classe "src/validator-docs/Rules/Certidao.php", não tive tempo ainda de verificar a diferença com a proposta que vc trouxe nesta issue, poderia verificar por favor?

enzo-santos commented 9 months ago

@geekcom Perdão, eu estava consultando o arquivo errado. Achei que a validação estava em src/validator-docs/Formats, mas na verdade está em src/validator-docs/Rules. Dei uma olhada por alto e os algoritmos parecem ser equivalentes. Pode encerrar a issue.