From bf7ea77e44f3e792e044e96af846a5caa52bb62d Mon Sep 17 00:00:00 2001 From: ljmwkx <1340053001@qq.com> Date: Sun, 22 Dec 2024 14:44:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=A9=E4=B8=9A=20=E5=BC=80=E5=A7=8B?= =?UTF-8?q?=E7=BB=93=E6=9D=9F=E6=97=B6=E9=97=B4=20=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_wechat/models/hr_attendance_detail.py | 856 ++++++++++++------- 1 file changed, 559 insertions(+), 297 deletions(-) diff --git a/yuthon_wechat/models/hr_attendance_detail.py b/yuthon_wechat/models/hr_attendance_detail.py index 0d1083269..4eb43e73f 100644 --- a/yuthon_wechat/models/hr_attendance_detail.py +++ b/yuthon_wechat/models/hr_attendance_detail.py @@ -5,6 +5,7 @@ from datetime import datetime, timedelta, time import logging import traceback from odoo import api, fields, models, tools, _ +from dateutil.relativedelta import relativedelta from ...yuthon_wechat.utils.common import utils_list_page _logger = logging.getLogger(__name__) @@ -91,7 +92,7 @@ class HrAttendanceDetail(models.Model): return user_list @staticmethod - def _get_wx_attendance_data(userid_limit): + def _get_wx_attendance_data(userid_limit, now_time, start_time): """ 获取企业微信的打卡信息 :param wx_work_checkin_api: 企业微信api @@ -99,8 +100,8 @@ class HrAttendanceDetail(models.Model): :return: """ # 先按照天抓取,时间戳 - now_time = datetime.now() + timedelta(hours=8) - start_time = now_time - timedelta(days=30) + # now_time = datetime.now() + timedelta(hours=8) + # start_time = now_time - timedelta(days=30) start_time_stamp = int(start_time.timestamp()) end_time_stamp = int(now_time.timestamp()) # 整理请求信息 @@ -239,297 +240,297 @@ class HrAttendanceDetail(models.Model): media_list = self._check_wx_attendance_media(data) attendance_detail_obj.attendance_detail_image_ids = media_list except Exception as e: - _logger.error( - '检查保存之前的数据分析出想要的数据失败,异常:{0},数据信息{1},异常详情:{2}'.format(str(e), str(data), - str(traceback.format_exc()))) + _logger.error('检查保存之前的数据分析出想要的数据失败,异常:{0},数据信息{1},异常详情:{2}'.format(str(e), str(data), + str(traceback.format_exc()))) - userid = data.get("userid", "") - # 区分当天的上班,下班,中午打卡,合并一个 - checkin_time_now = checkin_time + timedelta(hours=8) if checkin_time else None - sch_checkin_time_now = sch_checkin_time + timedelta(hours=8) if sch_checkin_time else None - current_data = (sch_checkin_time + timedelta(hours=8)).strftime("%Y-%m-%d") if sch_checkin_time_now else checkin_time_now.strftime("%Y-%m-%d") - # 同步整理当天出勤数据 - attendance_obj = self.env['hr.attendance'].search( - [("userid", "=", userid), ("current_data", "=", current_data)], limit=1) - attendance_obj.attendance_type = "wx_work" - checkin_type = data.get("checkin_type", "") - exception_type = data.get("exception_type", "") - if not attendance_obj: - res_user_obj = self.env['res.users'].search([("oauth_uid", "=", userid)], limit=1) - hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "=", res_user_obj.id)], limit=1) - if not hr_employee_obj.default_planning_role_id: - attendance_obj = self.env['hr.attendance'].sudo().create({ - 'employee_id': hr_employee_obj.id, - "userid": userid, - "current_data": current_data, - "attendance_type": "wx_work" - }) - else: - current_datetime_start = datetime.combine(datetime.strptime(current_data, '%Y-%m-%d'), datetime.min.time()) - current_datetime_end = datetime.combine(datetime.strptime(current_data, '%Y-%m-%d'), datetime.max.time()) - planning_slot_id = self.env['planning.slot'].search( - [('resource_id', '=', hr_employee_obj.resource_id.id), - ('start_datetime', '>=', current_datetime_start), - ('start_datetime', '<=', current_datetime_end)]) - if planning_slot_id: - attendance_obj = self.env['hr.attendance'].sudo().create({ - 'employee_id': hr_employee_obj.id, - "userid": userid, - "current_data": current_data, - "shift_id": planning_slot_id.id, - "attendance_type": "wx_work" - }) - if not hr_employee_obj.default_planning_role_id: - # 获取考勤日历的上班下班时间 - min_hour_from = self.env['resource.calendar'].search([])[0].attendance_ids[0].hour_from - min_hour = int(min_hour_from) - min_minute = int(min_hour_from * 10 % min_hour_from) - max_hour_to = self.env['resource.calendar'].search([])[-1].attendance_ids[0].hour_to - max_hour = int(max_hour_to) - max_minute = int(max_hour_to * 10 % max_hour_to) - if attendance_obj.is_approval: - # 已经审批修复无需再次进行更新数据 - return True - # 赋值企业微信打卡数据 - will_datetime_start = checkin_time.replace(hour=min_hour, minute=min_minute) - will_datetime_end = checkin_time.replace(hour=max_hour, minute=max_minute) - if exception_type != "未打卡": - if checkin_time and checkin_type == "上班打卡" and exception_type != "未打卡" and not attendance_obj.check_in: - attendance_obj.sudo().write({ - "sch_check_in_time": sch_checkin_time, - "check_in": checkin_time, - "is_late_card": checkin_time > will_datetime_start, - }) - elif checkin_time and checkin_type == "下班打卡" and exception_type != "未打卡" and not attendance_obj.check_out: - attendance_obj.sudo().write({ - "sch_check_out_time": sch_checkin_time, - "check_out": checkin_time, - "is_early_card": will_datetime_end > checkin_time, - }) - elif attendance_obj.check_in and checkin_time and checkin_type == "上班打卡" and exception_type != "未打卡" and checkin_time < attendance_obj.check_in: - attendance_obj.sudo().write({ - "sch_check_in_time": sch_checkin_time, - "check_in": checkin_time, - "is_late_card": checkin_time > will_datetime_start, - }) - elif attendance_obj.check_out and checkin_time and checkin_type == "下班打卡" and exception_type != "未打卡" and checkin_time > attendance_obj.check_out: - attendance_obj.sudo().write({ - "sch_check_out_time": sch_checkin_time, - "check_out": checkin_time, - "is_early_card": will_datetime_end > checkin_time, - }) - elif checkin_time and exception_type != "未打卡" and not attendance_obj.check_in and not attendance_obj.check_out: - attendance_obj.sudo().write({ - "sch_check_in_time": sch_checkin_time, - "check_in": checkin_time, - "is_late_card": checkin_time > will_datetime_start, - }) - elif checkin_time and exception_type != "未打卡" and attendance_obj.check_in and not attendance_obj.check_out: - attendance_obj.sudo().write({ - "sch_check_out_time": sch_checkin_time, - "check_out": checkin_time, - "is_early_card": will_datetime_end > checkin_time, - }) - elif attendance_obj.is_early_card or attendance_obj.is_late_card: - attendance_obj.sudo().write({"is_abnormal": True}) - else: - attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) - else: - current_data = datetime.strptime(current_data, '%Y-%m-%d') - # 获取当天的起始和结束时间 - current_datetime_start = datetime.combine(current_data, datetime.min.time()) - current_datetime_end = datetime.combine(current_data, datetime.max.time()) - # 获取本人当天的班次 - planning_id = self.env['planning.slot'].search([('resource_id', '=', hr_employee_obj.resource_id.id), - ('start_datetime', '>=', current_datetime_start), - ('start_datetime', '<=', current_datetime_end)]) - if planning_id: - planning_start_time = planning_id.start_datetime + timedelta(hours=8) - planning_end_time = planning_id.end_datetime + timedelta(hours=8) - if planning_id.role_id.name == '保安部': - # {'白班': [['8:30', '9.30'], ['8:30', '9.30']]}white - # {'中班': [['8:30', '9.30'], ['8:30', '9.30']]}mid - # {'夜班': [['8:30', '9.30'], ['8:30', '9.30']]}night - # 白班上班区间 - start_time = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) - end_time = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) - # 白班下班区间 - start_time1 = datetime.combine(current_data, time(2, 0)) + timedelta(hours=8) - end_time1 = datetime.combine(current_data, time(4, 0)) + timedelta(hours=8) - # 中班上班区间 - start_time2 = datetime.combine(current_data, time(14, 0)) + timedelta(hours=8) - end_time2 = datetime.combine(current_data, time(17, 0)) + timedelta(hours=8) - # 中班下班区间 - start_time3 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) - end_time3 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) - # 夜班上班区间 - start_time4 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) - end_time4 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) - # 夜班下班区间 - start_time5 = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) - end_time5 = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) - if checkin_time: - planning_name = planning_id.template_id.planning_name - if start_time <= checkin_time <= end_time and planning_name == '白班': - attendance_obj.sudo().write({ - "check_in": checkin_time, - "is_late_card": checkin_time > planning_start_time - }) - elif start_time1 <= checkin_time <= end_time1 and planning_name == '白班': - attendance_obj.sudo().write({ - "check_out": checkin_time, - "is_early_card": planning_end_time > checkin_time, - }) - elif start_time2 <= checkin_time <= end_time2 and planning_name == '中班': - attendance_obj.sudo().write({ - "check_in": checkin_time, - "is_late_card": checkin_time > planning_start_time - }) - elif start_time3 <= checkin_time <= end_time3 and planning_name == '中班': - attendance_obj.sudo().write({ - "check_out": checkin_time, - "is_early_card": planning_end_time > checkin_time, - }) - elif start_time4 <= checkin_time <= end_time4 and planning_name == '夜班': - attendance_obj.sudo().write({ - "check_in": checkin_time, - "is_late_card": checkin_time > planning_start_time - }) - elif start_time5 <= checkin_time <= end_time5 and planning_name == '夜班': - attendance_obj.sudo().write({ - "check_out": checkin_time, - "is_early_card": planning_end_time > checkin_time, - }) - elif attendance_obj.is_early_card or attendance_obj.is_late_card: - attendance_obj.sudo().write({"is_abnormal": True}) - else: - attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) - # elif planning_id.role_id.name == '工程部': - # # 白班和白值上班区间 - # start_time = datetime.combine(current_data, time(7, 0)) + timedelta( - # hours=8) - # end_time = datetime.combine(current_data, time(10, 0)) + timedelta( - # hours=8) - # # 白班和白值下班区间 - # start_time1 = datetime.combine(current_data, - # time(16, 0)) + timedelta(hours=8) - # end_time1 = datetime.combine(current_data, time(19, 0)) + timedelta( - # hours=8) - # # 白值值班打卡区间 - # start_time2 = datetime.combine(current_data, - # time(11, 30)) + timedelta(hours=8) - # end_time2 = datetime.combine(current_data, time(13, 30)) + timedelta( - # hours=8) - # # 中夜上班区间 中夜下班区间跟白班上班区间一样 - # start_time3 = datetime.combine(current_data, - # time(13, 0)) + timedelta(hours=8) - # end_time3 = datetime.combine(current_data, time(16, 0)) + timedelta( - # hours=8) - # # 中夜值班打卡区间 - # start_time4 = datetime.combine(current_data, - # time(20, 0)) + timedelta(hours=8) - # end_time4 = datetime.combine(current_data, time(23, 0)) + timedelta( - # hours=8) - # if planning_id: - # if checkin_time: - # if start_time <= checkin_time <= end_time and not attendance_obj.check_in and ( - # planning_name in ['白班', '白值']): - # attendance_obj.sudo().write({ - # "check_in": checkin_time, - # "is_late_card": checkin_time > planning_start_time - # }) - # elif end_time1 <= checkin_time <= start_time1 and not attendance_obj.check_out and ( - # planning_name in ['白班', '白值']): - # attendance_obj.sudo().write({ - # "check_out": checkin_time, - # "is_early_card": planning_end_time > checkin_time, - # }) - # elif start_time3 <= checkin_time <= end_time3 and not attendance_obj.check_in and planning_name == '中夜': - # attendance_obj.sudo().write({ - # "check_in": checkin_time, - # "is_late_card": checkin_time > planning_start_time - # }) - # elif start_time <= checkin_time <= end_time and not attendance_obj.check_out and planning_name == '中夜': - # attendance_obj.sudo().write({ - # "check_out": checkin_time, - # "is_early_card": checkin_time > planning_start_time - # }) - # elif planning_id.template_id.planning == '白值' and start_time2 <= checkin_time <= end_time2: - # attendance_obj.sudo().write({ - # "sch_check_out_time": sch_checkin_time, - # "noon_duty": checkin_time, - # }) - # elif planning_id.template_id.planning == '中夜' and start_time4 <= checkin_time <= end_time4: - # attendance_obj.sudo().write({ - # "sch_check_out_time": sch_checkin_time, - # "night_duty": checkin_time, - # }) - # # 异常情况处理,移到所有打卡逻辑之后 - # if (attendance_obj.is_early_card or attendance_obj.is_late_card or - # (planning_id.template_id.planning == '白值' and not attendance_obj.noon_duty) or - # (planning_id.template_id.planning == '中夜' and not attendance_obj.night_duty)): - # attendance_obj.sudo().write({"is_abnormal": True}) - # else: - # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) - # elif planning_id.role_id.name == '联安粮储': - # # 白班上班区间 - # start_time = datetime.combine(current_data, time(7, 0)) + timedelta( - # hours=8) - # end_time = datetime.combine(current_data, time(10, 0)) + timedelta( - # hours=8) - # # 白班下班区间 - # start_time1 = datetime.combine(current_data, - # time(15, 0)) + timedelta(hours=8) - # end_time1 = datetime.combine(current_data, time(18, 0)) + timedelta( - # hours=8) - # # 白值上班 - # start_time2 = datetime.combine(current_data, time(8, 0)) + timedelta( - # hours=8) - # end_time2 = datetime.combine(current_data, time(10, 0)) + timedelta( - # hours=8) - # # 白值下班 - # start_time4 = datetime.combine(current_data, time(4, 0)) + timedelta( - # hours=8) - # end_time4 = datetime.combine(current_data, time(7, 0)) + timedelta( - # hours=8) - # # 白值打卡区间、 - # start_time3 = datetime.combine(current_data, - # time(11, 30)) + timedelta(hours=8) - # end_time3 = datetime.combine(current_data, time(13, 30)) + timedelta( - # hours=8) - # if planning_id: - # if start_time <= checkin_time <= end_time and not attendance_obj.check_in and planning_name == '白班': - # attendance_obj.sudo().write({ - # "check_in": checkin_time, - # "is_late_card": checkin_time > planning_start_time - # }) - # elif start_time1 <= checkin_time <= end_time1 and not attendance_obj.check_out and planning_name == '白班': - # attendance_obj.sudo().write({ - # "check_out": checkin_time, - # "is_early_card": planning_end_time > checkin_time, - # }) - # elif start_time2 <= checkin_time <= end_time2 and not attendance_obj.check_in and planning_name == '白值': - # attendance_obj.sudo().write({ - # "check_in": checkin_time, - # "is_late_card": checkin_time > planning_start_time, - # }) - # elif start_time4 <= checkin_time <= end_time4 and not attendance_obj.check_out and planning_name == '白值': - # attendance_obj.sudo().write({ - # "check_out": checkin_time, - # "is_early_card": planning_end_time > checkin_time, - # }) - # elif start_time3 <= checkin_time <= end_time3 and planning_name == '白值': - # attendance_obj.sudo().write({ - # "noon_duty": checkin_time, - # }) - # if (attendance_obj.is_early_card or attendance_obj.is_late_card or - # (planning_id.template_id.planning == '白值班' and not attendance_obj.noon_duty)): - # attendance_obj.sudo().write({"is_abnormal": True}) - # else: - # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) - # 进行关联 - attendance_detail_obj.hr_attendance_id = attendance_obj.id - return True + # def _check_wx_attendance_data(self, data, checkin_time, sch_checkin_time): + # userid = data.get("userid", "") + # # 区分当天的上班,下班,中午打卡,合并一个 + # checkin_time_now = checkin_time + timedelta(hours=8) if checkin_time else None + # sch_checkin_time_now = sch_checkin_time + timedelta(hours=8) if sch_checkin_time else None + # current_data = (sch_checkin_time + timedelta(hours=8)).strftime("%Y-%m-%d") if sch_checkin_time_now else checkin_time_now.strftime("%Y-%m-%d") + # # 同步整理当天出勤数据 + # attendance_obj = self.env['hr.attendance'].search( + # [("userid", "=", userid), ("current_data", "=", current_data)], limit=1) + # attendance_obj.attendance_type = "wx_work" + # checkin_type = data.get("checkin_type", "") + # exception_type = data.get("exception_type", "") + # if not attendance_obj: + # res_user_obj = self.env['res.users'].search([("oauth_uid", "=", userid)], limit=1) + # hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "=", res_user_obj.id)], limit=1) + # if not hr_employee_obj.default_planning_role_id: + # attendance_obj = self.env['hr.attendance'].sudo().create({ + # 'employee_id': hr_employee_obj.id, + # "userid": userid, + # "current_data": current_data, + # "attendance_type": "wx_work" + # }) + # else: + # current_datetime_start = datetime.combine(datetime.strptime(current_data, '%Y-%m-%d'), datetime.min.time()) + # current_datetime_end = datetime.combine(datetime.strptime(current_data, '%Y-%m-%d'), datetime.max.time()) + # planning_slot_id = self.env['planning.slot'].search( + # [('resource_id', '=', hr_employee_obj.resource_id.id), + # ('start_datetime', '>=', current_datetime_start), + # ('start_datetime', '<=', current_datetime_end)]) + # if planning_slot_id: + # attendance_obj = self.env['hr.attendance'].sudo().create({ + # 'employee_id': hr_employee_obj.id, + # "userid": userid, + # "current_data": current_data, + # "shift_id": planning_slot_id.id, + # "attendance_type": "wx_work" + # }) + # if not hr_employee_obj.default_planning_role_id: + # # 获取考勤日历的上班下班时间 + # min_hour_from = self.env['resource.calendar'].search([])[0].attendance_ids[0].hour_from + # min_hour = int(min_hour_from) + # min_minute = int(min_hour_from * 10 % min_hour_from) + # max_hour_to = self.env['resource.calendar'].search([])[-1].attendance_ids[0].hour_to + # max_hour = int(max_hour_to) + # max_minute = int(max_hour_to * 10 % max_hour_to) + # if attendance_obj.is_approval: + # # 已经审批修复无需再次进行更新数据 + # return True + # # 赋值企业微信打卡数据 + # will_datetime_start = checkin_time.replace(hour=min_hour, minute=min_minute) + # will_datetime_end = checkin_time.replace(hour=max_hour, minute=max_minute) + # if exception_type != "未打卡": + # if checkin_time and checkin_type == "上班打卡" and exception_type != "未打卡" and not attendance_obj.check_in: + # attendance_obj.sudo().write({ + # "sch_check_in_time": sch_checkin_time, + # "check_in": checkin_time, + # "is_late_card": checkin_time > will_datetime_start, + # }) + # elif checkin_time and checkin_type == "下班打卡" and exception_type != "未打卡" and not attendance_obj.check_out: + # attendance_obj.sudo().write({ + # "sch_check_out_time": sch_checkin_time, + # "check_out": checkin_time, + # "is_early_card": will_datetime_end > checkin_time, + # }) + # elif attendance_obj.check_in and checkin_time and checkin_type == "上班打卡" and exception_type != "未打卡" and checkin_time < attendance_obj.check_in: + # attendance_obj.sudo().write({ + # "sch_check_in_time": sch_checkin_time, + # "check_in": checkin_time, + # "is_late_card": checkin_time > will_datetime_start, + # }) + # elif attendance_obj.check_out and checkin_time and checkin_type == "下班打卡" and exception_type != "未打卡" and checkin_time > attendance_obj.check_out: + # attendance_obj.sudo().write({ + # "sch_check_out_time": sch_checkin_time, + # "check_out": checkin_time, + # "is_early_card": will_datetime_end > checkin_time, + # }) + # elif checkin_time and exception_type != "未打卡" and not attendance_obj.check_in and not attendance_obj.check_out: + # attendance_obj.sudo().write({ + # "sch_check_in_time": sch_checkin_time, + # "check_in": checkin_time, + # "is_late_card": checkin_time > will_datetime_start, + # }) + # elif checkin_time and exception_type != "未打卡" and attendance_obj.check_in and not attendance_obj.check_out: + # attendance_obj.sudo().write({ + # "sch_check_out_time": sch_checkin_time, + # "check_out": checkin_time, + # "is_early_card": will_datetime_end > checkin_time, + # }) + # elif attendance_obj.is_early_card or attendance_obj.is_late_card: + # attendance_obj.sudo().write({"is_abnormal": True}) + # else: + # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + # else: + # current_data = datetime.strptime(current_data, '%Y-%m-%d') + # # 获取当天的起始和结束时间 + # current_datetime_start = datetime.combine(current_data, datetime.min.time()) + # current_datetime_end = datetime.combine(current_data, datetime.max.time()) + # # 获取本人当天的班次 + # planning_id = self.env['planning.slot'].search([('resource_id', '=', hr_employee_obj.resource_id.id), + # ('start_datetime', '>=', current_datetime_start), + # ('start_datetime', '<=', current_datetime_end)]) + # if planning_id: + # planning_start_time = planning_id.start_datetime + timedelta(hours=8) + # planning_end_time = planning_id.end_datetime + timedelta(hours=8) + # if planning_id.role_id.name == '保安部': + # # {'白班': [['8:30', '9.30'], ['8:30', '9.30']]}white + # # {'中班': [['8:30', '9.30'], ['8:30', '9.30']]}mid + # # {'夜班': [['8:30', '9.30'], ['8:30', '9.30']]}night + # # 白班上班区间 + # start_time = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) + # end_time = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) + # # 白班下班区间 + # start_time1 = datetime.combine(current_data, time(2, 0)) + timedelta(hours=8) + # end_time1 = datetime.combine(current_data, time(4, 0)) + timedelta(hours=8) + # # 中班上班区间 + # start_time2 = datetime.combine(current_data, time(14, 0)) + timedelta(hours=8) + # end_time2 = datetime.combine(current_data, time(17, 0)) + timedelta(hours=8) + # # 中班下班区间 + # start_time3 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) + # end_time3 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) + # # 夜班上班区间 + # start_time4 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) + # end_time4 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) + # # 夜班下班区间 + # start_time5 = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) + # end_time5 = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) + # if checkin_time: + # planning_name = planning_id.template_id.planning_name + # if start_time <= checkin_time <= end_time and planning_name == '白班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time1 <= checkin_time <= end_time1 and planning_name == '白班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif start_time2 <= checkin_time <= end_time2 and planning_name == '中班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time3 <= checkin_time <= end_time3 and planning_name == '中班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif start_time4 <= checkin_time <= end_time4 and planning_name == '夜班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time5 <= checkin_time <= end_time5 and planning_name == '夜班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif attendance_obj.is_early_card or attendance_obj.is_late_card: + # attendance_obj.sudo().write({"is_abnormal": True}) + # else: + # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + # # elif planning_id.role_id.name == '工程部': + # # # 白班和白值上班区间 + # # start_time = datetime.combine(current_data, time(7, 0)) + timedelta( + # # hours=8) + # # end_time = datetime.combine(current_data, time(10, 0)) + timedelta( + # # hours=8) + # # # 白班和白值下班区间 + # # start_time1 = datetime.combine(current_data, + # # time(16, 0)) + timedelta(hours=8) + # # end_time1 = datetime.combine(current_data, time(19, 0)) + timedelta( + # # hours=8) + # # # 白值值班打卡区间 + # # start_time2 = datetime.combine(current_data, + # # time(11, 30)) + timedelta(hours=8) + # # end_time2 = datetime.combine(current_data, time(13, 30)) + timedelta( + # # hours=8) + # # # 中夜上班区间 中夜下班区间跟白班上班区间一样 + # # start_time3 = datetime.combine(current_data, + # # time(13, 0)) + timedelta(hours=8) + # # end_time3 = datetime.combine(current_data, time(16, 0)) + timedelta( + # # hours=8) + # # # 中夜值班打卡区间 + # # start_time4 = datetime.combine(current_data, + # # time(20, 0)) + timedelta(hours=8) + # # end_time4 = datetime.combine(current_data, time(23, 0)) + timedelta( + # # hours=8) + # # if planning_id: + # # if checkin_time: + # # if start_time <= checkin_time <= end_time and not attendance_obj.check_in and ( + # # planning_name in ['白班', '白值']): + # # attendance_obj.sudo().write({ + # # "check_in": checkin_time, + # # "is_late_card": checkin_time > planning_start_time + # # }) + # # elif end_time1 <= checkin_time <= start_time1 and not attendance_obj.check_out and ( + # # planning_name in ['白班', '白值']): + # # attendance_obj.sudo().write({ + # # "check_out": checkin_time, + # # "is_early_card": planning_end_time > checkin_time, + # # }) + # # elif start_time3 <= checkin_time <= end_time3 and not attendance_obj.check_in and planning_name == '中夜': + # # attendance_obj.sudo().write({ + # # "check_in": checkin_time, + # # "is_late_card": checkin_time > planning_start_time + # # }) + # # elif start_time <= checkin_time <= end_time and not attendance_obj.check_out and planning_name == '中夜': + # # attendance_obj.sudo().write({ + # # "check_out": checkin_time, + # # "is_early_card": checkin_time > planning_start_time + # # }) + # # elif planning_id.template_id.planning == '白值' and start_time2 <= checkin_time <= end_time2: + # # attendance_obj.sudo().write({ + # # "sch_check_out_time": sch_checkin_time, + # # "noon_duty": checkin_time, + # # }) + # # elif planning_id.template_id.planning == '中夜' and start_time4 <= checkin_time <= end_time4: + # # attendance_obj.sudo().write({ + # # "sch_check_out_time": sch_checkin_time, + # # "night_duty": checkin_time, + # # }) + # # # 异常情况处理,移到所有打卡逻辑之后 + # # if (attendance_obj.is_early_card or attendance_obj.is_late_card or + # # (planning_id.template_id.planning == '白值' and not attendance_obj.noon_duty) or + # # (planning_id.template_id.planning == '中夜' and not attendance_obj.night_duty)): + # # attendance_obj.sudo().write({"is_abnormal": True}) + # # else: + # # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + # # elif planning_id.role_id.name == '联安粮储': + # # # 白班上班区间 + # # start_time = datetime.combine(current_data, time(7, 0)) + timedelta( + # # hours=8) + # # end_time = datetime.combine(current_data, time(10, 0)) + timedelta( + # # hours=8) + # # # 白班下班区间 + # # start_time1 = datetime.combine(current_data, + # # time(15, 0)) + timedelta(hours=8) + # # end_time1 = datetime.combine(current_data, time(18, 0)) + timedelta( + # # hours=8) + # # # 白值上班 + # # start_time2 = datetime.combine(current_data, time(8, 0)) + timedelta( + # # hours=8) + # # end_time2 = datetime.combine(current_data, time(10, 0)) + timedelta( + # # hours=8) + # # # 白值下班 + # # start_time4 = datetime.combine(current_data, time(4, 0)) + timedelta( + # # hours=8) + # # end_time4 = datetime.combine(current_data, time(7, 0)) + timedelta( + # # hours=8) + # # # 白值打卡区间、 + # # start_time3 = datetime.combine(current_data, + # # time(11, 30)) + timedelta(hours=8) + # # end_time3 = datetime.combine(current_data, time(13, 30)) + timedelta( + # # hours=8) + # # if planning_id: + # # if start_time <= checkin_time <= end_time and not attendance_obj.check_in and planning_name == '白班': + # # attendance_obj.sudo().write({ + # # "check_in": checkin_time, + # # "is_late_card": checkin_time > planning_start_time + # # }) + # # elif start_time1 <= checkin_time <= end_time1 and not attendance_obj.check_out and planning_name == '白班': + # # attendance_obj.sudo().write({ + # # "check_out": checkin_time, + # # "is_early_card": planning_end_time > checkin_time, + # # }) + # # elif start_time2 <= checkin_time <= end_time2 and not attendance_obj.check_in and planning_name == '白值': + # # attendance_obj.sudo().write({ + # # "check_in": checkin_time, + # # "is_late_card": checkin_time > planning_start_time, + # # }) + # # elif start_time4 <= checkin_time <= end_time4 and not attendance_obj.check_out and planning_name == '白值': + # # attendance_obj.sudo().write({ + # # "check_out": checkin_time, + # # "is_early_card": planning_end_time > checkin_time, + # # }) + # # elif start_time3 <= checkin_time <= end_time3 and planning_name == '白值': + # # attendance_obj.sudo().write({ + # # "noon_duty": checkin_time, + # # }) + # # if (attendance_obj.is_early_card or attendance_obj.is_late_card or + # # (planning_id.template_id.planning == '白值班' and not attendance_obj.noon_duty)): + # # attendance_obj.sudo().write({"is_abnormal": True}) + # # else: + # # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + # # 进行关联 + # attendance_detail_obj.hr_attendance_id = attendance_obj.id + # return True def get_hr_attendance_time(self): """ @@ -538,11 +539,14 @@ class HrAttendanceDetail(models.Model): """ # 从用户列表里获取企业微信的用户 user_list = self._get_wx_attendance_user_list() + now_time = datetime.now() + timedelta(hours=8) + start_time = now_time - timedelta(days=30) + # 企业微信获取打卡数据,要求用户分组100,分批获取打卡记录 for userid_limit in utils_list_page(user_list, 100): # 获取企业微信的打卡信息 try: - attendance_data = self._get_wx_attendance_data(userid_limit) + attendance_data = self._get_wx_attendance_data(userid_limit, now_time, start_time) attendance_result, response = self.sudo().env["wecom.apps"].sync_checkin_data(attendance_data) except Exception as e: _logger.error( @@ -573,7 +577,265 @@ class HrAttendanceDetail(models.Model): self._save_wx_attendance_detail_data(data, checkin_time, sch_checkin_time) except Exception as e: _logger.error( - '保存相关的企业微信的原始打卡信息失败,异常:{0},数据信息{1},异常详情:{2}'.format(str(e), - str(data), - str(traceback.format_exc()))) + '保存相关的企业微信的原始打卡信息失败,异常:{0},数据信息{1},异常详情:{2}'.format(str(e), str(data), str(traceback.format_exc()))) + + # 将取回来的数据进行组织整理写入到考勤表中 + user_obj = self.env['res.users'].search([]) + # 暂时先用for循环,如果后期加大频率,需改成并发 + for user in user_obj: + # 判断是否是微信用户 + if user.oauth_uid: + # 查询当前用户区间内的所有打卡数据没有的创建 + for current_date in self.divide_time_range_fixed(start_time, now_time): + # 写入打卡数据 + self._do_save_wx_attendance_data(user, current_date) return True + + def _do_save_wx_attendance_data(self, user, current_date): + """ + 开始 整理考勤数据 + :param user: + :param current_date: + :return: + """ + # 同步整理当天出勤数据 + attendance_obj = self.env['hr.attendance'].search([("userid", "=", user.id), ("current_data", "=", current_date)], limit=1) + hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "=", user.id)], limit=1) + current_datetime_start = datetime.combine(datetime.strptime(current_date, '%Y-%m-%d'), datetime.min.time()) + current_datetime_end = datetime.combine(datetime.strptime(current_date, '%Y-%m-%d'), datetime.max.time()) + if not attendance_obj: + # 判断是否是 普通打卡 + if not hr_employee_obj.default_planning_role_id: + attendance_obj = self.env['hr.attendance'].sudo().create({ + 'employee_id': hr_employee_obj.id, + "userid": user.id, + "current_data": current_date, + "attendance_type": "wx_work" + }) + self._do_not_planning_role(user, current_date, attendance_obj) + else: + planning_slot_id = self.env['planning.slot'].search( + [('resource_id', '=', hr_employee_obj.resource_id.id), + ('start_datetime', '>=', current_datetime_start), + ('start_datetime', '<=', current_datetime_end)]) + # 是否排班 + if planning_slot_id: + attendance_obj = self.env['hr.attendance'].sudo().create({ + 'employee_id': hr_employee_obj.id, + "userid": user.id, + "current_data": current_date, + "shift_id": planning_slot_id.id, + "attendance_type": "wx_work" + }) + self._do_planning_role(user, current_date, attendance_obj) + else: + # 没有排班 + return True + # 查询出当前抓取微信的当前时间的所有数据 + attendance_detail_obj = self.env['hr.attendance.detail'].sudo().search( + [("userid", "=", user.id), + ("checkin_time", ">=", current_datetime_start), + ("checkin_time", "<=", current_datetime_end)]) + # 关联 打卡详情 + attendance_detail_obj.hr_attendance_id = attendance_obj.id + return True + + + def _do_not_planning_role(self, user, current_date, attendance_obj): + """ + 正常班次的 上班下班判断 + :param user: 用户集合 + :param current_date: 循环判断的时间 + :param attendance_obj: 判断的时刻的考勤集合 + :return: + """ + current_datetime_start = datetime.combine(datetime.strptime(current_date, '%Y-%m-%d'), datetime.min.time()) + current_datetime_end = datetime.combine(datetime.strptime(current_date, '%Y-%m-%d'), datetime.max.time()) + # 获取考勤日历的上班下班时间 + min_hour_from = self.env['resource.calendar'].search([])[0].attendance_ids[0].hour_from + min_hour = int(min_hour_from) + min_minute = int(min_hour_from * 10 % min_hour_from) + max_hour_to = self.env['resource.calendar'].search([])[-1].attendance_ids[0].hour_to + max_hour = int(max_hour_to) + max_minute = int(max_hour_to * 10 % max_hour_to) + if attendance_obj.is_approval: + # 已经审批修复无需再次进行更新数据 + return True + + # 判断打卡情况排除未打卡情况 + attendance_detail_obj = self.env['hr.attendance.detail'].sudo().search( + [("exception_type", "!=", "未打卡"), + ("userid", "=", user.id), + ("checkin_time", ">=", current_datetime_start), + ("checkin_time", "<=", current_datetime_end)]) + # 没有打卡记录说明缺卡 + if len(attendance_detail_obj) <= 0: + attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + return True + # 打了一次卡记录说明缺卡 + elif len(attendance_detail_obj) == 1: + checkin_time = attendance_detail_obj.checkin_time + will_datetime_start = checkin_time.replace(hour=min_hour, minute=min_minute) + will_datetime_end = checkin_time.replace(hour=max_hour, minute=max_minute) + + if attendance_detail_obj.checkin_type == "上班打卡": + attendance_obj.sudo().write({ + "sch_check_in_time": will_datetime_start, + "check_in": checkin_time, + "is_late_card": checkin_time > will_datetime_start, + "is_no_card": True, + }) + elif attendance_detail_obj.checkin_type == "下班打卡": + attendance_obj.sudo().write({ + "sch_check_out_time": will_datetime_end, + "check_out": checkin_time, + "is_early_card": will_datetime_end > checkin_time, + "is_no_card": True, + }) + else: + # 如果是 打卡时间 早于 上班时间 判定为 上班打卡 缺下班卡 + if will_datetime_start > checkin_time: + attendance_obj.sudo().write({ + "sch_check_in_time": will_datetime_start, + "check_in": checkin_time, + "is_late_card": checkin_time > will_datetime_start, + "is_no_card": True, + }) + # 如果是 打卡时间 晚于 下班时间 判定为 下班打卡 缺上班卡 + elif will_datetime_end < checkin_time: + attendance_obj.sudo().write({ + "sch_check_out_time": will_datetime_end, + "check_out": checkin_time, + "is_early_card": will_datetime_end > checkin_time, + "is_no_card": True, + }) + # 既不是上班也不是下班,默认为上班打卡 + else: + attendance_obj.sudo().write({ + "sch_check_in_time": will_datetime_start, + "check_in": checkin_time, + "is_late_card": checkin_time > will_datetime_start, + "is_no_card": True, + }) + return True + else: + # 多次打卡时间的集合 + checkin_time_list = [obj.checkin_time for obj in attendance_detail_obj] + # 最早 和 最晚 时间 + min_time = min(checkin_time_list) + max_time = max(checkin_time_list) + + # 赋值企业微信打卡数据 + will_datetime_start = min_time.replace(hour=min_hour, minute=min_minute) + will_datetime_end = max_time.replace(hour=max_hour, minute=max_minute) + # 查询最早时间上班时间 查询最晚下班时间 + attendance_obj.sudo().write({ + "sch_check_in_time": will_datetime_start, + "check_in": min_time, + "is_late_card": min_time > will_datetime_start, + + "sch_check_out_time": will_datetime_end, + "check_out": max_time, + "is_early_card": will_datetime_end > max_time, + }) + return True + + def _do_planning_role(self, user, current_date, attendance_obj): + """ + 带有计划的班次判断 + :param user: 用户集合 + :param current_date: 循环判断的时间 + :param attendance_obj: 判断的时刻的考勤集合 + :return: + """ + current_data = datetime.strptime(current_date, '%Y-%m-%d') + # 获取当天的起始和结束时间 + current_datetime_start = datetime.combine(current_data, datetime.min.time()) + current_datetime_end = datetime.combine(current_data, datetime.max.time()) + # 获取本人当天的班次 + hr_employee_obj = self.env['hr.employee'].sudo().search([("user_id", "=", user.id)], limit=1) + planning_id = self.env['planning.slot'].search( + [('resource_id', '=', hr_employee_obj.resource_id.id), + ('start_datetime', '>=', current_datetime_start), + ('start_datetime', '<=', current_datetime_end)]) + + if planning_id: + planning_start_time = planning_id.start_datetime + timedelta(hours=8) + planning_end_time = planning_id.end_datetime + timedelta(hours=8) + + # 判断打卡情况排除未打卡情况 + attendance_detail_obj = self.env['hr.attendance.detail'].sudo().search( + [("exception_type", "!=", "未打卡"), + ("userid", "=", user.id), + ("checkin_time", ">=", planning_start_time), + ("checkin_time", "<=", planning_end_time)]) + + if planning_id.role_id.name == '保安部': + # {'白班': [['8:30', '9.30'], ['8:30', '9.30']]}white + # {'中班': [['8:30', '9.30'], ['8:30', '9.30']]}mid + # {'夜班': [['8:30', '9.30'], ['8:30', '9.30']]}night + # 白班上班区间 + start_time = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) + end_time = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) + # 白班下班区间 + start_time1 = datetime.combine(current_data, time(2, 0)) + timedelta(hours=8) + end_time1 = datetime.combine(current_data, time(4, 0)) + timedelta(hours=8) + # 中班上班区间 + start_time2 = datetime.combine(current_data, time(14, 0)) + timedelta(hours=8) + end_time2 = datetime.combine(current_data, time(17, 0)) + timedelta(hours=8) + # 中班下班区间 + start_time3 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) + end_time3 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) + # 夜班上班区间 + start_time4 = datetime.combine(current_data, time(22, 0)) + timedelta(hours=8) + end_time4 = datetime.combine(current_data, time(1, 0)) + timedelta(hours=8) + # 夜班下班区间 + start_time5 = datetime.combine(current_data, time(6, 0)) + timedelta(hours=8) + end_time5 = datetime.combine(current_data, time(9, 0)) + timedelta(hours=8) + # if checkin_time: + # planning_name = planning_id.template_id.planning_name + # if start_time <= checkin_time <= end_time and planning_name == '白班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time1 <= checkin_time <= end_time1 and planning_name == '白班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif start_time2 <= checkin_time <= end_time2 and planning_name == '中班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time3 <= checkin_time <= end_time3 and planning_name == '中班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif start_time4 <= checkin_time <= end_time4 and planning_name == '夜班': + # attendance_obj.sudo().write({ + # "check_in": checkin_time, + # "is_late_card": checkin_time > planning_start_time + # }) + # elif start_time5 <= checkin_time <= end_time5 and planning_name == '夜班': + # attendance_obj.sudo().write({ + # "check_out": checkin_time, + # "is_early_card": planning_end_time > checkin_time, + # }) + # elif attendance_obj.is_early_card or attendance_obj.is_late_card: + # attendance_obj.sudo().write({"is_abnormal": True}) + # else: + # attendance_obj.sudo().write({"is_no_card": True, "is_abnormal": True}) + + return True + + @staticmethod + def divide_time_range_fixed(start_time, end_time): + time_ranges = [start_time] + while start_time <= end_time: + current_date = start_time + relativedelta(days=1) + time_ranges.append(current_date.strftime("%Y-%m-%d")) + start_time = current_date + return time_ranges \ No newline at end of file