diff --git a/yuthon_catering/__manifest__.py b/yuthon_catering/__manifest__.py
index 5015fd6f8..c7c3d3479 100644
--- a/yuthon_catering/__manifest__.py
+++ b/yuthon_catering/__manifest__.py
@@ -15,6 +15,7 @@
'views/yuthon_catering_setting_views.xml',
'views/yuthon_catering_templates.xml',
'wizard/catering_reinstated_wizard_views.xml',
+ 'wizard/catering_conf_change_wizard_views.xml',
'data/yuthon_catering_cron.xml',
'views/root_menu.xml',
],
diff --git a/yuthon_catering/models/yuthon_catering.py b/yuthon_catering/models/yuthon_catering.py
index 8ef17e7c6..a4860cdf2 100644
--- a/yuthon_catering/models/yuthon_catering.py
+++ b/yuthon_catering/models/yuthon_catering.py
@@ -103,10 +103,15 @@ class YuthonCatering(models.Model):
'lunch': True,
})
+ def _get_active_conf_employees(self):
+ """获取当前有效配置(无失效日期)的员工列表"""
+ conf = self.env['yuthon.catering.conf'].search([('expiry_date', '=', False)], limit=1)
+ return conf.employee_ids if conf else self.env['hr.employee']
+
def task_catering(self):
today = fields.Date.today()
tomorrow = today + timedelta(days=1)
- employee_ids = self.env['yuthon.catering.conf'].search([])[0].employee_ids
+ employee_ids = self._get_active_conf_employees()
if not self._process_shift_days(today):
return
tomorrow_menu = self.env['yuthon.menu.setting'].search([
@@ -130,8 +135,8 @@ class YuthonCatering(models.Model):
def task_conf(self):
tomorrow = fields.Date.today() + timedelta(days=1)
company_main = self.env["res.company"].search([("name", "=", "集团本部")], limit=1)
- catering_conf = self.env["yuthon.catering.conf"].search([("company_id", "=", company_main.id)])
- employee_ids = catering_conf.mapped('employee_ids')
+ catering_conf = self.env['yuthon.catering.conf'].search([('company_id', '=', company_main.id), ('expiry_date', '=', False)], limit=1)
+ employee_ids = catering_conf.employee_ids if catering_conf else self.env['hr.employee']
menu_setting = self.env["yuthon.menu.setting"].search([("menu_date", "=", tomorrow)], limit=1)
if not menu_setting:
return
@@ -185,8 +190,7 @@ class YuthonCatering(models.Model):
def catering_task(self):
- conf_records = self.env['yuthon.catering.conf'].search([])
- employee_ids = conf_records.mapped('employee_ids')
+ employee_ids = self._get_active_conf_employees()
# 获取今天的日期
today = fields.Date.today()
@@ -232,10 +236,9 @@ class YuthonCatering(models.Model):
menu_today = self.env['yuthon.menu.setting'].search([('menu_date', '=', today)], limit=1)
if not menu_today:
return
- conf_records = self.env['yuthon.catering.conf'].search([])
- if not conf_records:
+ employee_ids = self._get_active_conf_employees()
+ if not employee_ids:
return
- employee_ids = conf_records.mapped('employee_ids')
create_vals = []
for employee in employee_ids:
existing = self.search([
@@ -333,8 +336,7 @@ class YuthonCatering(models.Model):
# 如果不是工作日,则不发送提醒
return
# 发送通用提醒消息
- conf_records = self.env['yuthon.catering.conf'].search([])
- employees = conf_records.mapped('employee_ids')
+ employees = self._get_active_conf_employees()
for employee in employees:
if employee.user_id: # 确保员工有关联的用户
@@ -358,7 +360,7 @@ class YuthonCatering(models.Model):
# 一次性,生成3.1-3.3所有数据,状态为已确认
def test_1(self):
- employee_ids = self.env['yuthon.catering.conf'].search([])[0].employee_ids
+ employee_ids = self._get_active_conf_employees()
for emp in employee_ids:
self.env['yuthon.catering'].create({
'date': '2026-03-01',
@@ -394,10 +396,7 @@ class YuthonCatering(models.Model):
"""一次性:补3月4日缺失数据,已确认且早餐午餐全勾"""
from datetime import date as date_cls
target_date = date_cls(2026, 3, 4)
- conf_records = self.env['yuthon.catering.conf'].search([])
- if not conf_records:
- return
- employee_ids = conf_records.mapped('employee_ids')
+ employee_ids = self._get_active_conf_employees()
if not employee_ids:
return
create_vals = []
@@ -421,10 +420,7 @@ class YuthonCatering(models.Model):
"""表3月12日缺失员工的餐饮收集任务数据"""
from datetime import date as date_cls
target_date = date_cls(2026, 3, 12)
- conf_records = self.env['yuthon.catering.conf'].search([])
- if not conf_records:
- return
- employee_ids = conf_records.mapped('employee_ids')
+ employee_ids = self._get_active_conf_employees()
if not employee_ids:
return
create_vals = []
@@ -445,7 +441,7 @@ class YuthonCatering(models.Model):
def batch_generate_catering(self):
"""批量生成2025-12、2026-01、2026-02的餐饮收集任务数据,排除节假日"""
from datetime import date as date_cls
- conf = self.env['yuthon.catering.conf'].search([], limit=1)
+ conf = self.env['yuthon.catering.conf'].search([('expiry_date', '=', False)], limit=1)
if not conf or not conf.employee_ids:
return
employee_ids = conf.employee_ids
diff --git a/yuthon_catering/models/yuthon_catering_conf.py b/yuthon_catering/models/yuthon_catering_conf.py
index 357b9ccfc..03c06d6a6 100644
--- a/yuthon_catering/models/yuthon_catering_conf.py
+++ b/yuthon_catering/models/yuthon_catering_conf.py
@@ -4,12 +4,39 @@ from odoo import api, fields, models
class YuthonCateringConf(models.Model):
_name = 'yuthon.catering.conf'
+ _order = 'is_active desc, effective_date desc'
company_id = fields.Many2one(string='公司', comodel_name='res.company', required=True, default=lambda self: self.env.company)
employee_ids = fields.Many2many(string='员工', comodel_name='hr.employee')
employee_count = fields.Integer(string='人数', compute='_compute_employee_count', store=True)
+ effective_date = fields.Date(string='生效日期')
+ expiry_date = fields.Date(string='失效日期')
+ is_active = fields.Integer(string='是否生效', compute='_compute_is_active', store=True)
@api.depends('employee_ids')
def _compute_employee_count(self):
for record in self:
record.employee_count = len(record.employee_ids)
+
+ @api.depends('expiry_date')
+ def _compute_is_active(self):
+ for record in self:
+ record.is_active = 0 if record.expiry_date else 1
+
+ def action_change_employees(self):
+ """变更员工按鈕:打开wizard"""
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': '变更员工',
+ 'res_model': 'catering.conf.change.wizard',
+ 'view_mode': 'form',
+ 'target': 'new',
+ 'context': {'active_id': self.id},
+ }
+
+ def action_fix_null_effective_date(self):
+ """一次性修复:将没有生效日期的记录补为 2020-01-01,使其排到最下面"""
+ from datetime import date as date_cls
+ records = self.search([('effective_date', '=', False)])
+ if records:
+ records.write({'effective_date': date_cls(2020, 1, 1)})
diff --git a/yuthon_catering/security/ir.model.access.csv b/yuthon_catering/security/ir.model.access.csv
index 1d3056d3a..0b2794b5f 100644
--- a/yuthon_catering/security/ir.model.access.csv
+++ b/yuthon_catering/security/ir.model.access.csv
@@ -4,5 +4,6 @@ access_yuthon_catering_conf,yuthon_catering_conf,model_yuthon_catering_conf,,1,1
access_yuthon_menu_setting,yuthon_menu_setting,model_yuthon_menu_setting,,1,1,1,1
access_yuthon_dishes_setting,yuthon_dishes_setting,model_yuthon_dishes_setting,,1,1,1,1
access_catering_reinstated_wizard,catering_reinstated_wizard,model_catering_reinstated_wizard,,1,1,1,1
+access_catering_conf_change_wizard,catering_conf_change_wizard,model_catering_conf_change_wizard,,1,1,1,1
diff --git a/yuthon_catering/views/yuthon_catering_conf.xml b/yuthon_catering/views/yuthon_catering_conf.xml
index 103cf11ee..c5d514e67 100644
--- a/yuthon_catering/views/yuthon_catering_conf.xml
+++ b/yuthon_catering/views/yuthon_catering_conf.xml
@@ -6,10 +6,15 @@
yuthon.catering.conf.tree
yuthon.catering.conf
-
+
-
+
+
+
+
+
+
@@ -19,7 +24,6 @@
餐饮人员配置
yuthon.catering.conf
tree
-
@@ -30,4 +34,4 @@
sequence="1"
action="yuthon_catering_conf_action_window"/>
-
\ No newline at end of file
+
diff --git a/yuthon_catering/wizard/__init__.py b/yuthon_catering/wizard/__init__.py
index 26d2cb010..4055b2b7f 100644
--- a/yuthon_catering/wizard/__init__.py
+++ b/yuthon_catering/wizard/__init__.py
@@ -1 +1,2 @@
-from . import catering_reinstated_wizard
\ No newline at end of file
+from . import catering_reinstated_wizard
+from . import catering_conf_change_wizard
\ No newline at end of file
diff --git a/yuthon_catering/wizard/catering_conf_change_wizard.py b/yuthon_catering/wizard/catering_conf_change_wizard.py
new file mode 100644
index 000000000..6ae169bf2
--- /dev/null
+++ b/yuthon_catering/wizard/catering_conf_change_wizard.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+from odoo import api, fields, models
+
+
+class CateringConfChangeWizard(models.TransientModel):
+ _name = 'catering.conf.change.wizard'
+ _description = '餐饮人员配置变更确认'
+
+ conf_id = fields.Many2one(string='配置记录', comodel_name='yuthon.catering.conf', required=True)
+ employee_ids = fields.Many2many(
+ string='员工',
+ comodel_name='hr.employee',
+ )
+
+ @api.model
+ def default_get(self, fields_list):
+ res = super().default_get(fields_list)
+ conf_id = self._context.get('active_id')
+ if conf_id:
+ conf = self.env['yuthon.catering.conf'].browse(conf_id)
+ res['conf_id'] = conf_id
+ res['employee_ids'] = [(6, 0, conf.employee_ids.ids)]
+ return res
+
+ def action_confirm(self):
+ """确认:旧记录加失效日期,生成新记录"""
+ today = fields.Date.today()
+ # 旧记录加失效日期(跳过write覆写,直接用super)
+ from odoo.models import Model
+ Model.write(self.conf_id, {'expiry_date': today})
+ # 生成新记录
+ self.env['yuthon.catering.conf'].create({
+ 'company_id': self.conf_id.company_id.id,
+ 'employee_ids': [(6, 0, self.employee_ids.ids)],
+ 'effective_date': today,
+ })
+ return {'type': 'ir.actions.act_window_close'}
+
+ def action_cancel(self):
+ """取消:不做任何变更"""
+ return {'type': 'ir.actions.act_window_close'}
+
+ def action_modify(self):
+ """仅修改当前记录员工,不生成新记录,不更新日期"""
+ from odoo.models import Model
+ Model.write(self.conf_id, {'employee_ids': [(6, 0, self.employee_ids.ids)]})
+ return {'type': 'ir.actions.act_window_close'}
diff --git a/yuthon_catering/wizard/catering_conf_change_wizard_views.xml b/yuthon_catering/wizard/catering_conf_change_wizard_views.xml
new file mode 100644
index 000000000..b5d59a768
--- /dev/null
+++ b/yuthon_catering/wizard/catering_conf_change_wizard_views.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ catering.conf.change.wizard.form
+ catering.conf.change.wizard
+
+
+
+
+
+