256 lines
14 KiB
Python
256 lines
14 KiB
Python
from odoo import api, fields, models, tools, _
|
|
from datetime import datetime, time, timedelta
|
|
from odoo.exceptions import UserError, ValidationError
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
|
|
class YuthonShiftPlanning(models.Model):
|
|
_name = 'yuthon.shift.planning'
|
|
_description = '保安部排班安排'
|
|
|
|
name = fields.Char(string='排班名称', required=True)
|
|
illustrate = fields.Char(string='排班说明', default='默认按ABC三组轮排到下个月')
|
|
number_of_shifts = fields.Integer(string='轮班次数', default=10)
|
|
planning_a_ids = fields.One2many('yuthon.shift.planning.a.line', 'shift_planning_id', string='关联A组')
|
|
planning_b_ids = fields.One2many('yuthon.shift.planning.b.line', 'shift_planning_id', string='关联B组')
|
|
planning_c_ids = fields.One2many('yuthon.shift.planning.c.line', 'shift_planning_id', string='关联C组')
|
|
start_date = fields.Date(string="生效日期", default=fields.Datetime.today())
|
|
end_date = fields.Date(string="失效日期")
|
|
is_effect = fields.Boolean(string="是否生效", compute="_compute_is_effect")
|
|
planning_ever_white_ids = fields.One2many('yuthon.shift.ever.white.line', 'shift_planning_id', string='关联常白班')
|
|
planning_ever_noon_ids = fields.One2many('yuthon.shift.ever.noon.line', 'shift_planning_id', string='关联常中班')
|
|
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
|
|
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
|
|
('9', '九月'), ('10', '十月'), ('11', '十一月'),
|
|
('12', '十二月')], string='选择月份', default=lambda self: self._get_default_month())
|
|
|
|
@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 confirm(self,next_date=False):
|
|
selected_month = int(self.select_time)
|
|
year = datetime.now().year
|
|
target_month = selected_month if not next_date else (selected_month % 12) + 1
|
|
target_year = year if (not next_date or selected_month != 12) else year + 1
|
|
start_date = datetime(target_year, target_month, 1)
|
|
next_month_first_day = start_date + relativedelta(months=1)
|
|
end_date = next_month_first_day - timedelta(days=1)
|
|
|
|
existing_slots = self.env['planning.slot'].search([
|
|
('role_id.name', '=', '保安部'),
|
|
('start_datetime', '>=', start_date),
|
|
('start_datetime', '<=', end_date),
|
|
])
|
|
if len(existing_slots) > 0:
|
|
raise UserError(f"该月已经有排程,请选择其他时间。")
|
|
|
|
role_a = self.env['planning.role'].search([('name', '=', '保安部')], limit=1)
|
|
role_template_a = self.env['planning.slot.template'].search([('planning_name', '=', '早班'), ('role_id', '=', role_a.id)])
|
|
role_template_b = self.env['planning.slot.template'].search([('planning_name', '=', '中班'), ('role_id', '=', role_a.id)])
|
|
role_template_c = self.env['planning.slot.template'].search([('planning_name', '=', '夜班'), ('role_id', '=', role_a.id)])
|
|
role = [role_template_a, role_template_b, role_template_c]
|
|
planning_groups = {
|
|
'planning_a_ids': [0, 2, 1], # 早 -> 夜 -> 中
|
|
'planning_b_ids': [1, 0, 2], # 中 -> 早 -> 夜
|
|
'planning_c_ids': [2, 1, 0], # 夜 -> 中 -> 早
|
|
}
|
|
|
|
weekday_mapping = {
|
|
'one': 0, 'two': 1, 'three': 2, 'four': 3, 'five': 4, 'six': 5, 'seven': 6
|
|
}
|
|
|
|
for planning_group, role_order in planning_groups.items():
|
|
ever_holidays = {} # 为每个组创建独立的休息日字典
|
|
|
|
# 获取当前组的员工记录
|
|
employee_records = getattr(self, planning_group)
|
|
|
|
# 处理当前组员工的休息日
|
|
for record in employee_records:
|
|
if record.employee_id:
|
|
resource_id = record.employee_id.resource_id.id
|
|
weekday_number = weekday_mapping.get(record.regular_holidays)
|
|
if resource_id not in ever_holidays:
|
|
ever_holidays[resource_id] = []
|
|
if weekday_number is not None: # 检查weekday_number是否有效
|
|
ever_holidays[resource_id].append(weekday_number)
|
|
|
|
for record in employee_records:
|
|
current_date = start_date
|
|
while current_date < end_date:
|
|
for role_index in role_order:
|
|
for _ in range(self.number_of_shifts):
|
|
employee = record.employee_id
|
|
resource_id = employee.resource_id.id
|
|
current_weekday = current_date.weekday()
|
|
if resource_id in ever_holidays and current_weekday in ever_holidays[resource_id]:
|
|
pass # 跳过休息日
|
|
else:
|
|
if current_date.day == 31:
|
|
self.create_planning_slot(record, role_a, role[role_index-2], current_date)
|
|
else:
|
|
self.create_planning_slot(record, role_a, role[role_index], current_date)
|
|
current_date += timedelta(days=1)
|
|
if current_date >= end_date:
|
|
break
|
|
if current_date >= end_date:
|
|
break
|
|
|
|
ever_holidays = {}
|
|
# 处理早班员工的休息日
|
|
for record in self.planning_ever_white_ids:
|
|
if record.employee_id:
|
|
resource_id = record.employee_id.resource_id.id
|
|
weekday_number = weekday_mapping.get(record.regular_holidays)
|
|
if resource_id not in ever_holidays:
|
|
ever_holidays[resource_id] = []
|
|
ever_holidays[resource_id].append(weekday_number)
|
|
|
|
# 处理中班员工的休息日
|
|
for record in self.planning_ever_noon_ids:
|
|
if record.employee_id:
|
|
resource_id = record.employee_id.resource_id.id
|
|
weekday_number = weekday_mapping.get(record.regular_holidays)
|
|
if resource_id not in ever_holidays:
|
|
ever_holidays[resource_id] = []
|
|
ever_holidays[resource_id].append(weekday_number)
|
|
|
|
def create_shifts_for_group(employee_records, role_item):
|
|
for record in employee_records:
|
|
resource_id = record.employee_id.resource_id.id
|
|
current_date = start_date
|
|
while current_date <= end_date:
|
|
current_weekday = current_date.weekday()
|
|
if resource_id in ever_holidays and current_weekday in ever_holidays[resource_id]:
|
|
pass
|
|
else:
|
|
self.create_planning_slot(record, role_a, role_item, current_date)
|
|
current_date += timedelta(days=1)
|
|
if current_date >= end_date:
|
|
break
|
|
if current_date >= end_date:
|
|
break
|
|
# 为白班员工创建排班
|
|
create_shifts_for_group(self.planning_ever_white_ids, role[0])
|
|
# 为中班员工创建排班
|
|
create_shifts_for_group(self.planning_ever_noon_ids, role[1])
|
|
|
|
def create_planning_slot(self, record,role,role_template, current_date):
|
|
check_in_start = role_template.start_time
|
|
check_out_end = role_template.end_time
|
|
start_hour = int(check_in_start)
|
|
start_minute = int((check_in_start - start_hour) * 60)
|
|
end_hour = int(check_out_end)
|
|
end_minute = int((check_out_end - end_hour) * 60)
|
|
# 拼接成 datetime 对象
|
|
start_datetime = datetime.combine(current_date, datetime.min.time()).replace(
|
|
hour=start_hour, minute=start_minute, second=0, microsecond=0
|
|
)
|
|
end_datetime = datetime.combine(current_date, datetime.min.time()).replace(
|
|
hour=end_hour, minute=end_minute, second=0, microsecond=0
|
|
)
|
|
self.env['planning.slot'].create({
|
|
'resource_id': record.employee_id.resource_id.id,
|
|
'template_id':role_template.id,
|
|
'role_id':role.id,
|
|
'start_datetime': start_datetime - timedelta(hours=8),
|
|
'end_datetime': end_datetime - timedelta(hours=8),
|
|
'allocated_hours':8,
|
|
})
|
|
|
|
def shift_next_planing(self):
|
|
self.confirm(next_date=True)
|
|
|
|
def exchange_button(self):
|
|
for record in self:
|
|
white_lines = record.planning_ever_white_ids
|
|
noon_lines = record.planning_ever_noon_ids
|
|
white_data = [{'employee_id': line.employee_id.id, 'sequence': line.sequence,
|
|
'regular_holidays': line.regular_holidays} for line in white_lines]
|
|
noon_data = [{'employee_id': line.employee_id.id, 'sequence': line.sequence,
|
|
'regular_holidays': line.regular_holidays} for line in noon_lines]
|
|
white_lines.unlink()
|
|
noon_lines.unlink()
|
|
for data in noon_data:
|
|
record.planning_ever_white_ids = [(0, 0, data)]
|
|
for data in white_data:
|
|
record.planning_ever_noon_ids = [(0, 0, data)]
|
|
|
|
def _get_default_month(self):
|
|
current_month = datetime.now().month
|
|
return str(current_month) # 返回字符串类型的月份
|
|
|
|
class YuthonShiftPlanningALine(models.Model):
|
|
_name = 'yuthon.shift.planning.a.line'
|
|
_description = '排班安排A组'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string='人员',
|
|
domain=lambda self: [('department_id.name', 'in', ['秩序维护部', '班组A', '班组B','班组C'])])
|
|
sequence = fields.Integer(string='序号')
|
|
regular_holidays = fields.Selection([('one', '星期一'), ('two', '星期二'), ('three', '星期三'),
|
|
('four', '星期四'), ('five', '星期五'), ('six', '星期六'),
|
|
('seven', '星期日')], string='固定休息日')
|
|
shift_planning_id = fields.Many2one('yuthon.shift.planning', string='关联排班安排')
|
|
|
|
|
|
class YuthonShiftPlanningBLine(models.Model):
|
|
_name = 'yuthon.shift.planning.b.line'
|
|
_description = '排班安排B组'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string='人员',
|
|
domain=lambda self: [('department_id.name', 'in', ['秩序维护部', '班组A', '班组B','班组C'])])
|
|
sequence = fields.Integer(string='序号')
|
|
regular_holidays = fields.Selection([('one', '星期一'), ('two', '星期二'), ('three', '星期三'),
|
|
('four', '星期四'), ('five', '星期五'), ('six', '星期六'),
|
|
('seven', '星期日')], string='固定休息日')
|
|
shift_planning_id = fields.Many2one('yuthon.shift.planning', string='关联排班安排')
|
|
|
|
|
|
class YuthonShiftPlanningCLine(models.Model):
|
|
_name = 'yuthon.shift.planning.c.line'
|
|
_description = '排班安排C组'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string='人员',
|
|
domain=lambda self: [('department_id.name', 'in', ['秩序维护部', '班组A', '班组B','班组C'])])
|
|
sequence = fields.Integer(string='序号')
|
|
regular_holidays = fields.Selection([('one', '星期一'), ('two', '星期二'), ('three', '星期三'),
|
|
('four', '星期四'), ('five', '星期五'), ('six', '星期六'),
|
|
('seven', '星期日')], string='固定休息日')
|
|
shift_planning_id = fields.Many2one('yuthon.shift.planning', string='关联排班安排')
|
|
|
|
|
|
class YuthonShiftEverWhiteLine(models.Model):
|
|
_name = 'yuthon.shift.ever.white.line'
|
|
_description = '常白班'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string='人员',
|
|
domain=lambda self: [('department_id.name', 'in', ['秩序维护部', '班组A', '班组B','班组C'])])
|
|
sequence = fields.Integer(string='序号')
|
|
regular_holidays = fields.Selection([('one', '星期一'), ('two', '星期二'), ('three', '星期三'),
|
|
('four', '星期四'), ('five', '星期五'), ('six', '星期六'),
|
|
('seven', '星期日')], string='固定休息日')
|
|
shift_planning_id = fields.Many2one('yuthon.shift.planning', string='关联排班安排')
|
|
|
|
|
|
class YuthonShiftEverNightLine(models.Model):
|
|
_name = 'yuthon.shift.ever.noon.line'
|
|
_description = '常中班'
|
|
|
|
employee_id = fields.Many2one('hr.employee', string='人员',
|
|
domain=lambda self: [('department_id.name', 'in', ['秩序维护部', '班组A', '班组B','班组C'])])
|
|
sequence = fields.Integer(string='序号')
|
|
regular_holidays = fields.Selection([('one', '星期一'), ('two', '星期二'), ('three', '星期三'),
|
|
('four', '星期四'), ('five', '星期五'), ('six', '星期六'),
|
|
('seven', '星期日')], string='固定休息日')
|
|
shift_planning_id = fields.Many2one('yuthon.shift.planning', string='关联排班安排')
|
|
|
|
|