From 807143815b6d3d1b5974c1cd53a4bcb535a59417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?=
<9664676+pengyuthon@user.noreply.gitee.com>
Date: Tue, 2 Dec 2025 10:41:50 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../data/attendance_time_data.xml | 28 +++++
yuthon_hr_attendance/data/data_other.xml | 4 +-
yuthon_hr_attendance/models/hr_attendance.py | 61 +++++++----
.../models/yuthon_run_planning.py | 102 +++++++++++-------
.../views/yuthon_run_planning_views.xml | 6 +-
.../models/inherit_yuthon_property.py | 14 +++
.../views/inherit_yuthon_property_views.xml | 1 +
7 files changed, 154 insertions(+), 62 deletions(-)
diff --git a/yuthon_hr_attendance/data/attendance_time_data.xml b/yuthon_hr_attendance/data/attendance_time_data.xml
index bdaf2e407..fff00f95d 100644
--- a/yuthon_hr_attendance/data/attendance_time_data.xml
+++ b/yuthon_hr_attendance/data/attendance_time_data.xml
@@ -298,6 +298,34 @@
-1
+
+
+ 定时任务:行政班次上班打卡提醒
+
+ code
+ model.executive_day_remind_in()
+
+
+ 1
+ days
+
+ -1
+
+
+
+
+ 定时任务:行政班次下班打卡提醒
+
+ code
+ model.executive_day_remind_out()
+
+
+ 1
+ days
+
+ -1
+
+
diff --git a/yuthon_hr_attendance/data/data_other.xml b/yuthon_hr_attendance/data/data_other.xml
index 3f09ce2b6..9bd8db905 100644
--- a/yuthon_hr_attendance/data/data_other.xml
+++ b/yuthon_hr_attendance/data/data_other.xml
@@ -2,7 +2,7 @@
- 定时任务:计划行政上班提醒
+ 定时任务:保安部计划行政上班提醒
code
model.card_lc_shift_remind_on_administrative()
@@ -16,7 +16,7 @@
- 定时任务:计划行政下班提醒
+ 定时任务:保安部计划行政下班提醒
code
model.card_lc_shift_remind_out_administrative()
diff --git a/yuthon_hr_attendance/models/hr_attendance.py b/yuthon_hr_attendance/models/hr_attendance.py
index 6d1827675..1a42c341f 100644
--- a/yuthon_hr_attendance/models/hr_attendance.py
+++ b/yuthon_hr_attendance/models/hr_attendance.py
@@ -791,7 +791,7 @@ class HrAttendance(models.Model):
else:
record.week = False
- def _common_card_remind(self, dept_name=None, planning_name=None, is_check_in=True, method_name=None):
+ def _common_card_remind(self, dept_name=None, planning_name=None, is_check_in=True, method_name=None, is_executive=False):
"""通用打卡提醒函数"""
if not method_name:
return
@@ -803,24 +803,38 @@ class HrAttendance(models.Model):
end_window = next_call + timedelta(minutes=5)
if not (start_window <= fields.Datetime.now() + timedelta(hours=8) <= end_window):
return
- slot_start = datetime.combine(current_date, datetime.min.time())
- slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time())
- domain = [
- ('template_id.planning_name', '=', planning_name),
- ('start_datetime', '>=', slot_start),
- ('start_datetime', '<', slot_end),
- ('role_id.name', '=', dept_name),
- ]
- planning_slots = self.env['planning.slot'].search(domain)
- for slot in planning_slots:
- if is_check_in:
- is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
- if not is_card:
- self.card_in_comment(slot.employee_id, planning_name)
- else:
- is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
- if not is_card:
- self.card_out_comment(slot.employee_id, planning_name)
+ if is_executive:
+ domain = [('current_data', '=', current_date)]
+ attendances = self.env['hr.attendance'].search(domain)
+ attended_employee_ids = attendances.mapped('employee_id')
+ for employee in attended_employee_ids:
+ if is_check_in:
+ is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
+ if not is_card:
+ self.card_in_comment(employee, '行政班次')
+ else:
+ is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
+ if not is_card:
+ self.card_out_comment(employee, '行政班次')
+ else:
+ slot_start = datetime.combine(current_date, datetime.min.time())
+ slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time())
+ domain = [
+ ('template_id.planning_name', '=', planning_name),
+ ('start_datetime', '>=', slot_start),
+ ('start_datetime', '<', slot_end),
+ ('role_id.name', '=', dept_name),
+ ]
+ planning_slots = self.env['planning.slot'].search(domain)
+ for slot in planning_slots:
+ if is_check_in:
+ is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
+ if not is_card:
+ self.card_in_comment(slot.employee_id, planning_name)
+ else:
+ is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
+ if not is_card:
+ self.card_out_comment(slot.employee_id, planning_name)
# 保安部 - 早班
def ba_card_white_up(self):
@@ -939,6 +953,15 @@ class HrAttendance(models.Model):
self._common_card_remind(dept_name='保安部', planning_name='保安计划行政', is_check_in=False,
method_name='card_lc_shift_remind_out_administrative')
+ # 行政班次
+ def executive_day_remind_in(self):
+ self._common_card_remind(planning_name='行政班次', is_check_in=True,
+ method_name='executive_day_remind_in', is_executive=True)
+
+ def executive_day_remind_out(self):
+ self._common_card_remind(planning_name='行政班次', is_check_in=False,
+ method_name='executive_day_remind_out', is_executive=True)
+
def card_in_comment(self, employee_id, planning_name):
data = f"您的班次是{planning_name},还有5分钟上班,记得打卡"
url = '#小程序://天投云/XttsPpKg3MEpY7h'
diff --git a/yuthon_hr_attendance/models/yuthon_run_planning.py b/yuthon_hr_attendance/models/yuthon_run_planning.py
index 4b7cdc1c2..d37a4f2d7 100644
--- a/yuthon_hr_attendance/models/yuthon_run_planning.py
+++ b/yuthon_hr_attendance/models/yuthon_run_planning.py
@@ -17,7 +17,18 @@ class YuthonRunPlanning(models.Model):
department_id = fields.Many2one("hr.department", string="部门", required=True)
start_date = fields.Date(string='生效日期', default=fields.Datetime.today())
end_date = fields.Date(string='失效日期')
+ is_effect = fields.Boolean(string="是否生效", compute="_compute_is_effect")
+ @api.depends('start_date', 'end_date')
+ def _compute_is_effect(self):
+ today = fields.Date.today()
+ for record in self:
+ if not record.start_date:
+ record.is_effect = False
+ elif not record.end_date:
+ record.is_effect = record.start_date <= today
+ else:
+ record.is_effect = record.start_date <= today <= record.end_date
def action_planning_wizard_run(self):
return {
@@ -48,20 +59,25 @@ class YuthonRunPlanning(models.Model):
# 运行班
def run_confirm(self):
- selected_month = self.start_date.month
- year = datetime.now().year
- first_day_of_month = datetime(year, selected_month, 1)
+ latest_slot = self.env['planning.slot'].search([
+ ('department_id.name', '=', '运行班')
+ ], order='start_datetime desc', limit=1)
+ # 从最新排班中提取年/月
+ latest_datetime = latest_slot.start_datetime
+ latest_year = latest_datetime.year
+ latest_month = latest_datetime.month
+
+ # 计算下个月的年/月
+ target_month = latest_month + 1
+ target_year = latest_year
+ if target_month > 12:
+ target_month = 1
+ target_year += 1
+ first_day_of_month = datetime(target_year, target_month, 1)
# 计算结束日期(当月的最后一天)
- next_month = (selected_month % 12) + 1
- next_year = year + (1 if next_month == 1 else 0)
+ next_month = target_month % 12 + 1
+ next_year = target_year + (1 if next_month == 1 else 0)
last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1)
- existing_slots = self.env['planning.slot'].search([
- ('department_id.name', '=', '运行班'),
- ('start_datetime', '>=', first_day_of_month),
- ('start_datetime', '<=', last_day_of_month),
- ])
- if len(existing_slots) > 0:
- raise UserError(f"该月已经有排程,请选择其他时间。")
role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1)
start_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time)
end_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).end_time)
@@ -147,20 +163,25 @@ class YuthonRunPlanning(models.Model):
}
# 高压班
def high_confirm(self):
- selected_month = self.start_date.month
- year = datetime.now().year
- first_day_of_month = datetime(year, selected_month, 1)
- # 计算结束日期(下个月的第一天)
- next_month = (selected_month % 12) + 1
- next_year = year + (1 if next_month == 1 else 0) # 如果是12月,年份加1
- last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1)
- existing_slots = self.env['planning.slot'].search([
+ latest_slot = self.env['planning.slot'].search([
('department_id.name', '=', '高压班'),
- ('start_datetime', '>=', first_day_of_month),
- ('start_datetime', '<=', last_day_of_month),
- ])
- if len(existing_slots) > 0:
- raise UserError(f"该月已经有排程,请选择其他时间。")
+ ], order='start_datetime desc', limit=1)
+ # 从最新排班中提取年/月
+ latest_datetime = latest_slot.start_datetime
+ latest_year = latest_datetime.year
+ latest_month = latest_datetime.month
+
+ # 计算下个月的年/月
+ target_month = latest_month + 1
+ target_year = latest_year
+ if target_month > 12:
+ target_month = 1
+ target_year += 1
+ first_day_of_month = datetime(target_year, target_month, 1)
+ # 计算结束日期(当月的最后一天)
+ next_month = target_month % 12 + 1
+ next_year = target_year + (1 if next_month == 1 else 0)
+ last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1)
role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1)
start_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time)
end_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).end_time)
@@ -220,20 +241,25 @@ class YuthonRunPlanning(models.Model):
}
# 综合班
def integrated_confirm(self):
- selected_month = self.start_date.month
- year = datetime.now().year
- first_day_of_month = datetime(year, selected_month, 1)
- # 计算结束日期(下个月的第一天)
- next_month = (selected_month % 12) + 1
- next_year = year + (1 if next_month == 1 else 0) # 如果是12月,年份加1
- last_day_of_month = datetime(next_year, next_month, 1)- timedelta(days=1)
- existing_slots = self.env['planning.slot'].search([
+ latest_slot = self.env['planning.slot'].search([
('department_id.name', '=', '综合班'),
- ('start_datetime', '>=', first_day_of_month),
- ('start_datetime', '<=', last_day_of_month),
- ])
- if len(existing_slots) > 0:
- raise UserError(f"该月已经有排程,请选择其他时间。")
+ ], order='start_datetime desc', limit=1)
+ # 从最新排班中提取年/月
+ latest_datetime = latest_slot.start_datetime
+ latest_year = latest_datetime.year
+ latest_month = latest_datetime.month
+
+ # 计算下个月的年/月
+ target_month = latest_month + 1
+ target_year = latest_year
+ if target_month > 12:
+ target_month = 1
+ target_year += 1
+ first_day_of_month = datetime(target_year, target_month, 1)
+ # 计算结束日期(当月的最后一天)
+ next_month = target_month % 12 + 1
+ next_year = target_year + (1 if next_month == 1 else 0)
+ last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1)
role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1)
start_time = int(self.env['planning.slot.template'].search(
[('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time)
diff --git a/yuthon_hr_attendance/views/yuthon_run_planning_views.xml b/yuthon_hr_attendance/views/yuthon_run_planning_views.xml
index 4cc6368c0..87a636370 100644
--- a/yuthon_hr_attendance/views/yuthon_run_planning_views.xml
+++ b/yuthon_hr_attendance/views/yuthon_run_planning_views.xml
@@ -20,7 +20,7 @@