diff --git a/yuthon_catering/__manifest__.py b/yuthon_catering/__manifest__.py
index c7c33564c..8cbfb5db6 100644
--- a/yuthon_catering/__manifest__.py
+++ b/yuthon_catering/__manifest__.py
@@ -16,6 +16,7 @@
'views/yuthon_catering_setting_views.xml',
'views/yuthon_catering_templates.xml',
'wizard/catering_reinstated_wizard_views.xml',
+ 'data/yuthon_catering_cron.xml',
],
'assets': {
'web.assets_backend': [
diff --git a/yuthon_catering/data/yuthon_catering_cron.xml b/yuthon_catering/data/yuthon_catering_cron.xml
new file mode 100644
index 000000000..0c769482d
--- /dev/null
+++ b/yuthon_catering/data/yuthon_catering_cron.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ 定时任务:餐饮登记提醒
+
+ code
+ model.cron_send_message()
+
+
+ 1
+ days
+
+ -1
+
+
+
+
\ No newline at end of file
diff --git a/yuthon_catering/models/yuthon_catering.py b/yuthon_catering/models/yuthon_catering.py
index 328175718..fee3f0bc8 100644
--- a/yuthon_catering/models/yuthon_catering.py
+++ b/yuthon_catering/models/yuthon_catering.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+
from odoo import api, fields, models
from datetime import datetime, timedelta
@@ -23,23 +23,32 @@ class YuthonCatering(models.Model):
conf_records = self.env['yuthon.catering.conf'].search([])
employee_ids = conf_records.mapped('employee_ids')
+ # 获取今天的日期
today = fields.Date.today()
+ # 创建未来7天的日期列表
date_list = [today + timedelta(days=i) for i in range(7)]
+ # 初始化待创建记录列表
create_vals = []
+ # 遍历每个员工
for employee in employee_ids:
+ # 遍历每个日期
for target_date in date_list:
+ # 检查目标日期是否为工作日,如果不是则跳过
if not self._process_shift_days(target_date):
continue
+ # 检查是否已存在该员工在该日期的记录
existing = self.search([
('employee_id', '=', employee.id),
('date', '=', target_date)
], limit=1)
+ # 查找当天的菜单设置
menu_record = self.env['yuthon.menu.setting'].search([
('menu_date', '=', target_date)
], limit=1)
+ # 如果不存在记录,则准备创建新记录的数据
if not existing:
create_vals.append({
'menu_record': menu_record.id if menu_record else False,
@@ -47,52 +56,175 @@ class YuthonCatering(models.Model):
'employee_id': employee.id,
})
+ # 如果有待创建的记录,则批量创建
if create_vals:
self.create(create_vals)
+ # 定义私有方法,用于判断给定日期是否为工作日
def _process_shift_days(self, current_data):
"""
判断是否是工作日 调休日 双休
"""
+ # 获取当前年份
current_year = (fields.Date.today() + timedelta(hours=8)).year
+ # 设置查询开始时间(当年1月1日)
query_start = datetime(current_year, 1, 1, 0, 0, 0) - timedelta(hours=8)
+ # 设置查询结束时间(当年12月31日)
query_end = datetime(current_year, 12, 31, 23, 59, 59) - timedelta(hours=8)
+ # 查询"行政考勤工作日"日历的假期设置
calendar_leaves = self.env['resource.calendar.leaves'].sudo().search([
("calendar_id.name", "=", "行政考勤工作日"),
("date_from", ">=", query_start),
("date_from", "<=", query_end)
])
+ # 初始化假期列表
holidays_list = []
+ # 初始化调休列表
shift_days_list = []
# 提取节假日和调休日
for leave in calendar_leaves:
+ # 如果有假期设置,添加到假期列表
if leave.holidays:
holidays_list.extend(leave.holidays.split(','))
+ # 如果有调休日设置,添加到假期列表
if leave.alternate_rest_day:
holidays_list.extend(leave.alternate_rest_day.split(','))
+ # 如果有换班日设置,添加到调休列表
if leave.shift_replacement_day:
shift_days_list.extend(leave.shift_replacement_day.split(','))
+ # 移除日期字符串中的前导零
holidays_list = [self.remove_leading_zero(date) for date in holidays_list]
+ # 移除日期字符串中的前导零
shift_days_list = [self.remove_leading_zero(date) for date in shift_days_list]
+ # 格式化输入的日期为"月日"格式
result = f"{current_data.month}月{current_data.day}日"
+ # 如果日期在调休列表中,返回True(是工作日)
if result in shift_days_list:
return True
+ # 如果日期在假期列表中或为周末,返回False(不是工作日)
elif (result in holidays_list) or (current_data.weekday() in [5, 6]):
return False
+ # 其他情况返回True(是工作日)
else:
return True
+ # 移除日期字符串中的前导零
def remove_leading_zero(self, date_str):
+ # 分割月份和日期部分
month, day = date_str.split('月')
+ # 移除月份前面的零
month = month.lstrip('0')
+ # 移除日期末尾的"日"字符
day = day.rstrip('日')
+ # 移除日期前面的零
day = day.lstrip('0')
+ # 返回处理后的日期字符串
return f'{month}月{day}日'
+ # 定义定时任务方法,每天九点半发送消息提醒
def cron_send_message(self):
- # 登记页面
- url = f'/catering/registration/'
- # 统计页面
- url = f'/catering/statistics/'
+ """
+ 定时任务:每天上午九点半发送消息提醒
+ """
+ # 获取当前时间(本地时间)
+ current_utc_time = fields.Datetime.now()
+ local_time = current_utc_time + timedelta(hours=8)
+ h = local_time.hour
+ m = local_time.minute
+
+ # 检查是否是上午9:30左右
+ if not (h == 9 and 25 <= m <= 35): # 9:25-9:35之间
+ return
+ # 判断今天是否为工作日
+ today = fields.Date.today()
+ if not self._process_shift_days(today):
+ # 如果不是工作日,则不发送提醒
+ return
+ # 发送通用提醒消息
+ employees = self.env['hr.employee'].search([('user_id', '!=', False)])
+
+ for employee in employees:
+ if employee.user_id: # 确保员工有关联的用户
+ # 构造跳转URL,格式为 f'https://phone.thtzjt.com/phone/Restaurant/(users_id)
+ users_id = employee.user_id.id
+ target_url = f'https://phone.thtzjt.com/phone/Restaurant/{users_id}'
+
+ # 发送消息,使用指定的格式
+ if hasattr(self.env["wecom.apps"], 'sync_send_message_textcard'):
+ description = f"您有1条待办未处理,请及时登OA系统处理,谢谢配合"
+ title = "餐饮登记提醒"
+
+ self.env["wecom.apps"].sync_send_message_textcard(
+ category='oa',
+ user_id=employee.wecom_userid if hasattr(employee, 'wecom_userid') else employee.user_id.login,
+ title=title,
+ description=description,
+ url=target_url,
+ btntxt="查看详情"
+ )
+
+ # 定义批量提醒方法
+ def batch_remind_catering(self):
+ """
+ 批量提醒功能:手动触发提醒选定的记录
+ """
+ # 从环境上下文中获取选中的记录ID
+ active_ids = self.env.context.get('active_ids')
+ # 浏览选中的记录,如果没有则使用当前记录
+ selected_records = self.browse(active_ids) if active_ids else self
+ # 如果没有选中任何记录,抛出异常
+ if not selected_records:
+ raise ValueError("没有选择任何记录进行提醒")
+ # 按员工分组存储待通知的记录
+ employees_to_notify = {}
+ # 遍历选中的记录
+ for record in selected_records:
+ # 只处理员工存在且状态为未确认的记录
+ if record.employee_id and record.state == 'unconfirmed':
+ # 如果员工ID不在字典中,则初始化
+ if record.employee_id.id not in employees_to_notify:
+ employees_to_notify[record.employee_id.id] = {
+ 'employee': record.employee_id,
+ 'records': []
+ }
+ # 将记录添加到对应员工的列表中
+ employees_to_notify[record.employee_id.id]['records'].append(record)
+ # 发送提醒给每个员工
+ notified_count = 0
+ # 遍历员工字典
+ for emp_id, data in employees_to_notify.items():
+ employee = data['employee']
+ records = data['records']
+ # 构造跳转URL
+ users_id = employee.user_id.id if employee.user_id else ''
+ target_url = f'https://phone.thtzjt.com/phone/Restaurant/{users_id}'
+ # 发送消息,使用指定的格式
+ if hasattr(self.env["wecom.apps"], 'sync_send_message_textcard'):
+ # 构造消息内容
+ description = f"您有{len(data['records'])}条待办未处理,请及时登OA系统处理,谢谢配合"
+ # 设置消息标题
+ title = "餐饮登记提醒"
+ # 调用企业微信API发送消息卡片
+ self.env["wecom.apps"].sync_send_message_textcard(
+ category='oa', # 消息类别为OA
+ # 获取员工的企业微信ID或登录名
+ user_id=employee.wecom_userid if hasattr(employee, 'wecom_userid') else employee.user_id.login if employee.user_id else '',
+ title=title, # 消息标题
+ description=description, # 消息内容
+ url=target_url, # 点击后跳转的URL
+ btntxt="查看详情" # 按钮文字
+ )
+ # 增加已通知计数
+ notified_count += 1
+ # 返回通知结果
+ return {
+ 'type': 'ir.actions.client', # 动作类型为客户端动作
+ 'tag': 'display_notification', # 标签为显示通知
+ 'params': {
+ 'title': '批量提醒', # 通知标题
+ 'message': f'已向 {notified_count} 名员工发送提醒消息', # 通知内容
+ 'sticky': False, # 不是粘性通知
+ }
+ }
diff --git a/yuthon_catering/views/yuthon_catering.xml b/yuthon_catering/views/yuthon_catering.xml
index 1cfe07b3a..00c9041d5 100644
--- a/yuthon_catering/views/yuthon_catering.xml
+++ b/yuthon_catering/views/yuthon_catering.xml
@@ -7,13 +7,16 @@
yuthon.catering
+
-
+
@@ -24,6 +27,7 @@
餐饮收集任务
yuthon.catering
tree,form
+ {'default_order': 'date desc'}