diff --git a/IFPass.py b/IFPass.py index a712fed..7c2e970 100644 --- a/IFPass.py +++ b/IFPass.py @@ -15,6 +15,7 @@ from pywinauto.findwindows import find_window from pywinauto.win32functions import SetForegroundWindow from PIL import Image, ImageDraw, ImageFont from PyPDF2 import PdfFileReader, PdfFileWriter +import fitz # = PyMuPDF : To convert pdf to png import subprocess from shutil import copyfile, move from pyfiglet import Figlet @@ -85,14 +86,20 @@ def initialisation(): return IFPassDBdir, printername, AcrobatReader, clientsfile, clientsbkpfile, imgdir, templatesdir, pdftemplate, pngtemplate, fonttemplate -def get_fullname(): - while "Empty firstname": - firstname = input("Prénom : ").strip() - if len(firstname) == 0: - os.system('cls') - print(colored("\nLe Prénom ne peut pas être vide.", 'red')) - else: - break +def get_fullname(**kwargs): # **kwargs => Optionnal arguments + if 'firstname' in kwargs: + firstname = kwargs['firstname'] + newfirstname = input("Prénom (" + firstname + "): ").strip() + if len(newfirstname) != 0: + firstname = newfirstname + else: + while "Empty firstname": + firstname = input("Prénom : ").strip() + if len(firstname) == 0: + os.system('cls') + print(colored("\nLe Prénom ne peut pas être vide.", 'red')) + else: + break firstname = firstname[0].upper() + firstname[1:].lower() if '-' in firstname: pos = firstname.find("-") @@ -102,21 +109,29 @@ def get_fullname(): pos = firstname.find(" ") firstname = firstname[:pos + 1] + firstname[pos + 1].upper() + \ firstname[pos + 2:] # Check if compound name - while "Empty surname": - surname = input("Nom : ").upper().strip() - if len(surname) == 0: - os.system('cls') - print(colored("\nLe Nom ne peut pas être vide.", 'red')) - else: - break + + if 'surname' in kwargs: + surname = kwargs['surname'] + newsurname = input("Nom (" + surname + "): ").strip() + if len(newsurname) != 0: + surname = newsurname + else: + while "Empty surname": + surname = input("Nom : ").strip() + if len(surname) == 0: + os.system('cls') + print(colored("\nLe Nom ne peut pas être vide.", 'red')) + else: + break + surname = surname.upper() docteur = yes_or_no('Est-ce un Docteur ?') if docteur: titre = 'Dr.' - fullname = titre + ' ' + surname + ' ' + firstname + titrename = titre + ' ' + surname else: titre = '' - fullname = surname + ' ' + firstname - return titre, firstname, surname, fullname + titrename = surname + return titre, firstname, surname, titrename def yes_or_no(question): @@ -137,7 +152,6 @@ def getclientID(): else: clientID = str(int(lastID) + 1).zfill(10) - writeindb(clientID) return clientID @@ -202,19 +216,38 @@ def getpic(): sys.exit() -def writeindb(clientID): - print("Ajout dans la base de données... ", end="") - with open(clientsfile, 'a', newline='', encoding='utf-8') as csvfile: - writer = csv.writer(csvfile, delimiter=';') - writer.writerow([titre, firstname, surname, clientID, dateinsc, dateexp]) - print(colored('[OK]', 'green')) +def writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new): + if new is True: + print("Ajout dans la base de données... ", end="") + with open(clientsfile, 'a', newline='', encoding='utf-8') as csvfile: + writer = csv.writer(csvfile, delimiter=';') + writer.writerow([titre, firstname, surname, clientID, dateinsc, dateexp]) + print(colored('[OK]', 'green')) + elif new is False: + print("Modification de la base de données... ", end="") + with open(clientsfile, 'r+', newline='', encoding='utf-8') as csvfile: + content = csvfile.readlines() + for index, member in enumerate(content): + member = member.split(';') + if member[3] == clientID: + tochange = index + break + content.pop(tochange) + changewith = ";".join([titre, firstname, surname, clientID, dateinsc, dateexp]) + '\n' + content.insert(tochange, changewith) + content = "".join(content) + csvfile.seek(0) + csvfile.truncate(0) + csvfile.write(content) + + print(colored('[OK]', 'green')) def bkpdb(): copyfile(clientsfile, clientsbkpfile) -def fillcard(barcode): +def fillcard(clientID, titrename, firstname, dateexp, barcode, picture): print("Création de la carte avec les informations...", end='') try: im = Image.open(pngtemplate) @@ -228,12 +261,13 @@ def fillcard(barcode): draw = ImageDraw.Draw(im) # Name embedding : - font = ImageFont.truetype(fonttemplate, 45) - draw.text((401, 310), fullname, fill=(0, 0, 0), font=font) + font = ImageFont.truetype(fonttemplate, 40) + draw.text((401, 296), titrename, fill=(0, 0, 0), font=font) + draw.text((401, 334), firstname, fill=(0, 0, 0), font=font) # Date embedding : font = ImageFont.truetype(fonttemplate, 30) - draw.text((401, 390), dateexp, fill=(0, 0, 0), font=font) + draw.text((401, 400), dateexp, fill=(0, 0, 0), font=font) # ID embedding : font = ImageFont.truetype('arial.ttf', 30) @@ -252,7 +286,7 @@ def fillcard(barcode): print(colored('[OK]', 'green')) -def mergepdf(): +def mergepdf(clientID): cartefilename = os.path.join(imgdir, clientID + '.pdf') output = PdfFileWriter() @@ -277,10 +311,52 @@ def printcard(cartefilename): subprocess.Popen('"' + AcrobatReader + '"' + ' /h /n /t ' + cartefilename + ' ' + printername, shell=False) +def newmember(): + while "the informations are incorrect": # Loop Filling informations + os.system('cls') + titre, firstname, surname, titrename = get_fullname() + dateinsc = date.today() + dateexp = dateinsc + timedelta(days=365) + + dateinsc = dateinsc.strftime('%d/%m/%Y') + dateexp = dateexp.strftime('%d/%m/%Y') + changeexp = yes_or_no("Voulez-vous choisir la date d'expiration ?") + if changeexp: + while True: + dateexp = input("Quelle date d'expiration voulez-vous mettre (Format : JJ/MM/AAAA)? : ") + match = re.fullmatch(r'^(0[1-9]|1[0-9]|2[0-9]|3[0-1])/(0[1-9]|1[0-2])/([0-9]){4}$', dateexp) + if match: + break + else: + print('Mauvais format ! JJ/MM/AAAA, exemple : 01/08/2042') + + os.system('cls') + print("Titre : ", colored(titre, 'green')) + print("Prénom : ", colored(firstname, 'green')) + print("Nom : ", colored(surname, 'green')) + print("Date d'inscription :", colored(dateinsc, 'green')) + print("Date d'expiration : ", colored(dateexp, 'green')) + correct = yes_or_no("Ces informations sont elles correctes ?") + + if correct: + os.system('cls') + if version != 'devnocam': + picture = getpic() + clientID = getclientID() + barcode = barcode_gen(clientID) + fillcard(clientID, titrename, firstname, dateexp, barcode, picture) + cartefilename = mergepdf(clientID) + if version not in ('dev', 'devnocam'): + bkpdb() + printcard(cartefilename) + writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=True) + break + + def membersearch(): with open(clientsfile, 'r', newline='', encoding='utf-8') as csvfile: reader = csv.reader(csvfile, delimiter=';') - csvlist = list(map(tuple, reader)) + csvlist = list(map(list, reader)) del csvlist[0] # We dele the first line (Prénom, Nom...) research = input('Entrez une partie du nom, prénom, ou numéro de carte (ou flashez) : ').lower() os.system('cls') @@ -310,29 +386,141 @@ def membersearch(): break except (IndexError, ValueError): print(colored('Choix invalide ! Veillez bien à sélectionner le numéro de la colonne "Choix"', 'red', attrs=['bold'])) - os.system('cls') + os.system('cls') - print("Titre : ", colored(member[0], 'green')) - print("Prénom : ", colored(member[1], 'green')) - print("Nom : ", colored(member[2], 'green')) - print("Numéro de carte : ", colored(member[3], 'green')) - print("Date d'inscription :", member[4]) - print("Date d'expiration : ", member[5]) - dateexp = datetime.strptime(member[5], '%d/%m/%Y').date() - diff = (dateexp - date.today()).days - if diff > 0: - print(colored(f"L'abonnement est encore valable {diff} jours.", 'green', attrs=['bold'])) - elif diff < 0: - print(colored("L'abonnement est expiré depuis {abs(diff)} jours.", 'red', attrs=['bold'])) # abs() to remove minus sign - elif diff == 0: - print(colored("Il s'agit du dernier jour de l'abonnement, il expirera demain.", 'yellow', attrs=['bold'])) + while 'Choix incorect': + print("Titre : ", colored(member[0], 'green')) + print("Prénom : ", colored(member[1], 'green')) + print("Nom : ", colored(member[2], 'green')) + print("Numéro de carte : ", colored(member[3], 'green')) + print("Date d'inscription :", member[4]) + print("Date d'expiration : ", member[5]) + dateexp = datetime.strptime(member[5], '%d/%m/%Y').date() + diff = (dateexp - date.today()).days + if diff > 0: + print(colored(f"L'abonnement est encore valable {diff} jours.", 'green', attrs=['bold'])) + elif diff < 0: + print(colored("L'abonnement est expiré depuis {abs(diff)} jours.", 'red', attrs=['bold'])) # abs() to remove minus sign + elif diff == 0: + print(colored("Il s'agit du dernier jour de l'abonnement, il expirera demain.", 'yellow', attrs=['bold'])) + + print('\n1 - Modifier', "2 - Renouveller l'abonnement", '3 - Imprimer la carte', '0 - Menu principal', sep='\n') + choix = input('Choix : ') + if choix == '0': + os.system('cls') + return + # We update values with new (edited) values : + newtitre, newfirstname, newsurname, newdateexp = memberdo(choix, member) + member[0], member[1], member[2], member[5] = newtitre, newfirstname, newsurname, newdateexp else: print(colored("Aucun membre n'a été trouvé.", 'red', attrs=['bold'])) + os.system("pause") + + +def memberdo(choix, member): + titre = member[0] + firstname = member[1] + surname = member[2] + clientID = member[3] + dateinsc = member[4] + dateexp = member[5] + + os.system('cls') + if choix == '1': # Edit member + titre, firstname, surname, dateexp = memberedit(titre, firstname, surname, clientID, dateinsc, dateexp) + + elif choix == '2': # Renew subscription + dateexp = datetime.strptime(dateexp, '%d/%m/%Y').date() + diff = (dateexp - date.today()).days + if diff >= 0: + dateexp = dateexp + timedelta(days=365) + elif diff < 0: + dateexp = date.today() + timedelta(days=365) + dateexp = dateexp.strftime('%d/%m/%Y') + + if titre == 'Dr.': + titrename = titre + ' ' + surname + else: + titrename = surname + + wantnewpic = yes_or_no("Voulez-vous prendre une nouvelle photo ?") + os.system('cls') + if wantnewpic: + os.system('cls') + if version != 'devnocam': + picture = getpic() + else: + # We crop pic from the previous card + cartefilename = os.path.join(imgdir, clientID + '.pdf') + pdf = fitz.open(cartefilename) + page = pdf.loadPage(0) + mat = fitz.Matrix(4.165, 4.165) # To obtain good resolution + pix = page.getPixmap(matrix=mat) + pageimg = Image.frombytes("RGBA", [pix.width, pix.height], pix.samples) + picture = pageimg.crop((47, 49, 343, 378)) + + barcode = barcode_gen(clientID) + fillcard(clientID, titrename, firstname, dateexp, barcode, picture) + cartefilename = mergepdf(clientID) + + if version not in ('dev', 'devnocam'): + bkpdb() + printcard(cartefilename) + writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=False) + os.system('cls') + print(colored("La date d'expiration a bien été mise à jour !\n", 'blue', attrs=['bold'])) + + elif choix == '3': # Print card + printcard(cartefilename) + else: + print(colored('Choix incorrect !\n', 'red', attrs=['bold'])) + return titre, firstname, surname, dateexp + + +def memberedit(titre, firstname, surname, clientID, dateinsc, dateexp): + while "the informations are incorrect": # Loop Filling informations + titre, firstname, surname, titrename = get_fullname(titre=titre, firstname=firstname, surname=surname) + + print("Titre : ", colored(titre, 'green')) + print("Prénom : ", colored(firstname, 'green')) + print("Nom : ", colored(surname, 'green')) + + correct = yes_or_no("Ces informations sont elles correctes ?") + os.system('cls') + + if correct: + wantnewpic = yes_or_no("Voulez-vous prendre une nouvelle photo ?") + os.system('cls') + if wantnewpic: + os.system('cls') + if version != 'devnocam': + picture = getpic() + else: + # We crop pic from the previous card + cartefilename = os.path.join(imgdir, clientID + '.pdf') + pdf = fitz.open(cartefilename) + page = pdf.loadPage(0) + mat = fitz.Matrix(4.165, 4.165) # To obtain good resolution + pix = page.getPixmap(matrix=mat) + + pageimg = Image.frombytes("RGBA", [pix.width, pix.height], pix.samples) + picture = pageimg.crop((47, 49, 343, 378)) + + barcode = barcode_gen(clientID) + fillcard(clientID, titrename, firstname, dateexp, barcode, picture) + cartefilename = mergepdf(clientID) + if version not in ('dev', 'devnocam'): + bkpdb() + printcard(cartefilename) + writeindb(titre, firstname, surname, clientID, dateinsc, dateexp, new=False) + os.system('cls') + break + return titre, firstname, surname, dateexp def main(): - global titre, firstname, surname, fullname, dateinsc, dateexp, clientID, clientsfile, IFPassDBdir, clientsfile, imgdir, clientsbkpfile, templatesdir, pngtemplate, fonttemplate, picture, pdftemplate, printername, AcrobatReader + global IFPassDBdir, clientsfile, imgdir, clientsbkpfile, templatesdir, pngtemplate, fonttemplate, pdftemplate, printername, AcrobatReader while "The program is running": init() # Initialisation of colorama IFPassDBdir, printername, AcrobatReader, clientsfile, clientsbkpfile, imgdir, templatesdir, pdftemplate, pngtemplate, fonttemplate = initialisation() @@ -343,57 +531,18 @@ def main(): print('Version : ', version) if version in ('dev', 'devnocam'): print(colored("\nATTENTION : Il s'agit d'une version en cours de développement, potentiellement instable !", 'red')) - print("\nLe programme IFPass à été écrit par Jordan ERNST Q1 2018 pour l'Institut Français en Hongrie.") + print("\nCe programme est developpé par par Jordan ERNST pour l'Institut Français en Hongrie.") print('Pour toute question, problème ou requête contactez-moi à pro.ernst@gmail.com.\n') - print('1 - Nouveau membre', '2 - Rechercher un membre', '3 - Quitter', sep='\n') + print('1 - Nouveau membre', '2 - Rechercher un membre', '0 - Quitter', sep='\n') choix = input('Choix : ') if choix == '1': - while "the informations are incorrect": # Loop Filling informations - os.system('cls') - titre, firstname, surname, fullname = get_fullname() - dateinsc = date.today() - dateexp = dateinsc + timedelta(days=365) - - dateinsc = dateinsc.strftime('%d/%m/%Y') - dateexp = dateexp.strftime('%d/%m/%Y') - changeexp = yes_or_no("Voulez-vous choisir la date d'expiration ?") - if changeexp: - while True: - dateexp = input("Quelle date d'expiration voulez-vous mettre (Format : JJ/MM/AAAA)? : ") - match = re.fullmatch(r'^(0[1-9]|1[0-9]|2[0-9]|3[0-1])/(0[1-9]|1[0-2])/([0-9]){4}$', dateexp) - if match: - break - else: - print('Mauvais format ! JJ/MM/AAAA, exemple : 01/08/2042') - - os.system('cls') - print("Titre : ", colored(titre, 'green')) - print("Prénom : ", colored(firstname, 'green')) - print("Nom : ", colored(surname, 'green')) - print("Date d'inscription :", colored(dateinsc, 'green')) - print("Date d'expiration : ", colored(dateexp, 'green')) - correct = yes_or_no("Ces informations sont elles correctes ?") - - if correct: - os.system('cls') - if version != 'devnocam': - global picture - picture = getpic() - clientID = getclientID() - barcode = barcode_gen(clientID) - fillcard(barcode) - cartefilename = mergepdf() - if version not in ('dev', 'devnocam'): - bkpdb() - printcard(cartefilename) - break + newmember() elif choix == '2': os.system('cls') membersearch() - os.system("pause") - elif choix == '3': + elif choix == '0': sys.exit() else: