# -*- coding: utf-8 -*- import datetime import unicodedata from .utils import ( to_upper, search_vowel, search_consonant ) from .constants import ENTITIES, DISADVANTAGES_WORDS class BaseGenerator(object): """class Base Generator""" full_name = None def generate(self): raise NotImplementedError('No implement.') def parse(self, complete_name, last_name, mother_last_name=None, city=None, state_code=None): self.city = to_upper(city) if city else None self.state_code = to_upper(state_code) if state_code else None if mother_last_name: mother_last_name = self.remove_accents(mother_last_name) mother_last_name = self.remove_precisions(mother_last_name) mother_last_name = self.remove_articles(mother_last_name) self.mother_last_name = to_upper(mother_last_name) first_name = self.remove_names(complete_name) first_name = self.remove_accents(first_name) first_name = self.remove_precisions(first_name) self.complete_name = to_upper(first_name) last_name = self.remove_accents(last_name) last_name = self.remove_precisions(last_name) last_name = self.remove_articles(last_name) self.last_name = to_upper(last_name) self.full_name = "{} {} {}".format(self.last_name, self.mother_last_name, self.complete_name) def data_fiscal(self, complete_name, last_name, mother_last_name, birth_date): birth_date = self.parse_date(birth_date) if len(last_name) is 1 or len(last_name) is 2: initials = self.initials_name_comp(complete_name, last_name, mother_last_name) elif mother_last_name is None or mother_last_name is '': #Rule 7 initials = self.initials_single_last_name(complete_name, last_name) else: initials = self.initials_name(complete_name, last_name, mother_last_name) #Rule 9 completename = self.verify_initials(initials) return '%s%s' % (completename, birth_date) def initials_name(self, first_name, last_name, mother_last_name): """Rule 1 - The key is integrated with the following data: 1.- The first letter of the father's last name and the next first vowel of the same. 2.- The first letter of the mother's last name. 3.- The first letter of the name. """ ini_last_name = last_name[0:1] last_name_vowel = search_vowel(last_name) ini_mothlast_name = self.get_ini_mothlast_name(mother_last_name) ini_first_name = first_name[0:1] # Rule 5 # When the paternal or maternal surname are composed, the first word that corresponds # to any of them will be taken for the classification. # Dolores San Martín Dávalos SADD-180812 # Mario Sánchez de la Barquera Gómez SAGM-190224 # Antonio Jiménez Ponce de León JIPA-170808 initials = '%s%s%s%s' % ( ini_last_name, last_name_vowel, ini_mothlast_name, ini_first_name ) return initials def remove_precisions(self, phrase): """ Rule 3 - When the initial letter of any of the surnames or first names is composed, only its initial will be noted. In Ch la C and in Ll la L. For example: Manuel Chávez González CAGM-240618 Felipe Camargo Llamas CALF-450228 Charles Kennedy Truman KETC-511012 """ letters = phrase[0:2] data = phrase[2:len(phrase)] if letters == 'CH': phrase = 'C%s' % data elif letters == 'LL': phrase = 'L%s' % data return phrase def remove_articles(self, phrase): """ Replace all the occurrences of string in list. Rule 8 - When articles, prepositions, conjunctions or contractions appear in the name of natural persons, they will not be taken as elements of integration of the code, examples: Carmen de la Peña Ramírez PERC-631201 Mario Sánchez de los Cobos SACM-701110 Roberto González and Durán GODR-600101 Juan del Valle Martínez VAMJ-691001 """ to_replaces = ['DE LA', 'DE LOS', 'DEL', 'DE', 'LAS', 'LA', 'LOS', 'Y', 'MC', 'MAC', 'VON', 'VAN'] # Iterate over the strings to be replaced for elem in to_replaces : # Check if string is in the main string if elem in phrase: # Replace the string phrase = phrase.replace(elem, '').strip() return phrase def remove_names(self, first_name): """ Rule 6 - When the name is composed, that is, it is made up of two or more words, the initial letter of the first will be taken for the conformation, provided it is not MARIA or JOSE given its frequent use, in which case the first letter will be taken of the second word. For example: Luz María Fernández Juárez FEJL-200205 José Antonio Camargo Hernández CAHA-211218 María Luisa Ramírez Sánchez RASL-251112 """ to_replaces = ['JOSE', 'MARIA'] # Iterate over the strings to be replaced for elem in to_replaces : # Check if string is in the main string if elem in first_name : # Replace the string first_name = first_name.replace(elem, '').strip() return first_name def get_ini_mothlast_name(self, mother_last_name): """ The first letter of the mother's last name. """ return mother_last_name[0:1] if mother_last_name else '' def initials_name_comp(self, first_name, last_name, mother_last_name): """Rule 4 - In cases where the paternal surname of the natural person is made up of one or two letters, the password will be formed as follows: 1.- The first letter of the paternal surname. 2.- The first letter of the mother's last name. 3.- The first and second letters of the name. For example: Alvaro de la O Lozano OLAL-401201 Ernesto Ek Rivera ERER-071120 """ ini_last_name = last_name[0:1] ini_mthlast_name = self.get_ini_mothlast_name(mother_last_name) data = "{}{}{}".format(ini_last_name, ini_mthlast_name, first_name[0:2]) return data def initials_single_last_name(self, first_name, last_name): """Rule 7 - In the cases in which the natural person has only one surname, he will comply with the first and second letters of the paternal or maternal surname, as it appears on the birth certificate, plus the first and second letters of the name. For example: Juan Martínez MAJU-420116 Gerarda Zafra ZAGE-251115 """ return '{}{}'.format(last_name[0:2], first_name[0:2], ) def verify_initials(self, initials): """ Rule 9 - When an inconvenient word appears from the four letters that make up the alphabetical expression, the last letter will be replaced by an "X". """ words = dict((x, y) for x, y in DISADVANTAGES_WORDS) data = words.get(initials) if words.get(initials) else initials return data def remove_accents(self, text): """ Normalise (normalize) unicode data in Python to remove umlauts, accents etc. Rule 10 - When special characters appear as part of the name, paternal surname and maternal surname, they must be excluded for the calculation of the homonym and the verification digit. The characters will be interpreted, yes and only if, they are individually within the name, paternal surname and maternal surname. Examples: Roberto O’farril Carballo OACR-661121 Rubén D’angelo Fargo DAFR-710108 Luz Ma. Fernández Juárez FEJL-830120 """ #s_no_accents = ''.join((c for c in unicodedata.normalize('NFD', text) if unicodedata.category(c) != 'Mn')) try: text = unicode(text, 'utf-8') except (TypeError, NameError): # unicode is a default on python 3 pass text = unicodedata.normalize('NFD', text) text = text.encode('ascii', 'ignore') text = text.decode("utf-8") return str(text) def parse_date(self, birthdate): """Rule 2 - The taxpayer's date of birth will be noted below, in the following order: 1. Year: The last two figures will be taken, writing them in Arabic numerals. 2.- Month: The month of birth will be taken in its order number, in a calendar year, writing it with Arabic numbers. 3.- Day: It will be written in Arabic numerals. Args: birthdate: The first parameter. Returns: As a result we will have the numerical expression: 070401 """ try: dtype = type(birthdate) if birthdate is None: birthdate = datetime.datetime.today() else: if not (dtype is datetime.datetime or dtype is datetime.date): birthdate = datetime.datetime.strptime(birthdate, '%d-%m-%Y').date() year = str(birthdate.year) year = year[2:4] # When in the year, month or day, of the date of birth, only one figure appears, # a ZERO will be put before it. month = str(birthdate.month).zfill(2) day = str(birthdate.day).zfill(2) return '%s%s%s' % (year, month, day) except Exception as exc: raise str(exc) def city_search(self, name_city): data = '' for key, value in ENTITIES.items(): if key == name_city: data = value return data def get_consonante(self, word): return search_consonant(word) def get_year(self, str_date): """Get year of birth date.""" try: if str_date is None: date = datetime.datetime.today() else: date = datetime.datetime.strptime(str_date, '%d-%m-%Y').date() return date.year except Exception as exc: raise str(exc) def current_year(self): return datetime.datetime.now().year