diff --git a/yuthon_hr_employee/__manifest__.py b/yuthon_hr_employee/__manifest__.py
index fff2de219..fd3ff90fe 100644
--- a/yuthon_hr_employee/__manifest__.py
+++ b/yuthon_hr_employee/__manifest__.py
@@ -30,6 +30,7 @@
'views/inherit_hr_applicant_views.xml',
'views/publish_applicant_setting_views.xml',
'views/inherit_res_groups_views.xml',
+ 'views/inherit_hr_employee_fix_calendar.xml',
'views/yuthon_medical_rule_views.xml',
'views/yuthon_medical_manage_views.xml',
'views/yuthon_job_postings_views.xml',
diff --git a/yuthon_hr_employee/models/yuthon_hr_employee.py b/yuthon_hr_employee/models/yuthon_hr_employee.py
index c02235f39..542b7b172 100644
--- a/yuthon_hr_employee/models/yuthon_hr_employee.py
+++ b/yuthon_hr_employee/models/yuthon_hr_employee.py
@@ -823,6 +823,64 @@ class YuthonHrEmployee(models.Model):
else:
num.number = ''
+ def action_batch_fix_resource_calendar(self):
+ """根据所属公司批量修复员工工作时间"""
+ company_calendar_map = {
+ '天河物管': '行政考勤-物管',
+ '集团本部': '行政考勤-本部',
+ '天河粮储': '行政考勤-粮储',
+ }
+ updated_count = 0
+ skipped_count = 0
+ failed_employees = []
+
+ # 预加载所有需要的 resource.calendar
+ calendar_names = list(company_calendar_map.values())
+ calendars = self.env['resource.calendar'].search([('name', 'in', calendar_names)])
+ calendar_map = {cal.name: cal for cal in calendars}
+
+ for employee in self:
+ company_name = employee.company_id.name if employee.company_id else False
+ if not company_name or company_name not in company_calendar_map:
+ skipped_count += 1
+ continue
+
+ calendar_name = company_calendar_map[company_name]
+ calendar = calendar_map.get(calendar_name)
+
+ if not calendar:
+ skipped_count += 1
+ continue
+
+ if not employee.contract_id:
+ skipped_count += 1
+ continue
+
+ try:
+ employee.contract_id.write({'resource_calendar_id': calendar.id})
+ updated_count += 1
+ except Exception as e:
+ failed_employees.append('%s(%s)' % (employee.name, employee.id))
+ continue
+
+ parts = ['成功更新 %d 条记录,跳过 %d 条。' % (updated_count, skipped_count)]
+ if failed_employees:
+ parts.append('失败 %d 条:%s' % (len(failed_employees), ', '.join(failed_employees[:5])))
+ if len(failed_employees) > 5:
+ parts.append('...等共 %d 条' % len(failed_employees))
+ message = '\n'.join(parts)
+
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'display_notification',
+ 'params': {
+ 'title': '批量修复工作时间完成',
+ 'message': message,
+ 'type': 'success',
+ 'sticky': False,
+ }
+ }
+
def action_hr_employee(self):
return {
"type": "ir.actions.act_window",
diff --git a/yuthon_hr_employee/views/inherit_hr_employee_fix_calendar.xml b/yuthon_hr_employee/views/inherit_hr_employee_fix_calendar.xml
new file mode 100644
index 000000000..518f28233
--- /dev/null
+++ b/yuthon_hr_employee/views/inherit_hr_employee_fix_calendar.xml
@@ -0,0 +1,17 @@
+
+
+
+ hr.employee.tree.fix.calendar
+ hr.employee
+
+
+
+
+
+
+
+
diff --git a/yuthon_notice/models/yuthon_confirm_users.py b/yuthon_notice/models/yuthon_confirm_users.py
index aa2484076..d6ccbfbfe 100644
--- a/yuthon_notice/models/yuthon_confirm_users.py
+++ b/yuthon_notice/models/yuthon_confirm_users.py
@@ -23,6 +23,8 @@ class YuthonConfirmUsers(models.Model):
employee_number = fields.Char(related='employee_id.number', string='序号', store=True)
def withdrawn(self):
+ if self.state == 'to_sent':
+ raise UserError('该通知还未发送,无法撤回')
if self.msg_id:
self.sudo().env["wecom.apps"].back_message(self.msg_id, category='notice')
self.state = 'to_sent'
diff --git a/yuthon_notice/views/yuthon_confirm_users_views.xml b/yuthon_notice/views/yuthon_confirm_users_views.xml
index 49fffc88e..9799c36f7 100644
--- a/yuthon_notice/views/yuthon_confirm_users_views.xml
+++ b/yuthon_notice/views/yuthon_confirm_users_views.xml
@@ -20,7 +20,7 @@
-
+