Código fuente para mexa.CurpField

# encoding: utf-8
"""Clase encargada del CURP"""
from calendar import monthrange
from mexa.core import FieldInterface, Partes
from mexa.Estados import estados
from mexa.CurpUtils import Rand, CurpTools, CONSONANTS
from mexa.ErrorMsgs import CURP_ERRORS as ERRORS


# Expresión regular para validar y las partes(groups) que conforman el CURP
partes = Partes(r'^([A-Z]{4})(\d{6})([H|M])([A-Z]{2})([A-Z]{3})(\S)(\d)$')
FECHA_NACIMIENTO = 2
SEXO = 3
ENTIDAD_FEDERATIVA = 4
ID2_NOMBRE = 5
HOMOCLAVE = 6
CHECKSUM = 7

[documentos]class CurpField(FieldInterface): """ CurpField, clase encargada de administrar el CURP, el cual lo representamos como: >>> # ⌐------------------------------ id_nombre: 1ras letras 1er ap, 2do ap y nombre >>> # | ⌐----------------------- fecha_nacimiento: 6 digitos en orden AAMMDD >>> # | | ⌐------------------ sexo: un carácter el cual puede ser H ó M >>> # | | | ⌐-------------- entidad_federativa: codigo de 2 caracteres >>> # | | | | ⌐---------- consonantes_internas: 1er ap, 2d ap y nombre >>> # | | | | | ⌐----- homoclave: Evita duplicidades >>> # | | | | | | ⌐-- checksum: Digito verificador de integridad >>> # | | | | | | | >>> # NNNN AAMMDD S EN CCC H C >>> # 0123 012345 0 01 012 0 0 """ errorMsgs = ERRORS
[documentos] @staticmethod def gen_id_nombre(data): """ Genera la parte del nombre, los primeros 4 dígitos, :param data: diccionario de datos a utilizar. :type data: dict :return: Genera el id del nombre un str de 4 carácteres. :rtype: str """ out = ['X','X','X','X'] # Tomando la parte del primer apellido (paterno) if 'primer_ap' in data: primer_ap = CurpTools.quitar_conjunciones(data['primer_ap']) out[0] = CurpTools.primer_letra(primer_ap) out[1] = CurpTools.primer_vocal_interna(primer_ap) else: out[0] = Rand.consonante() out[1] = Rand.vocal() # Tomando la parte del segundo apellido (materno) if 'segundo_ap' in data: segundo_ap = CurpTools.quitar_conjunciones(data['segundo_ap']) out[2] = CurpTools.primer_letra(segundo_ap) else: out[2] = Rand.consonante() # Tomando la parte del nombre if 'nombre' in data: nombre = CurpTools.nombre_de_pila(data['nombre']) out[3] = CurpTools.primer_letra(nombre) else: out[3] = Rand.consonante() return CurpTools.limpiar_mal_palabra(''.join(out))
[documentos] @staticmethod def gen_consonantes_nombre(data): """ Genera la segunda parte parte del nombre :param data: diccionario de datos a utilizar. :type data: dict :return: la segunda parte del nombre, en formato de 3 consonantes. :rtype: str """ out = ['X','X','X'] # Tomando la parte del primer apellido (paterno) if 'primer_ap' in data: primer_ap = CurpTools.quitar_conjunciones(data['primer_ap']) out[0] = CurpTools.primer_consonante_interna(primer_ap) else: out[0] = Rand.consonante() # Tomando la parte del segundo apellido (materno) if 'segundo_ap' in data: segundo_ap = CurpTools.quitar_conjunciones(data['segundo_ap']) out[1] = CurpTools.primer_consonante_interna(segundo_ap) else: out[1] = Rand.consonante() # Tomando la parte del nombre if 'nombre' in data: nombre = CurpTools.nombre_de_pila(data['nombre']) out[2] = CurpTools.primer_consonante_interna(nombre) else: out[2] = Rand.consonante() return CurpTools.sanitizar(''.join(out))
[documentos] @staticmethod def check_fecha(fecha_str, homo_serial): """ Revisa si existe algún error en el en formato fecha AAMMDD :param fecha_str: Fecha en 6 digitos en formato AAMMDD :type fecha_str: str :return: devuelve el código de error o None en caso de no existir error. :rtype: CodeError/None """ y = CurpTools.anio(fecha_str[0:2], homo_serial) m = int(fecha_str[2:4]) if m > 12: return 102 dias_mes = monthrange(y, m)[1] d = int(fecha_str[4:6]) if d > dias_mes: return 103 return None
[documentos] @staticmethod def checksum(curp: str) -> int: """ Calcula el checksum del CURP. :param curp: El curp sobre al cual se calcula el checksum. :type curp: str :return: el valor del checksum. :rtype: int """ chars = "0123456789ABCDEFGHIJKLMNNOPQRSTUVWXYZ" suma = sum([(18 - i) * chars.index(curp[i]) for i in range(17)]) return (10 - (suma % 10)) % 10
[documentos] @staticmethod def find_match_error_nombre(nombre:str, curp:str) -> str: """ Valida si el curp para el nombre el curp es correcto :param nombre: Nombre a validar :type nombre: str :param curp: CURP a validar. :return: True si encontró algun error/False en caso contrario :rtype: bool """ has_error = False if curp[3] != CurpTools.primer_letra(nombre): CurpField.add_error(201) has_error = True if curp[15] != CurpTools.primer_consonante_interna(nombre): CurpField.add_error(202) has_error = True return has_error
[documentos] @staticmethod def find_match_error_primer_ap(primer_ap:str, curp:str) -> bool: """ Valida si para el primer apellido el curp es correcto :param primer_ap: El valor del primer apellido. :type primer_ap: str :param curp: El valor del CURP. :type curp: str :return: True si existe(n) error(es)/ False caso contrario :rtype: bool """ has_error = False if curp[0] != CurpTools.primer_letra(primer_ap): has_error = True CurpField.add_error(203) if curp[1] != CurpTools.primer_vocal_interna(primer_ap): has_error = True CurpField.add_error(204) if curp[10] != CurpTools.primer_consonante_interna(primer_ap): has_error = True CurpField.add_error(205) return has_error
[documentos] @staticmethod def find_match_error_segundo_ap(segundo_ap:str, curp:str) -> bool: """ Valida si para el primer apellido el curp es correcto :param segundo_ap: Valor del segundo apellido. :type segundo_ap: str :param curp: Valor del CURP :type curp: str :return: True si existe(n) error(es)/ False caso contrario :rtype: bool """ if curp[2] != CurpTools.primer_letra(segundo_ap): CurpField.add_error(206) if curp[14] != CurpTools.primer_consonante_interna(segundo_ap): CurpField.add_error(207)
[documentos] @staticmethod def find_match_error(match:dict): """ Busca errores a partir del match proporcionado. :param match: Diccionario de datos el cual puede contener los valores de nombre, primer_ap, segundo_ap, fecha_nacimiento, sexo y entidad_federativa :type match: dict """ curp = partes.value() if 'nombre' in match: nombre = CurpTools.nombre_de_pila(CurpTools.sanitizar(match['nombre'])) CurpField.find_match_error_nombre(nombre, curp) if 'primer_ap' in match: primer_ap = CurpTools.quitar_conjunciones(match['primer_ap']) CurpField.find_match_error_primer_ap(primer_ap, curp) if 'segundo_ap' in match: segundo_ap = CurpTools.quitar_conjunciones(match['segundo_ap']) CurpField.find_match_error_segundo_ap(segundo_ap, curp) if 'fecha_nacimiento' in match: fecha6digits = CurpTools.fecha_to_6digits(match['fecha_nacimiento']) if partes.get(FECHA_NACIMIENTO) != fecha6digits: CurpField.add_error(code = 208, value = match['fecha_nacimiento']) if 'sexo' in match: if partes.get(SEXO) != match['sexo']: CurpField.add_error(code = 209, value = match['sexo']) if 'entidad_federativa' in match: edo2chars = CurpTools.estado_to_2chars(match['entidad_federativa']) if partes.get(ENTIDAD_FEDERATIVA) != edo2chars: CurpField.add_error(code = 210, value = match['entidad_federativa'])
[documentos] @staticmethod def is_valid(value, match = None): """ Valida el CURP :param value: Contiene el valor del CURP. :type value: str :return: Regresa True si value es un CURP valido :rtype: bool """ CurpField.clear_errors() # partes.load(CurpTools.sanitizar(value)) if partes.error: CurpField.add_error(code = 100) return False # Fecha de nacimiento. error_code = CurpField.check_fecha( partes.get(FECHA_NACIMIENTO), partes.get(HOMOCLAVE) ) if error_code is not None: CurpField.add_error(error_code) # Sexo if partes.get(SEXO) not in ('H', 'M'): CurpField.add_error(code = 101, value = partes.get(SEXO)) # Entidad Federativa, NE es no especificado el caso común es para extrangeros # Ya que no nació en ninguna entidad federativa. if partes.get(ENTIDAD_FEDERATIVA) not in estados: CurpField.add_error(code = 104, value = partes.get(ENTIDAD_FEDERATIVA)) # La parte del nombre esta conformada por la 1er consonante interna del: # primer apellido, 2d apellido, nombre pila par_nombre = partes.get(ID2_NOMBRE) for c in par_nombre: if c not in CONSONANTS: CurpField.add_error(code = 105, value = c) curp_val = partes.value() # Valida el match. if match is not None: # Falta agregar la implementación del match code = CurpField.find_match_error(match) if code is not None: CurpField.add_error(code) # CurpField.add_error(code = 100) # Checksum cs = CurpField.checksum(curp_val) if cs != int(partes.get(CHECKSUM)): CurpField.add_error(code = 106, value = curp_val) return not CurpField.has_errors()
[documentos] @staticmethod def gen_fecha_nacimiento(data:dict) -> str: """ Genera/Busca la fecha de nacimiento :param data: Diccionario que puede contener el valor de fecha_nacimiento :type data: dic :return: Una fecha de nacimiento valida en forma de 6 digítos AAMMDD :rtype: str """ if 'fecha_nacimiento' in data and len(data['fecha_nacimiento']) == 6: return data['fecha_nacimiento'] return Rand.fecha()
[documentos] @staticmethod def gen_sexo(data:dict) -> str: """ Genera el sexo, en caso de ya venir uno devuelve este normalizado. :param data: Diccionario de datos de parametros definidos por el usuario :type data: dict :return: El sexo un caracter que puede ser H ó M :rtype: str """ if 'sexo' in data: if data['sexo'] in ('HOMBRE', 'MASCULINO', 'H'): return 'H' if data['sexo'] in ('MUJER', 'FEMENINO', 'F', 'M'): return 'M' return Rand.sexo()
[documentos] @staticmethod def gen_entidad_federativa(data:dict) -> str: """ Genera la entidad federativa, en caso de ya venir uno devuelve esta. :param data: Diccionario de datos de parametros definidos por el usuario :type data: dict :return: La entidad_federativa un código de 2 carácteres :rtype: str """ if 'entidad_federativa' in data: return data['entidad_federativa'] return Rand.estado()
[documentos] @staticmethod def generate(data:dict) -> str: """ Genera el CURP, en caso de ya venir uno devuelve esta. :param data: Diccionario de datos de parametros definidos por el usuario :type data: dict :return: el CURP código de 18 carácteres :rtype: str """ id_nombre = CurpField.gen_id_nombre(data) fecha = CurpField.gen_fecha_nacimiento(data) sexo = CurpField.gen_sexo(data) ent_fed = CurpField.gen_entidad_federativa(data) id2_nombre = CurpField.gen_consonantes_nombre(data) # Generando el curp y su suma de verificación (cs). curp = f'{id_nombre}{fecha}{sexo}{ent_fed}{id2_nombre}0' cs = str(CurpField.checksum(curp)) return f'{curp}{cs}'