Files
gzth/yuthon_will_task/models/yuthon_will_task.py
T
2026-04-13 21:54:43 +08:00

346 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from odoo import api, fields, models, modules
import datetime
from datetime import datetime, timedelta, time
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class YuthonWillTask(models.Model):
_name = 'yuthon.will.task'
_description = '日程'
_rec_name = 'name'
time_list = [
('0', '0:00'), ('0.25', '0:15'), ('0.5', '0:30'), ('0.75', '0:45'),
('1', '01:00'), ('1.25', '01:15'), ('1.5', '01:30'), ('1.75', '01:45'),
('2', '02:00'), ('2.25', '02:15'), ('2.5', '02:30'), ('2.75', '02:45'),
('3', '03:00'), ('3.25', '03:15'), ('3.5', '03:30'), ('3.75', '03:45'),
('4', '04:00'), ('4.25', '04:15'), ('4.5', '04:30'), ('4.75', '04:45'),
('5', '05:00'), ('5.25', '05:15'), ('5.5', '05:30'), ('5.75', '05:45'),
('6', '06:00'), ('6.25', '06:15'), ('6.5', '06:30'), ('6.75', '06:45'),
('7', '07:00'), ('7.25', '07:15'), ('7.5', '07:30'), ('7.75', '07:45'),
('8', '08:00'), ('8.25', '08:15'), ('8.5', '08:30'), ('8.75', '08:45'),
('9', '09:00'), ('9.25', '09:15'), ('9.5', '09:30'), ('9.75', '09:45'),
('10', '10:00'), ('10.25', '10:15'), ('10.5', '10:30'), ('10.75', '10:45'),
('11', '11:00'), ('11.25', '11:15'), ('11.5', '11:30'), ('11.75', '11:45'),
('12', '12:00'), ('12.25', '12:15'), ('12.5', '12:30'), ('12.75', '12:45'),
('13', '13:00'), ('13.25', '13:15'), ('13.5', '13:30'), ('13.75', '13:45'),
('14', '14:00'), ('14.25', '14:15'), ('14.5', '14:30'), ('14.75', '14:45'),
('15', '15:00'), ('15.25', '15:15'), ('15.5', '15:30'), ('15.75', '15:45'),
('16', '16:00'), ('16.25', '16:15'), ('16.5', '16:30'), ('16.75', '16:45'),
('17', '17:00'), ('17.25', '17:15'), ('17.5', '17:30'), ('17.75', '17:45'),
('18', '18:00'), ('18.25', '18:15'), ('18.5', '18:30'), ('18.75', '18:45'),
('19', '19:00'), ('19.25', '19:15'), ('19.5', '19:30'), ('19.75', '19:45'),
('20', '20:00'), ('20.25', '20:15'), ('20.5', '20:30'), ('20.75', '20:45'),
('21', '21:00'), ('21.25', '21:15'), ('21.5', '21:30'), ('21.75', '21:45'),
('22', '22:00'), ('22.25', '22:15'), ('22.5', '22:30'), ('22.75', '22:45'),
('23', '23:00'), ('23.25', '23:15'), ('23.5', '23:30'), ('23.75', '23:45')]
def _default_request_hour_from(self):
"""开始时间默认当前小时(处理UTC+8时区)"""
now = fields.datetime.now() + timedelta(hours=8)
hour = now.hour
return str(hour)
def _default_request_hour_to(self):
"""结束时间默认当前小时+1(23+1=0,处理UTC+8时区)"""
now = fields.datetime.now() + timedelta(hours=8)
hour = (now.hour + 1) % 24
return str(hour)
request_hour_from = fields.Selection(time_list, string='开始时间')
request_hour_to = fields.Selection(time_list, string='结束时间')
priority = fields.Selection([('important', '重要不紧急'), ('urgent', '紧急不重要'), ('very_urgent', '重要且紧急')], string='优先级')
code = fields.Char(string="任务编号", default=lambda self: self.env['ir.sequence'].next_by_code('task_code'))
user_id = fields.Many2one('res.users', string="创建人", default=lambda self: self.env.user)
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company)
name = fields.Text(string='任务内容')
remarks = fields.Text(string='备注')
creation_time = fields.Date(string='创建时间', default=fields.Date.today())
employee_ids = fields.Many2many('hr.employee', 'will_task_employee_rel', 'custom_id', 'employee_id',
string='人员', store=True, index=True)
employee_ids2 = fields.Many2many('hr.employee', 'will_task_employee_rel2', 'custom_id', 'employee_id',
string='司机', store=True, index=True)
user_role_ids = fields.Many2many('soong.user.role', string='角色', store=True, index=True)
task_time_ids = fields.Many2many('yuthon.task.time', string='提醒')
document_ids = fields.Many2many('ir.attachment', string="附件")
address = fields.Char(string='地点')
start_date = fields.Date(string='开始日期', default=fields.Date.today)
task_time = fields.Char(string='任务时间', compute='_compute_task_time', store=True)
is_this_company = fields.Boolean(string='本公司', default=True)
task_state = fields.Selection([('will', '待办'), ('done', '已办'), ('cancel', '取消')], default='will', string='状态', store=True)
users_ids = fields.Many2many('res.users', relation='yuthon_will_task_users_rel', column1='task_id', column2='user_id',
string='用户', store=True, index=True, default=lambda self: self.env.user)
self_users_ids = fields.Many2many('res.users',
relation='yuthon_will_task_current_users_rel',column1='task_id', column2='user_id', string="当前经办人", store=True, default=lambda self: [(6, 0, [self.env.user.id])]
)
employee_id = fields.Many2one('hr.employee', string="经办人", default=lambda self: self.env.user.employee_id)
task_week = fields.Char(string="周", readonly=True, compute='_compute_task_week')
msg_id = fields.Char(string="msg_id")
task_type = fields.Selection([
('task', '日程'),
('meet', '会议')
], string='类型', default='task')
room_booking_id = fields.Many2one('room.booking', string='会议室')
def back_wecom_msg(self):
self.env['wecom.apps'].back_message(category='task', msg_id=self.msg_id)
def open_record(self):
self.ensure_one()
if self.room_booking_id:
target_model = 'room.booking'
target_id = self.room_booking_id.id
view_id = self.env.ref('room.room_booking_view_form').id
else:
target_model = self._name
target_id = self.id
view_id = self.env.ref('yuthon_will_task.view_yuthon_will_task_form').id
return {
'type': 'ir.actions.act_window',
'name': f'{target_model} 详情',
'res_model': target_model,
'res_id': target_id,
'view_mode': 'form',
'view_type': 'form',
'view_id': view_id,
'target': 'current',
}
@api.depends('start_date')
def _compute_task_week(self):
weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
for record in self:
if record.start_date:
record.task_week = weekdays[record.start_date.weekday()]
def one_time(self):
will_ids = self.env["yuthon.will.task"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in will_ids:
record._compute_task_time()
@api.depends('start_date', 'task_week', 'request_hour_from', 'task_type', 'room_booking_id', 'room_booking_id.start_datetime', 'room_booking_id.stop_datetime')
def _compute_task_time(self):
for record in self:
date_str = ""
if record.start_date:
date_str = record.start_date.strftime("%Y/%m/%d")
hour_mapping = {
'0': '0:00', '0.25': '0:15', '0.5': '0:30', '0.75': '0:45',
'1': '01:00', '1.25': '01:15', '1.5': '01:30', '1.75': '01:45',
'2': '02:00', '2.25': '02:15', '2.5': '02:30', '2.75': '02:45',
'3': '03:00', '3.25': '03:15', '3.5': '03:30', '3.75': '03:45',
'4': '04:00', '4.25': '04:15', '4.5': '04:30', '4.75': '04:45',
'5': '05:00', '5.25': '05:15', '5.5': '05:30', '5.75': '05:45',
'6': '06:00', '6.25': '06:15', '6.5': '06:30', '6.75': '06:45',
'7': '07:00', '7.25': '07:15', '7.5': '07:30', '7.75': '07:45',
'8': '08:00', '8.25': '08:15', '8.5': '08:30', '8.75': '08:45',
'9': '09:00', '9.25': '09:15', '9.5': '09:30', '9.75': '09:45',
'10': '10:00', '10.25': '10:15', '10.5': '10:30', '10.75': '10:45',
'11': '11:00', '11.25': '11:15', '11.5': '11:30', '11.75': '11:45',
'12': '12:00', '12.25': '12:15', '12.5': '12:30', '12.75': '12:45',
'13': '13:00', '13.25': '13:15', '13.5': '13:30', '13.75': '13:45',
'14': '14:00', '14.25': '14:15', '14.5': '14:30', '14.75': '14:45',
'15': '15:00', '15.25': '15:15', '15.5': '15:30', '15.75': '15:45',
'16': '16:00', '16.25': '16:15', '16.5': '16:30', '16.75': '16:45',
'17': '17:00', '17.25': '17:15', '17.5': '17:30', '17.75': '17:45',
'18': '18:00', '18.25': '18:15', '18.5': '18:30', '18.75': '18:45',
'19': '19:00', '19.25': '19:15', '19.5': '19:30', '19.75': '19:45',
'20': '20:00', '20.25': '20:15', '20.5': '20:30', '20.75': '20:45',
'21': '21:00', '21.25': '21:15', '21.5': '21:30', '21.75': '21:45',
'22': '22:00', '22.25': '22:15', '22.5': '22:30', '22.75': '22:45',
'23': '23:00', '23.25': '23:15', '23.5': '23:30', '23.75': '23:45'
}
from_time = hour_mapping.get(record.request_hour_from, "")
if date_str and from_time:
# 会议类型:显示完整的开始和结束日期时间
if record.task_type == 'meet' and record.room_booking_id and record.room_booking_id.start_datetime and record.room_booking_id.stop_datetime:
# 转换为本地时间(UTC+8)
start_local = record.room_booking_id.start_datetime + timedelta(hours=8)
stop_local = record.room_booking_id.stop_datetime + timedelta(hours=8)
# 格式化为 "YYYY-M-D HH∶MM" 格式
start_str = start_local.strftime("%Y-%m-%d %H∶%M")
stop_str = stop_local.strftime("%Y-%m-%d %H∶%M")
record.task_time = f"{start_str} 至 {stop_str}"
else:
base_time = f"{date_str} {record.task_week} {from_time}"
record.task_time = base_time
else:
record.task_time = ""
@api.onchange('employee_ids', 'user_id')
def _onchange_employee_ids(self):
user_ids = []
if self.user_id:
user_ids.append(self.user_id.id)
for employee in self.employee_ids:
if employee.user_id:
user_ids.append(employee.user_id.id)
for employee2 in self.employee_ids2:
if employee2.user_id:
user_ids.append(employee2.user_id.id)
roles = self.employee_ids.mapped('user_role_id')
self.user_role_ids = roles
self.users_ids = [(6, 0, user_ids)]
def read_number(self):
return self.search_count([('task_state', '=', 'will'), ('users_ids', 'in', self.env.user.id)])
def _compute_duration(self, task_time):
if task_time.task_unit == 'min':
return timedelta(minutes=task_time.number)
elif task_time.task_unit == 'hour':
return timedelta(hours=task_time.number)
elif task_time.task_unit == 'day':
return timedelta(days=task_time.number)
else:
return timedelta.max
def add_comment(self):
"""日程定时任务提醒"""
_logger.info('-----------日程任务验证--------')
now = fields.datetime.now() + timedelta(hours=8)
dates_task_ids = self.env['yuthon.dates.task'].search([('task_state', '=', 'to_do'), ('reminder_time', '<', fields.datetime.now() + timedelta(days=1))])
for task in dates_task_ids:
hour1 = (task.reminder_time + timedelta(hours=8)).hour
minute1 = (task.reminder_time + timedelta(hours=8)).minute
_logger.info(f'-任务时间{hour1}:{minute1}任务分钟{now.hour}:{now.minute}')
_logger.info(f'-状态{minute1 == now.minute and hour1 == now.hour}')
if minute1 == now.minute and hour1 == now.hour and task.reminder_time.day == fields.date.today().day:
task.write({'task_state': 'done'})
will_id = task.yuthon_will_task_id
will_id.task_state = 'done'
for employee_id in task.employee_ids:
url = f'https://phone.thtzjt.com/phone/Schedule/{task.yuthon_will_task_id.id}/{employee_id.user_id.id}'
request_hour_from = dict(task.yuthon_will_task_id._fields['request_hour_from'].selection).get(task.yuthon_will_task_id.request_hour_from, '') + '\n'
data_date = '开始时间:' + str(task.yuthon_will_task_id.start_date) + '--' + str(request_hour_from) + '\n'
data_name = "事项名称: " + task.yuthon_will_task_id.name + '\n'
data_user_ids = '参与人: ' + ', '.join(will_id.employee_ids.mapped('name')) + '\n'
data_employee_id = ('司机:' + ', '.join(will_id.employee_ids2.mapped('name')) + '\n') if will_id.employee_ids2 else ''
data_nota = ('备注:' + will_id.remarks) if will_id.remarks else ('') + '\n'
data = data_date + data_name + data_user_ids + data_employee_id + data_nota
# url = f'https://phone.thtzjt.com/phone/Schedule/{will_id.id}/{employee_id.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task', user_id=employee_id.wecom_userid, title="日程事项提醒", description=data,
url=url, btntxt="详细信息")
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task', user_id="18562027762", title="日程事项提醒", description=data,
url=url, btntxt="详细信息")
def button_add_comment(self):
for employee_id in self.employee_ids + self.employee_ids2:
data_date = '开始时间:' + str(self.start_date) + str(self.request_hour_from) + '\n'
data_name = "事项名称: " + self.name + '\n'
data_user_ids = '参与人: ' + ', '.join(self.employee_ids.mapped('name')) + '\n'
data_employee_id = ('司机:' + ', '.join(self.employee_ids2.mapped('name')) + '\n') if self.employee_ids2 else ''
data_nota = ('备注:' + self.remarks + '\n') if self.remarks else ('') + '\n'
data = data_date + data_name + data_user_ids + data_nota + data_employee_id
url = f'https://phone.thtzjt.com/phone/Schedule/{self.id}/{employee_id.user_id.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task', user_id=employee_id.wecom_userid,
title="日程事项提醒", description=data, url=url, btntxt="详细信息")
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task', user_id="18562027762",
title="日程事项提醒", description=data, url=url, btntxt="详细信息")
# if test_msg_id:
# self.write({'msg_id': test_msg_id[-1]['msgid']})
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': '已发送提醒消息',
'sticky': False,
}
}
def button_add_comment_cancel(self):
self.write({'task_state': 'cancel'})
employee_list = [i.id for i in self.employee_ids] + [i.id for i in self.employee_ids2]
for employee_id in self.env['hr.employee'].search([('id', 'in', employee_list)]):
if not employee_id.wecom_userid:
raise UserError("请同步{}的企业微信".format(employee_id.name))
url = f'https://oa.thtzjt.com/webh5#/journey?id={self.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='task', user_id=employee_id.wecom_userid,
title="日程事项提醒", description="事项名称: " + self.name + '\t' + '该事项已取消',
url=url, btntxt="详细信息")
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'success',
'message': '已发送取消提醒消息',
'sticky': False,
}
}
@api.model
def create(self, vals):
"""创建日程时,同步创建提醒任务"""
will_task = super(YuthonWillTask, self).create(vals)
will_task._sync_dates_task()
return will_task
def write(self, vals):
"""修改日程时,先删除旧提醒任务,再创建新的"""
res = super(YuthonWillTask, self).write(vals)
key_fields = ['start_date', 'request_hour_from', 'task_time_ids', 'employee_ids', 'employee_ids2', 'task_type', 'room_booking_id']
if any(field in vals for field in key_fields):
self._sync_dates_task()
return res
def _sync_dates_task(self):
reminder_employees = self.employee_ids | self.employee_ids2 | self.employee_id
if not reminder_employees:
return
old_tasks = self.env['yuthon.dates.task'].search([('yuthon_will_task_id', '=', self.id), ('task_state', '=', 'to_do')])
if old_tasks:
old_tasks.unlink()
start_hour = float(self.request_hour_from)
hours = int(start_hour)
minutes = int((start_hour - hours) * 60)
task_start_datetime = datetime.combine(self.start_date,time(hour=hours, minute=minutes))
for task_time in self.task_time_ids:
reminder_time_str = task_time.name
reminder_hours = 0.0
import re
match = re.match(r'(\d+)(分钟|小时|天)', reminder_time_str.strip())
num = int(match.group(1))
unit = match.group(2)
if unit == '小时':
reminder_hours = num
elif unit == '分钟':
reminder_hours = num / 60.0
elif unit == '天':
reminder_hours = num * 24.0
reminder_datetime = task_start_datetime - timedelta(hours=reminder_hours)
now = fields.datetime.now() + timedelta(hours=8)
if now > reminder_datetime:
continue
existing_dates_task = self.env['yuthon.dates.task'].search([
('yuthon_will_task_id', '=', self.id),
('reminder_time', '=', reminder_datetime)
])
task_vals = {
'reminder_time': reminder_datetime - timedelta(hours=8),
'employee_ids': [(6, 0, reminder_employees.ids)],
'task_state': 'to_do',
}
if existing_dates_task:
existing_dates_task.write(task_vals)
else:
task_vals['yuthon_will_task_id'] = self.id
self.env['yuthon.dates.task'].create(task_vals)
def schedule_reminders(self):
return {
'type': 'ir.actions.act_window',
'name': '提醒任务详情',
'view_mode': 'tree',
'res_model': 'yuthon.dates.task',
'domain': [('yuthon_will_task_id', '=', self.id)],
}