@@ -96,111 +96,107 @@ class HrAttendanceDetail(models.Model):
|
||||
}
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
record = super(HrAttendanceDetail, self).create(vals)
|
||||
# 批量导入时跳过企业微信通知
|
||||
if self.env.context.get('skip_iot_notify'):
|
||||
return record
|
||||
if record.employee_id.name not in ['Administrator', '张丽芳']:
|
||||
resource_user_ids = record.employee_id.resource_calendar_id.resource_user_ids.ids
|
||||
is_resource_user = True if record.employee_id.id in resource_user_ids else False
|
||||
employee_id = record.employee_id
|
||||
checkin_datetime = record.checkin_time
|
||||
last_record = self.search([
|
||||
('employee_id', '=', employee_id.id),
|
||||
('source', '=', 'iot'),
|
||||
('checkin_time', '<', checkin_datetime)
|
||||
], order='checkin_time desc', limit=1)
|
||||
# 如果上一条记录存在,并且时间差 < 60秒 → 不发提醒
|
||||
skip_notify = False
|
||||
if last_record:
|
||||
time_diff = checkin_datetime - last_record.checkin_time
|
||||
if time_diff.total_seconds() < 60:
|
||||
skip_notify = True # 小于1分钟,跳过提醒
|
||||
if record.employee_id and record.checkin_time and record.source == 'iot' and not is_resource_user and not skip_notify:
|
||||
current_data = record.checkin_time.date() + timedelta(hours=8)
|
||||
day_start = checkin_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
day_end = checkin_datetime.replace(hour=23, minute=59, second=59, microsecond=99)
|
||||
daily_iot_records = self.search([
|
||||
('employee_id', '=', employee_id.id),
|
||||
('source', '=', 'iot'),
|
||||
('checkin_time', '>=', day_start),
|
||||
('checkin_time', '<=', day_end)
|
||||
], order='checkin_time asc')
|
||||
if daily_iot_records:
|
||||
message = f"打卡成功!今日上班时间:{record.checkin_time + timedelta(hours=8)}: {employee_id.name},祝您工作愉快!"
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
# if record.employee_id.name == '蒋彬':
|
||||
# self.sudo().env["wecom.apps"].sync_send_message(
|
||||
# category='att', user_id='18562027762',
|
||||
# message=message + f'管理员测试管理员测试{vals}',
|
||||
# )
|
||||
self.write({'remark': message})
|
||||
_logger.info(message)
|
||||
else:
|
||||
resource_user_ids = employee_id.resource_calendar_id.resource_user_ids.ids
|
||||
is_resource_user = True if employee_id.id in resource_user_ids else False
|
||||
# 哺乳人员
|
||||
suckling_employees = employee_id.resource_calendar_id.breastfeeding_holiday_ids.mapped('employee_id')
|
||||
def _get_attendance_template(self, employee, current_data):
|
||||
"""根据员工与打卡日期获取对应的班次模板,找不到返回 None。
|
||||
|
||||
逻辑与 compute_attendance_detail 中一致:先按排班(planning.slot)匹配,
|
||||
再按部门层级+角色兜底,最后回退到「集团行政」。
|
||||
"""
|
||||
slot_start = datetime.combine(current_data, datetime.min.time()) - timedelta(hours=8)
|
||||
slot_end = datetime.combine(current_data + timedelta(days=1), datetime.min.time()) - timedelta(hours=8)
|
||||
planning_slots = self.env['planning.slot'].search([
|
||||
('resource_id', '=', employee.resource_id.id),
|
||||
('start_datetime', '>=', slot_start),
|
||||
('start_datetime', '<', slot_end),
|
||||
], limit=1)
|
||||
planning_name = planning_slots.planning_name if planning_slots else None
|
||||
|
||||
def get_all_upper_depts(dept):
|
||||
"""递归获取部门及其所有上级部门的ID列表"""
|
||||
dept_ids = [dept.id]
|
||||
if dept.parent_id:
|
||||
dept_ids.extend(get_all_upper_depts(dept.parent_id))
|
||||
return dept_ids
|
||||
|
||||
all_dept_ids = get_all_upper_depts(employee_id.department_id)
|
||||
all_dept_ids = get_all_upper_depts(employee.department_id)
|
||||
|
||||
if not is_resource_user:
|
||||
slot_start = datetime.combine(current_data, datetime.min.time()) - timedelta(hours=8)
|
||||
slot_end = datetime.combine(current_data + timedelta(days=1), datetime.min.time()) - timedelta(
|
||||
hours=8)
|
||||
# 查找员工对应的班次
|
||||
planning_slots = self.env['planning.slot'].search([
|
||||
('resource_id', '=', employee_id.resource_id.id),
|
||||
('start_datetime', '>=', slot_start),
|
||||
('start_datetime', '<', slot_end),
|
||||
], limit=1)
|
||||
planning_name = planning_slots.planning_name if planning_slots else None
|
||||
template_domain = []
|
||||
if planning_name:
|
||||
template_domain.append(('planning_name', '=', planning_name))
|
||||
template_domain.append(('department_id', 'in', all_dept_ids))
|
||||
template = self.env['planning.slot.template'].search(template_domain, limit=1)
|
||||
# 如果模板里面找不到这个人 则还是往下判断(模板为空)
|
||||
if employee_id.id not in template.role_id.resource_ids.employee_id.ids:
|
||||
# 模板里找不到这个人则置空,继续往下兜底
|
||||
if template and employee.id not in template.role_id.resource_ids.employee_id.ids:
|
||||
template = None
|
||||
if not template:
|
||||
role_templates = [
|
||||
{'role_name': '厨卫(集团)', 'template': None},
|
||||
{'role_name': '项目运营岗', 'template': None}
|
||||
]
|
||||
|
||||
for item in role_templates:
|
||||
item['template'] = self.env['planning.slot.template'].search(
|
||||
[('role_id.name', '=', item['role_name'])], )
|
||||
[('role_id.name', '=', item['role_name'])])
|
||||
for item in role_templates:
|
||||
if item['template']:
|
||||
employee_ids = item['template'].role_id.resource_ids.employee_id.ids or []
|
||||
employee_list = list(employee_ids)
|
||||
if employee_id.id in employee_list:
|
||||
if employee.id in list(employee_ids):
|
||||
template = item['template']
|
||||
break
|
||||
if not template:
|
||||
template = self.env['planning.slot.template'].search(
|
||||
[('role_id.name', '=', '集团行政')],
|
||||
limit=1
|
||||
[('role_id.name', '=', '集团行政')], limit=1)
|
||||
return template
|
||||
|
||||
def _send_att_notify(self, employee_id, message, record, vals, test_users=None):
|
||||
"""发送企业微信考勤通知并写入 remark 日志。
|
||||
|
||||
:param test_users: 命中该名单的员工改用管理员测试号发送(保留原调试逻辑)
|
||||
"""
|
||||
test_users = test_users or []
|
||||
if employee_id.name in test_users:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id='18562027762',
|
||||
message=message + f'管理员测试管理员测试{vals}',
|
||||
)
|
||||
else:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
record.write({'remark': message})
|
||||
_logger.info(message)
|
||||
|
||||
def create(self, vals):
|
||||
record = super(HrAttendanceDetail, self).create(vals)
|
||||
# 批量导入时跳过企业微信通知
|
||||
if self.env.context.get('skip_iot_notify'):
|
||||
return record
|
||||
if record.employee_id.name not in ['Administrator', '张丽芳']:
|
||||
employee_id = record.employee_id
|
||||
checkin_datetime = record.checkin_time # UTC 时间
|
||||
resource_user_ids = employee_id.resource_calendar_id.resource_user_ids.ids
|
||||
is_resource_user = employee_id.id in resource_user_ids
|
||||
# 上一条记录存在且时间差 < 60秒 → 不重复提醒
|
||||
last_record = self.search([
|
||||
('employee_id', '=', employee_id.id),
|
||||
('source', '=', 'iot'),
|
||||
('checkin_time', '<', checkin_datetime)
|
||||
], order='checkin_time desc', limit=1)
|
||||
skip_notify = bool(last_record) and (checkin_datetime - last_record.checkin_time).total_seconds() < 60
|
||||
if employee_id and checkin_datetime and record.source == 'iot' and not is_resource_user and not skip_notify:
|
||||
# 本地时间表示(UTC+8),用于匹配班次模板与标准上下班时间
|
||||
current_data = checkin_datetime.date() + timedelta(hours=8)
|
||||
template = self._get_attendance_template(employee_id, current_data)
|
||||
if not template:
|
||||
# 找不到班次模板,默认按上班打卡提醒
|
||||
message = f"打卡成功!今日上班时间:{checkin_datetime + timedelta(hours=8)}: {employee_id.name},祝您工作愉快!"
|
||||
self._send_att_notify(employee_id, message, record, vals)
|
||||
else:
|
||||
sch_check_in_time, sch_check_out_time = self.normal_clock_in_time(template, current_data)
|
||||
# 判断是否是哺乳人员
|
||||
# 哺乳人员:下午班次下班时间提前 1 小时
|
||||
suckling_employees = employee_id.resource_calendar_id.breastfeeding_holiday_ids.mapped('employee_id')
|
||||
if employee_id in suckling_employees:
|
||||
# 判断是否是哺乳人员并调整标准打卡时间
|
||||
current_date = fields.Date.to_date(current_data) if current_data else None
|
||||
current_date = fields.Date.to_date(current_data)
|
||||
if current_date:
|
||||
# 查找当天的哺乳假记录(匹配员工+日期范围)
|
||||
breastfeeding_record = self.env['breastfeeding.holiday'].search([
|
||||
('employee_id', '=', employee_id.id),
|
||||
('calendar_start_time', '<=', current_date),
|
||||
@@ -208,21 +204,13 @@ class HrAttendanceDetail(models.Model):
|
||||
], limit=1)
|
||||
if breastfeeding_record.time_slot_selection == 'afternoon':
|
||||
sch_check_out_time = sch_check_out_time - timedelta(hours=1)
|
||||
|
||||
# 以标准下班时间为界:晚于下班时间算「下班」,否则算「上班」
|
||||
if checkin_datetime > sch_check_out_time:
|
||||
message = f"打卡成功!今日下班时间:{record.checkin_time + timedelta(hours=8)}: {employee_id.name},祝您归途平安!"
|
||||
if record.employee_id.name not in ['林伟东']:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id=employee_id.wecom_userid,
|
||||
message=message,
|
||||
)
|
||||
message = f"打卡成功!今日下班时间:{checkin_datetime + timedelta(hours=8)}: {employee_id.name},祝您归途平安!"
|
||||
self._send_att_notify(employee_id, message, record, vals, test_users=['林伟东'])
|
||||
else:
|
||||
self.sudo().env["wecom.apps"].sync_send_message(
|
||||
category='att', user_id='18562027762',
|
||||
message=message + f'管理员测试管理员测试{vals}',
|
||||
)
|
||||
self.write({'remark': message})
|
||||
_logger.info(message)
|
||||
message = f"打卡成功!今日上班时间:{checkin_datetime + timedelta(hours=8)}: {employee_id.name},祝您工作愉快!"
|
||||
self._send_att_notify(employee_id, message, record, vals)
|
||||
|
||||
if record.employee_id and record.checkin_time:
|
||||
self._sync_to_hr_attendance(record)
|
||||
|
||||
Reference in New Issue
Block a user