157 lines
6.7 KiB
Python
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}")
|