添加功能
This commit is contained in:
@@ -14,5 +14,18 @@
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="to_do_process_reminders_task" model="ir.cron">
|
||||
<field name="name">定时任务:待办提醒</field>
|
||||
<field name="model_id" ref="model_soong_workflow"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.to_do_process_reminders()</field>
|
||||
<field eval="False" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 08:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo import models, exceptions
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
import logging
|
||||
from datetime import datetime, date, time, timedelta
|
||||
@@ -395,6 +396,55 @@ class SoongWorkflowRecord(models.Model):
|
||||
|
||||
return super(SoongWorkflowRecord, self).get_view(view_id, view_type, **options)
|
||||
|
||||
def to_do_process_reminders(self):
|
||||
workflow_records = self.env['soong.workflow.record'].search([
|
||||
('approve_state', '=', 'pending'),
|
||||
('employee_ids', '!=', False)
|
||||
])
|
||||
employee_tasks = {}
|
||||
for record in workflow_records:
|
||||
try:
|
||||
biz_record = self.env[record.res_model].browse(record.res_id)
|
||||
urgency_level = biz_record.urgency_level or 'normal'
|
||||
task_type = 'urgent' if urgency_level in ('urgent', 'emergency') else 'normal'
|
||||
|
||||
for emp in record.employee_ids:
|
||||
emp_id = emp.id
|
||||
if emp_id not in employee_tasks:
|
||||
employee_tasks[emp_id] = {'urgent': 0, 'normal': 0, 'employee': emp}
|
||||
employee_tasks[emp_id][task_type] += 1
|
||||
except exceptions.MissingError as e:
|
||||
error_msg = str(e).strip()
|
||||
if "记录不存在或已删除" in error_msg:
|
||||
continue
|
||||
|
||||
for emp_id, task_data in employee_tasks.items():
|
||||
emp = task_data['employee']
|
||||
urgent_count = task_data['urgent']
|
||||
normal_count = task_data['normal']
|
||||
msg_parts = []
|
||||
if urgent_count > 0:
|
||||
msg_parts.append(f'特急任务{urgent_count}条')
|
||||
if normal_count > 0:
|
||||
msg_parts.append(f'常规待办{normal_count}条')
|
||||
if not msg_parts:
|
||||
continue
|
||||
reminder_msg = (
|
||||
f"您好,截至今日17:30,您有 {','.join(msg_parts)} 尚未处理,"
|
||||
"请及时登录系统完成办理。感谢配合!"
|
||||
)
|
||||
menu_id = self.env['ir.ui.menu'].search([('name', '=', '待办流程')], limit=1)
|
||||
target_url = f'https://oa.thtzjt.com/web#action=4378&model=soong.workflow.record&view_type=list&cids=2-1-3-4&menu_id={menu_id.id}'
|
||||
url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, emp.user_id.id)
|
||||
self.sudo().env["wecom.apps"].sync_send_message_textcard(
|
||||
category='notice',
|
||||
user_id=emp.wecom_userid,
|
||||
title='【待办流程提醒】',
|
||||
description=reminder_msg,
|
||||
url=url,
|
||||
btntxt="查看详情"
|
||||
)
|
||||
|
||||
# def get_department_employees(self, department_id):
|
||||
# valid_user_ids = set()
|
||||
# employee_ids = self.sudo().env['hr.employee'].search([('department_id', '=', department_id.id)])
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record forcecreate="True" id="hr_attendance_abnormal_task" model="ir.cron">
|
||||
<field name="name">定时任务:考勤异常提醒</field>
|
||||
<field name="model_id" ref="model_hr_attendance"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.attendance_abnormal_remind()</field>
|
||||
<field eval="True" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_type">months</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 12:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="attendance_month_data" model="ir.cron">
|
||||
<field name="name">定时任务:考勤统计</field>
|
||||
<field name="model_id" ref="model_hr_attendance_month_wizard"/>
|
||||
|
||||
@@ -3,7 +3,7 @@ from datetime import datetime, time
|
||||
from re import search
|
||||
|
||||
from odoo import models, fields, api, exceptions, _
|
||||
from datetime import timedelta
|
||||
from datetime import timedelta, date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo.tools import format_datetime, format_duration
|
||||
import logging
|
||||
@@ -242,55 +242,71 @@ class HrAttendance(models.Model):
|
||||
|
||||
#考勤异常提醒
|
||||
def attendance_abnormal_remind(self):
|
||||
all_employees = self.env['hr.employee'].search([])
|
||||
current_date = fields.Date.today()
|
||||
current_dt = fields.Datetime.now()
|
||||
month_start = current_date.replace(day=1)
|
||||
month_end = (month_start + relativedelta(months=1) - relativedelta(days=1))
|
||||
start_time = datetime.combine(current_date, datetime.min.time().replace(hour=8, minute=50))
|
||||
end_time = datetime.combine(current_date, datetime.min.time().replace(hour=9, minute=10))
|
||||
if not (start_time <= current_dt <= end_time):
|
||||
return
|
||||
if not self._process_shift_days(current_date):
|
||||
return
|
||||
for employee in all_employees:
|
||||
domain = [
|
||||
('shift_name', '=', '行政班次'),
|
||||
('employee_id', '=', employee.id),
|
||||
('current_data', '>=', month_start),
|
||||
('current_data', '<=', month_end),
|
||||
]
|
||||
is_no_card = 0
|
||||
is_early_card = 0
|
||||
is_late_card = 0
|
||||
is_abnormal = 0
|
||||
absenteeism_card = 0
|
||||
attend_records = self.env['hr.attendance'].search(domain)
|
||||
has_abnormal = False
|
||||
for record in attend_records:
|
||||
if record.is_no_card or record.is_early_card or record.is_late_card or record.is_abnormal or record.absenteeism_card:
|
||||
has_abnormal = True
|
||||
if record.is_no_card:
|
||||
is_no_card += 1
|
||||
if record.is_early_card:
|
||||
is_early_card += 1
|
||||
if record.is_late_card:
|
||||
is_late_card += 1
|
||||
if record.is_abnormal:
|
||||
is_abnormal += 1
|
||||
if record.absenteeism_card:
|
||||
absenteeism_card += 1
|
||||
if has_abnormal:
|
||||
url = f"https://oa.thtzjt.com/webh5#/clock_in_staticstis?user_id={employee.user_id.id}"
|
||||
self.sudo().env["wecom.apps"].sync_send_message_textcard(
|
||||
category='default',
|
||||
user_id=employee.wecom_userid,
|
||||
title="打卡异常提醒",
|
||||
description="本月迟到: {}\n本月缺卡: {}\n本月早退: {}\n本月异常:{}\n 本月旷工: {}\n"
|
||||
.format(is_late_card, is_no_card, is_early_card, is_abnormal, absenteeism_card),
|
||||
url=url,
|
||||
btntxt="详细信息"
|
||||
)
|
||||
today = date.today()
|
||||
current_year = today.year
|
||||
current_month = today.month
|
||||
first_day = date(current_year, current_month, 1)
|
||||
next_month = current_month + 1 if current_month < 12 else 1
|
||||
next_year = current_year if current_month < 12 else current_year + 1
|
||||
last_day = date(next_year, next_month, 1) - timedelta(days=1)
|
||||
|
||||
# 搜索本月的考勤记录
|
||||
attendance_records = self.env['hr.attendance'].search([
|
||||
('current_data', '>=', first_day),
|
||||
('current_data', '<=', last_day),
|
||||
('shift_name', '!=', '休息')
|
||||
])
|
||||
# 按员工分组,整理异常记录(结构:{员工ID: [异常文案列表, 员工对象]})
|
||||
employee_abnormal = {}
|
||||
for rec in attendance_records:
|
||||
emp = rec.employee_id
|
||||
emp_id = emp.id
|
||||
if emp_id not in employee_abnormal:
|
||||
employee_abnormal[emp_id] = {'abnormal_list': [], 'employee': emp}
|
||||
|
||||
# 提取基础信息:日期(月-日)、班次
|
||||
att_date = rec.current_data
|
||||
date_str = att_date.strftime('%m-%d')
|
||||
shift_name = rec.shift_name
|
||||
|
||||
# 判断异常类型(优先级:缺卡 > 迟到/早退)
|
||||
abnormal_desc = ""
|
||||
# 判断缺卡类型
|
||||
if not rec.check_in and not rec.check_out:
|
||||
abnormal_desc = "缺上班卡、缺下班卡"
|
||||
elif not rec.check_in:
|
||||
abnormal_desc = "缺上班卡"
|
||||
elif not rec.check_out:
|
||||
abnormal_desc = "缺下班卡"
|
||||
# 无缺卡时,判断迟到/早退
|
||||
else:
|
||||
abnormal_list = []
|
||||
if rec.is_late_card:
|
||||
abnormal_list.append("迟到")
|
||||
if rec.is_early_card:
|
||||
abnormal_list.append("早退")
|
||||
if abnormal_list:
|
||||
abnormal_desc = '、'.join(abnormal_list)
|
||||
|
||||
if abnormal_desc:
|
||||
single_abnormal = f"{date_str} {shift_name} {abnormal_desc}"
|
||||
employee_abnormal[emp_id]['abnormal_list'].append(single_abnormal)
|
||||
|
||||
for emp_id, data in employee_abnormal.items():
|
||||
emp = data['employee']
|
||||
abnormal_list = data['abnormal_list']
|
||||
if not abnormal_list:
|
||||
continue
|
||||
abnormal_str = '、'.join(abnormal_list)
|
||||
reminder_msg = f"{abnormal_str},请尽快处理。"
|
||||
menu_id = self.env['ir.ui.menu'].search([('name', '=', '我的考勤')])
|
||||
target_url = f'https://oa.thtzjt.com/web=#action=2465&model=hr.attendance&view_type=list&cids=2-1-3-4&menu_id={menu_id}'
|
||||
url = self.sudo().env["wecom.apps"].generate_oauth_login_url(target_url, emp.user_id.id)
|
||||
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='notice',
|
||||
user_id=emp.wecom_userid,
|
||||
title='【考勤异常提醒】',
|
||||
description=reminder_msg,
|
||||
url=url, btntxt="查看详情")
|
||||
|
||||
def missing_card_judgment(self):
|
||||
today = fields.Date.today()
|
||||
|
||||
@@ -934,6 +934,7 @@ class VacationOverline(models.Model):
|
||||
vacation_id = fields.Many2one('yuthon.vacation.reports', string='关联假期额度记录')
|
||||
employee_id = fields.Many2one('hr.employee', string='员工', compute='_compute_employee_id', store=True)
|
||||
department_id = fields.Many2one('hr.department', related='employee_id.department_id', string="部门")
|
||||
company_id = fields.Many2one('res.company', related='employee_id.company_id', string="公司")
|
||||
workflow_record_id = fields.Many2one('soong.workflow.record', string='流程')
|
||||
update_type= fields.Selection([('add', '增加'), ('reduce', '减少')], string='更新类型')
|
||||
workday = fields.Float(string='工作日')
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record model="ir.rule" id="vacation_over_line_detail">
|
||||
<field name="name">加班单明细行多公司</field>
|
||||
<field name="model_id" ref="model_vacation_over_line"/>
|
||||
<field name="domain_force">[('company_id', 'in', company_ids)]</field>
|
||||
</record>
|
||||
<record model="ir.rule" id="hr_attendance_month_detail">
|
||||
<field name="name">考勤确认单多公司</field>
|
||||
<field name="model_id" ref="model_hr_attendance_month_detail"/>
|
||||
|
||||
Reference in New Issue
Block a user