def select_table_path(self, table_key): default_path = os.path.dirname(self.settings_configs[table_key]) select_path = self.open_file_dialog( default_path=default_path, extension=["*.xlsx", "*.xls"]) if select_path is None: return self.settings_configs[table_key] = select_path Configs.get_instance().save_json() self.refresh_UI()
def select_out_path(self): default_path = self.settings_configs["out_path"] select_path = self.open_dir_dialog(default_path=default_path) if select_path is None: return self.settings_configs["out_path"] = select_path Configs.get_instance().save_json() self.refresh_UI()
def remove_all_checkins(self, day): day_str = str(day) added_checkins_config = Configs.get_instance( ).get_member_checkin_temp_config(self.name) if day_str not in added_checkins_config: return added_checkins_config.pop(day_str) Configs.get_instance().save_temp_json() self.load_added_checkins()
def add_checkin(self, day, time): added_checkins_config = Configs.get_instance( ).get_member_checkin_temp_config(self.name) day_str = str(day) if day_str not in added_checkins_config: added_checkins_config[day_str] = [] day_checkins = added_checkins_config[day_str] day_checkins.append(time) day_checkins.sort(key=lambda key: (key[0], key[1])) Configs.get_instance().save_temp_json() self.load_added_checkins()
def set_leaves(self, time_text_list, need_save=True): if 1 == len(time_text_list) % 2: return False self.leave_dict = {} for idx in range(0, len(time_text_list), 2): if not self.add_leave(time_text_list[idx], time_text_list[idx + 1]): return False if need_save: Configs.get_instance().set_member_leave_temp_config( self.name, time_text_list) return True
def calc_all_data(self): #缺卡 self.lack_checkin_count = 0 #迟到早退 self.late_or_early_count = 0 self.late_or_early_duration = 0 self.late_or_early_fine_number = 0 self.late_early_time_dict = {} #工作天数 self.work_days = 0 #放假天数 self.holidays = 0 #请假时长 self.day_leave_durations = [] self.leave_durations = timedelta() #重新加载配置 self.load_leaves_data() self.load_added_checkins() self.load_config_data() for index in range(1, CommonDatas.get_instance().days_number + 1): if not self.in_company(index): #没入职 pass elif not Configs.get_instance().get_is_work_time(index): #休息日 self.holidays += 1 else: self.work_days += 1 duration, late, early = self.calc_late_and_early_time(index) self.late_early_time_dict[index] = [duration, late, early] if 0 < duration: self.late_or_early_count += 1 self.late_or_early_duration += duration self.late_or_early_fine_number += Configs.get_instance( ).get_fine_number(duration) if 30 <= duration: self.lack_checkin_count += 1 #请假时长 leave_duration_am = timedelta() leave_duration_pm = timedelta() leave_times = self.get_leave_time_range(index) lunch_break_start, lunch_break_end = CommonDatas.get_instance( ).create_lunch_break(index) for leave_time in leave_times: if leave_time[0] < lunch_break_start: leave_duration_am += leave_time[1] - leave_time[0] else: leave_duration_pm += leave_time[1] - leave_time[0] self.day_leave_durations.append( (leave_duration_am, leave_duration_pm)) self.leave_durations += (leave_duration_am + leave_duration_pm) if 5 < self.late_or_early_count: self.late_or_early_fine_number *= 2
def open(self): super().open() self.widget.show() self.calendar.setMinimumDate(CommonDatas.get_instance().start_date) self.calendar.setMaximumDate(CommonDatas.get_instance().end_date) work_time = Configs.get_instance().get_config("work_time") self.timeEditOut.setTime(QTime(work_time[1][0], work_time[1][1])) self.timeEditIn.setTime(QTime(work_time[0][0], work_time[0][1])) lunch_break = Configs.get_instance().get_config("lunch_break") self.lunchBreakEditOut.setTime(QTime(lunch_break[1][0], lunch_break[1][1])) self.lunchBreakEditIn.setTime(QTime(lunch_break[0][0], lunch_break[0][1])) self.work_time_table = Configs.get_instance().get_temp_config("work_time_table").copy() self.on_time_change() self.refresh_UI()
def add_leave(self, start, end): try: work_time = Configs.get_instance().get_config("work_time") start_date = Functions.string2datetime(start) end_date = Functions.string2datetime(end) while start_date < end_date: lunch_break_start, lunch_break_end = CommonDatas.get_instance( ).create_lunch_break(start_date.day) tempend_date = CommonDatas.get_instance().create_work_time( start_date.day)[1] if end_date < tempend_date: tempend_date = end_date if start_date < lunch_break_start and lunch_break_end < tempend_date: #午休的时间拆开 self._add_leave(start_date, lunch_break_start) self._add_leave(lunch_break_end, tempend_date) else: self._add_leave(start_date, tempend_date) if start_date.day == CommonDatas.get_instance().days_number: break else: start_date = CommonDatas.get_instance().create_work_time( start_date.day + 1)[0] except Exception as e: print(e) return False return True
def create_work_time(self, day): from Scripts.Data.Configs import Configs work_time = Configs.get_instance().get_config("work_time") start_time = self.create_datetime(day=day, hour=work_time[0][0], minute=work_time[0][1]) end_time = self.create_datetime(day=day, hour=work_time[1][0], minute=work_time[1][1]) return start_time, end_time
def create_lunch_break(self, day): from Scripts.Data.Configs import Configs lunch_break = Configs.get_instance().get_config("lunch_break") start_time = self.create_datetime(day=day, hour=lunch_break[0][0], minute=lunch_break[0][1]) end_time = self.create_datetime(day=day, hour=lunch_break[1][0], minute=lunch_break[1][1]) return start_time, end_time
def save_config(self): in_time = self.timeEditIn.time() out_time = self.timeEditOut.time() work_time = [] work_time.append([in_time.hour(), in_time.minute()]) work_time.append([out_time.hour(), out_time.minute()]) Configs.get_instance().set_config("work_time", work_time) lunch_break_in_time = self.lunchBreakEditIn.time() lunch_break_out_time = self.lunchBreakEditOut.time() lunch_break = [] lunch_break.append([lunch_break_in_time.hour(), lunch_break_in_time.minute()]) lunch_break.append([lunch_break_out_time.hour(), lunch_break_out_time.minute()]) Configs.get_instance().set_config("lunch_break", lunch_break) Configs.get_instance().save_json() Configs.get_instance().set_temp_config("work_time_table", self.work_time_table) Configs.get_instance().save_temp_json() from Scripts.UI.UIMain import UIMain UIMain.get_instance().refresh_UI()
def refresh_UI(self): self.settings_configs = Configs.get_instance().get_config("settings") detail_table_path = self.settings_configs["detail_table_path"] summary_table_path = self.settings_configs["summary_table_path"] out_path = self.settings_configs["out_path"] if os.path.isfile(detail_table_path): self.detailPathEdit.setText(detail_table_path) if os.path.isfile(summary_table_path): self.summaryPathEdit.setText(summary_table_path) if os.path.isdir(out_path): self.outPathEdit.setText(out_path)
def set_config(self, **kwargs): member_config = Configs.get_instance().get_member_config(self.name) if "email" in kwargs: member_config["email"] = kwargs["email"] if "bank_card" in kwargs: member_config["bank_card"] = kwargs["bank_card"] if "profession" in kwargs: member_config["profession"] = kwargs["profession"] if "department_1" in kwargs: member_config["department_1"] = kwargs["department_1"] if "department_2" in kwargs: member_config["department_2"] = kwargs["department_2"] if "in_date" in kwargs: member_config["in_date"] = Functions.QDateTime2string( kwargs["in_date"]) if "out_date" in kwargs: member_config["out_date"] = Functions.QDateTime2string( kwargs["out_date"]) Configs.get_instance().save_json() self.load_config_data()
def load_added_checkins(self): start_date = CommonDatas.get_instance().start_date self.added_checkin_list = [] added_checkins_config = Configs.get_instance( ).get_member_checkin_temp_config(self.name) for day in range(1, CommonDatas.get_instance().days_number + 1): checkins = [] day_checkins = [] if str(day) in added_checkins_config: checkins = added_checkins_config[str(day)] for checkin in checkins: day_checkins.append(CommonDatas.get_instance().create_datetime( day=day, hour=checkin[0], minute=checkin[1])) self.added_checkin_list.append(day_checkins)
def export_file(self): error_tips = None miss_member = False settings_configs = Configs.get_instance().get_config("settings") if False and not os.path.isfile(settings_configs["detail_table_path"]): error_tips = "请选择明细表模板" elif False and not os.path.isfile( settings_configs["summary_table_path"]): error_tips = "请选择汇总表模板" elif not os.path.isdir(settings_configs["out_path"]): error_tips = "请选择输出文件路径" else: show_out_member = self.showOutMember.isChecked() for name, member in CommonDatas.get_instance().get_all_member_dict( show_out_member).items(): if len(member.email) <= 0: error_tips = name + "的邮箱没填写" elif len(member.bank_card) <= 0: error_tips = name + "的银行卡号没填写" if error_tips is not None: miss_member = member break if error_tips is not None: reply = QMessageBox.warning(self.widget, 'Message', error_tips, QMessageBox.Yes, QMessageBox.Yes) if reply == QMessageBox.Yes: if miss_member is not False: self.open_edit_member_data(member=miss_member) else: self.open_settings() return try: #导出明细表 ExportXLSX.export_detail_table( settings_configs["detail_table_path"], settings_configs["out_path"]) #导出汇总表 ExportXLSX.export_summary_table( settings_configs["summary_table_path"], settings_configs["out_path"]) except PermissionError as exc: QMessageBox.warning(self.widget, "Error", "文件导出错误" + str(exc), QMessageBox.Yes) else: os.system("start explorer " + settings_configs["out_path"].replace("/", "\\"))
def load_config_data(self): start_date = CommonDatas.get_instance().start_date member_config = Configs.get_instance().get_member_config(self.name) self.email = member_config["email"] self.bank_card = member_config["bank_card"] self.profession = member_config["profession"] self.department_1 = member_config["department_1"] self.department_2 = member_config["department_2"] self.in_date = Functions.string2datetime(member_config["in_date"]) self.out_date = Functions.string2datetime(member_config["out_date"]) self.ignore = (self.out_date.year == start_date.year and self.out_date.month < start_date.month) if self.in_date.year == start_date.year and start_date.month < self.in_date.month: #还没入职 self.ignore = True if self.in_date.year == start_date.year and self.in_date.month == start_date.month and 15 < self.in_date.day: #上个月15号以后入职不统计 self.ignore = True
def refresh_select_member(self, new_member=None): if new_member is not None: self.select_member = new_member if self.select_member is None: return self.select_member.calc_all_data() cur_year = CommonDatas.get_instance().start_date.year cur_month = CommonDatas.get_instance().start_date.month for index in range(1, CommonDatas.get_instance().days_number + 1): brush = QtGui.QBrush() if not self.select_member.in_company(index): #没入职或者离职了 brush.setColor(QtGui.QColor('Black')) elif not Configs.get_instance().get_is_work_time(index): #休息日 brush.setColor(QtGui.QColor('Black')) elif 0 < self.select_member.is_late_or_early(index): #迟到 brush.setColor(QtGui.QColor('Red')) else: brush.setColor(QtGui.QColor('Green')) cmd_fmt = QtGui.QTextCharFormat() cmd_fmt.setForeground(brush) self.calendar.setDateTextFormat(QDate(cur_year, cur_month, index), cmd_fmt) self.leaveMember.setCurrentText(self.select_member.name) self.inDateEdit.setDateTime(self.select_member.in_date) self.outDateEdit.setDateTime(self.select_member.out_date) #显示 member = self.select_member self.detailedInfo.setText(member.name) self.detailedInfo.append("缺卡次数:{0}".format(member.lack_checkin_count)) self.detailedInfo.append("迟到早退天数:{0} 罚款总数:{1}".format( member.late_or_early_count, member.late_or_early_fine_number)) self.detailedInfo.append("工作天数:{0} 休息天数:{1}".format( member.work_days, member.holidays)) self.detailedInfo.append("请假次数:{0} 请假时长:{1}".format( member.get_leave_count(), Functions.timedelta2string(member.get_leave_duration())))
def export_detail_table(template_path, out_dir): start_date = CommonDatas.get_instance().start_date out_path = os.path.join(out_dir, "{0:02d}月考勤明细.xlsx".format(start_date.month)) #out_path = copy_template(template_path, out_dir, "{0:02d}月考勤明细{1}") xlsx_table = openpyxl.Workbook() xlsx_sheet = xlsx_table.get_active_sheet() #成员信息 member_dict = CommonDatas.get_instance().get_all_member_dict() member_list = list(member_dict.values()) #初始表格样式 sheet_row, sheet_column = init_detail_sheet( xlsx_sheet, len(member_list), CommonDatas.get_instance().days_number) #成员数据 for index, member in enumerate(member_list): row = 5 + index member.calc_all_data() #序号 xlsx_sheet.cell(row, 1).value = index + 1 #名字 xlsx_sheet.cell(row, 2).value = member.name #打卡情况 for day in range(1, CommonDatas.get_instance().days_number + 1): colum1 = 2 + 2 * day - 1 #上午 colum2 = colum1 + 1 #下午 cur_date = CommonDatas.get_instance().create_datetime(day=day) xlsx_cell1 = xlsx_sheet.cell(row, colum1) xlsx_cell2 = xlsx_sheet.cell(row, colum2) #初始化 xlsx_cell1.value = "√" xlsx_cell2.value = "√" if not member.in_company(day): #没入职 xlsx_sheet.merge_cells(None, row, colum1, row, colum2) xlsx_cell1.value = "未入职" elif not Configs.get_instance().get_is_work_time(day): #休息 xlsx_cell1.value = "休息" xlsx_cell2.value = "休息" elif 0 < member.is_late_or_early(day): #迟到或者早退 duration, late, early = member.get_late_and_early_time(day) if 1440 == duration or 480 == duration: xlsx_sheet.merge_cells(None, row, colum1, row, colum2) xlsx_cell1.fill = const_fill_purple xlsx_cell1.value = "缺卡" else: if 0 < late: xlsx_cell1.fill = const_fill_yellow xlsx_cell1.value = "迟到{0}分钟".format(late) if 0 < early: xlsx_cell2.fill = const_fill_yellow xlsx_cell2.value = " 早退{0}分钟".format(early) #计算请假 leave_duration, am_duration, pm_duration = member.get_leave_duration( day) work_day_duration = CommonDatas.get_instance( ).get_work_day_duration() if leave_duration == work_day_duration: #全天请假 xlsx_cell1.fill = const_fill_red xlsx_cell2.fill = const_fill_red xlsx_sheet.merge_cells(None, row, colum1, row, colum2) xlsx_cell1.value = "请假" + Functions.timedelta2string( leave_duration) else: if 0 < am_duration.total_seconds(): xlsx_cell1.fill = const_fill_red xlsx_cell1.value = "请假" + Functions.timedelta2string( am_duration) if 0 < pm_duration.total_seconds(): xlsx_cell2.fill = const_fill_red xlsx_cell2.value = "请假" + Functions.timedelta2string( pm_duration) cloum_offset = 2 + 2 * CommonDatas.get_instance().days_number + 1 #请假次数 xlsx_sheet.cell(row, cloum_offset).value = member.get_leave_count() #请假小时 xlsx_sheet.cell(row, cloum_offset + 1).value = Functions.timedelta2string( member.get_leave_duration()) #迟到次数 xlsx_sheet.cell(row, cloum_offset + 2).value = member.late_or_early_count #缺卡次数 xlsx_sheet.cell(row, cloum_offset + 3).value = member.lack_checkin_count #罚款金额 xlsx_sheet.cell(row, cloum_offset + 4).value = member.late_or_early_fine_number xlsx_table.save(out_path)
def get_leave_text_list(self): return Configs.get_instance().get_member_leave_temp_config(self.name)
def load_leaves_data(self): leave_text_list = Configs.get_instance().get_member_leave_temp_config( self.name) self.set_leaves(leave_text_list, False)
def add_in_checkin(self): date = self.calendar.selectedDate() work_time = Configs.get_instance().get_config("work_time") self.select_member.add_checkin(int(date.day()), [work_time[0][0], work_time[0][1]]) self.refresh_select_member()