!9073 Merge branch 'dev' of <a href="https://gitee.com/jinan-pengyusen-data/gzth">https://gitee.com/jinan-pengyusen-data/gzth</a> into dev_wang
Merge pull request !9073 from 李鹏宇/dev_wang
This commit is contained in:
@@ -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': [
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record forcecreate="True" id="catering_reminder_cron" model="ir.cron">
|
||||
<field name="name">定时任务:餐饮登记提醒</field>
|
||||
<field name="model_id" ref="model_yuthon_catering"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.cron_send_message()</field>
|
||||
<field eval="True" 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 09:30:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -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/<int:employee_id>'
|
||||
# 统计页面
|
||||
url = f'/catering/statistics/<int:employee_id>'
|
||||
"""
|
||||
定时任务:每天上午九点半发送消息提醒
|
||||
"""
|
||||
# 获取当前时间(本地时间)
|
||||
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, # 不是粘性通知
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,16 @@
|
||||
<field name="model">yuthon.catering</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="餐饮" editable="top">
|
||||
<header>
|
||||
<button name="batch_remind_catering" string="批量提醒" type="object" class="btn btn-primary"/>
|
||||
</header>
|
||||
<field name="date"/>
|
||||
<field name="dept_id"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="breakfast"/>
|
||||
<field name="lunch"/>
|
||||
<field name="amount"/>
|
||||
<field name="menu_day_id"/>
|
||||
<field name="menu_day_id" column_invisible="True"/>
|
||||
<field name="note"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -24,6 +27,7 @@
|
||||
<field name="name">餐饮收集任务</field>
|
||||
<field name="res_model">yuthon.catering</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'default_order': 'date desc'}</field>
|
||||
</record>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user