Sign_In_Register/sign_in.py

157 lines
6.7 KiB
Python

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("<FocusIn>", self.focus_color)
self.scan_text.bind("<FocusOut>", self.unfocus_color)
self.scan_text.bind('<Return>', 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}")