346 lines
19 KiB
Python
346 lines
19 KiB
Python
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)],
|
||
}
|
||
|