from tkinter import * from tkinter import ttk import pandas as pd import os import re import logging from datetime import datetime, timedelta from lib import row_tracker, treerow_add, csvrow_add, csvrow_del, treerow_del from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import A4 class SignIn(Frame): def __init__(self, parent, controller): Frame.__init__(self, parent) print('Signin refresh') self.columns_signin = ['department', 'fname', 'sname', 'cardID', 'signin'] self.current_date = str(datetime.now().date()) #File path generation for logs and csv of sign ins self.todays_signins_path = 'sign_ins/signin-'+ self.current_date + '.csv' self.todays_log_path = 'sign_in_logs/' + self.current_date + '.log' self.recent_signin = [False, timedelta(0)] logging.basicConfig(level=logging.INFO, filename=self.todays_log_path, filemode="a") #Data frames for list of departments and database of users self.employee_df = pd.read_csv('employeeregister.csv', converters={'cardID': str}) self.department_df = pd.read_csv('departments.csv', converters={'cardID': str}) self.row_trackerobj = row_tracker(self.department_df, 0) self.signin_df = self.load_signin_df() self.input_frame = Frame(self) self.input_frame.grid(column=0, row=0, columnspan=2, padx=10, pady=(0,30)) self.scan_label = Label(self.input_frame, text='Scan Card') self.scan_label.grid(column=0, row=0, pady=10) self.border_color = Frame(self.input_frame) self.scan_text = Entry(self.border_color) self.scan_text.focus() self.scan_text.bind("", self.focus_color) self.scan_text.bind("", self.unfocus_color) self.scan_text.bind('', self.register_scan) self.scan_text.pack(padx=3, pady=3) self.border_color.grid(column=0, row=1) self.tree_frame = Frame(self) self.tree_frame.grid(column=0, row=2) self.fire_register_tree = ttk.Treeview(self.tree_frame) self.fire_register_tree.grid(column=0, row=0, padx=10) self.fire_register_tree['columns'] = ('First Name', 'Surname', 'Sign in Time') self.fire_register_tree.column('#0', width=120) self.fire_register_tree.column('First Name', anchor=CENTER, width=110) self.fire_register_tree.column('Surname', anchor=CENTER, width=110) self.fire_register_tree.column('Sign in Time', anchor=CENTER, width=110) #Define headings for each column self.fire_register_tree.heading('#0', text='Department') self.fire_register_tree.heading('First Name', text='First Name') self.fire_register_tree.heading('Surname', text='Surname') self.fire_register_tree.heading('Sign in Time', text='Sign in Time') self.pdf_btn = Button(self, text='Signin Report', command=self.generate_pdf) self.pdf_btn.grid(column=0, row=3, pady=(10,0)) #Build tree rows for existing sign ins (needed if program restarted after users have already signed in for the day) for rownum, row in self.signin_df.iterrows(): treerow_add(self.row_trackerobj, self.fire_register_tree, row) def load_signin_df(self): sign_ins = os.listdir('sign_ins') for file in sign_ins: if re.findall(self.current_date, file): return pd.read_csv(self.todays_signins_path, converters={'cardID': str, 'iid': str}) df = pd.DataFrame(columns=self.columns_signin) df.to_csv(self.todays_signins_path, index=False) return df #Clear input of text box def input_clear(self): self.scan_text.delete('0', END) self.scan_text.focus() #change border colour of text box when focused/unfocused def focus_color(self, event): self.border_color.configure(background='green') def unfocus_color(self, event): self.border_color.configure(background='red') def register_scan(self, event): card_code = self.scan_text.get() signin_datetime = datetime.now() signin_time = signin_datetime.strftime("%H:%M:%S") signin_datetime_future = signin_datetime + timedelta(seconds = 10) self.input_clear() # If employee does not exist exit if not self.employee_df.loc[self.employee_df['cardID'] == card_code].values.size: return #Prevent double tap of card if card_code == self.recent_signin[0] and self.recent_signin[1] > signin_datetime: return self.recent_signin = [card_code, signin_datetime_future] code_linked_employee = self.employee_df.loc[self.employee_df['cardID'] == card_code].values[0].tolist() #If employee has already signed in sign out. remove from tree, csv and create a log if self.signin_df.loc[self.signin_df['cardID'] == card_code].values.size: self.signin_df = csvrow_del(self.todays_signins_path, self.signin_df, [card_code]) treerow_del( self.row_trackerobj, self.fire_register_tree, [card_code]) logging.info('SIGN OUT: ' + code_linked_employee[1] + ' ' + code_linked_employee[2] + ' : ' + signin_time) return code_linked_employee.append(signin_time) tree_row_toadd = [code_linked_employee[0], code_linked_employee[1], code_linked_employee[2], code_linked_employee[3]] #Add employee to tree and sign in csv, also create log treerow_add( self.row_trackerobj, self.fire_register_tree, tree_row_toadd) self.signin_df = csvrow_add(self.todays_signins_path, self.signin_df, self.columns_signin, code_linked_employee) logging.info('SIGN IN: ' + code_linked_employee[1] + ' ' + code_linked_employee[2] + ' : ' + signin_time) #Populate PDF and send to default printer def generate_pdf(self): w, h = A4 current_row = 150 register_filename = "signinregister.pdf" c = canvas.Canvas(register_filename, pagesize=A4) c.drawString(30, h - 100, "Department") c.drawString(150, h - 100, "First Name") c.drawString(270, h - 100, "Surname") c.drawString(390, h - 100, "Sign in Time") for rownnum, row in self.signin_df.iterrows(): current_row += 20 c.drawString(30, h - current_row, row[0]) c.drawString(150, h - current_row, row[1]) c.drawString(270, h - current_row, row[2]) c.drawString(390, h - current_row, row[4]) c.showPage() c.save() if os.name == 'nt': os.startfile(register_filename, "print") else: os.system(f"lp {register_filename}")