添加功能
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
'views/inherit_planning_role_views.xml',
|
||||
'views/inherit_planning_slot_views.xml',
|
||||
'views/attendance_message_log.xml',
|
||||
'views/duty_adjustment_schedule_views.xml',
|
||||
'views/inherit_planning_slot_template_views.xml',
|
||||
'views/yuthon_customer_approval_views.xml',
|
||||
'views/yuthon_shift_planning_views.xml',
|
||||
|
||||
@@ -39,6 +39,7 @@ from . import vacation_overtime_active
|
||||
from . import yuthon_overtime_line
|
||||
from . import overtime_active_line
|
||||
from . import vacation_meal_active
|
||||
from . import duty_adjustment_schedule
|
||||
# from odoo.tools import SQL
|
||||
# import odoo
|
||||
# odoo.models.READ_GROUP_AGGREGATE.update({
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models, tools, _
|
||||
from datetime import datetime, time, timedelta
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import date, timedelta
|
||||
|
||||
|
||||
class DutyAdjustmentSchedule(models.Model):
|
||||
_name = 'duty.adjustment.schedule'
|
||||
_description = '值班调休表'
|
||||
|
||||
vacation_id = fields.Many2one('yuthon.vacation.reports', string="关联假期额度日志")
|
||||
employee_id = fields.Many2one('hr.employee', string="员工")
|
||||
is_adjustment = fields.Boolean(string="已调休")
|
||||
hide_selection = fields.Selection([('legal_date', '法定日'), ('adjust_holidays', '调班日'), ('workday', '工作日')], string="", compute="_compute_is_hide")
|
||||
is_hide = fields.Boolean(string="隐藏", compute='_compute_is_hide')
|
||||
company_id = fields.Many2one(related='employee_id.company_id', string="公司")
|
||||
duty_date = fields.Date(string="值班日期")
|
||||
week_day = fields.Char(string='星期', compute='_compute_week_day', store=True)
|
||||
|
||||
@api.depends('duty_date')
|
||||
def _compute_is_hide(self):
|
||||
"""
|
||||
最终规则(周末/调休日不隐藏):
|
||||
- 法定日 → 隐藏(is_hide=True),原因=法定日
|
||||
- 调班日 → 隐藏(is_hide=True),原因=调班日
|
||||
- 平常工作日 → 隐藏(is_hide=True),原因=工作日
|
||||
- 调休日/周末 → 不隐藏(is_hide=False),无原因
|
||||
"""
|
||||
for record in self:
|
||||
record.is_hide = False
|
||||
record.hide_selection = False
|
||||
if not record.duty_date:
|
||||
continue
|
||||
date_type = record._process_shift_days(record.duty_date)
|
||||
if date_type == 'legal_date':
|
||||
record.is_hide = True
|
||||
record.hide_selection = 'legal_date'
|
||||
elif date_type == 'adjust_holidays':
|
||||
record.is_hide = True
|
||||
record.hide_selection = 'adjust_holidays'
|
||||
elif date_type == 'workday':
|
||||
record.is_hide = True
|
||||
record.hide_selection = 'workday'
|
||||
|
||||
@api.depends('duty_date')
|
||||
def _compute_week_day(self):
|
||||
week_map = {'0': '周一', '1': '周二', '2': '周三', '3': '周四', '4': '周五', '5': '周六', '6': '周日'}
|
||||
for record in self:
|
||||
if record.duty_date:
|
||||
record.week_day = week_map[str(record.duty_date.weekday())]
|
||||
else:
|
||||
record.week_day = ''
|
||||
|
||||
def compensation(self):
|
||||
for record in self:
|
||||
if record.vacation_id.vacation_state == 'confirmed':
|
||||
raise UserError('该假期额度已确认,无法进行调休操作')
|
||||
record.is_adjustment = True
|
||||
over_record = self.env['vacation.over.line'].search([('employee_id', '=', record.employee_id.id), ('update_date', '=', record.duty_date),
|
||||
('vacation_id', '=', record.vacation_id.id)], limit=1)
|
||||
if not over_record:
|
||||
self.env['vacation.over.line'].create({
|
||||
'employee_id': record.employee_id.id,
|
||||
'update_date': record.duty_date,
|
||||
'vacation_id': record.vacation_id.id,
|
||||
'valid_date': date(record.duty_date.year + 1, 6, 30),
|
||||
'workday': 8,
|
||||
'update_type': 'add',
|
||||
'text': '值班调休'
|
||||
})
|
||||
record.vacation_id.update_line()
|
||||
|
||||
def revoke(self):
|
||||
for record in self:
|
||||
record.is_adjustment = False
|
||||
over_record = self.env['vacation.over.line'].search([('employee_id', '=', record.employee_id.id), ('update_date', '=', record.duty_date),
|
||||
('vacation_id', '=', record.vacation_id.id), ('text', '=', '值班调休')], limit=1)
|
||||
if over_record:
|
||||
over_record.unlink()
|
||||
record.vacation_id.update_line()
|
||||
|
||||
def _process_shift_days(self, current_data):
|
||||
"""
|
||||
判断指定日期的类型:
|
||||
- 法定日(holidays)→ 'legal_date'
|
||||
- 调班日(shift_replacement_day)→ 'adjust_holidays'
|
||||
- 平常工作日(1-5)→ 'workday'
|
||||
- 调休日(alternate_rest_day)/周末 → None
|
||||
"""
|
||||
if not current_data:
|
||||
return None
|
||||
current_year = current_data.year
|
||||
query_start = datetime(current_year, 1, 1, 0, 0, 0) - timedelta(hours=8)
|
||||
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 = [] # 调班日(对应adjust_holidays)
|
||||
adjust_days_list = [] # 调休日(不隐藏,无原因)
|
||||
|
||||
for leave in calendar_leaves:
|
||||
if leave.holidays:
|
||||
holidays_list.extend(leave.holidays.split(','))
|
||||
if leave.shift_replacement_day: # 调班日
|
||||
shift_days_list.extend(leave.shift_replacement_day.split(','))
|
||||
if leave.alternate_rest_day: # 调休日(仅判断,不赋值原因)
|
||||
adjust_days_list.extend(leave.alternate_rest_day.split(','))
|
||||
|
||||
holidays_list = [self.remove_leading_zero(d) for d in holidays_list if d]
|
||||
shift_days_list = [self.remove_leading_zero(d) for d in shift_days_list if d]
|
||||
current_date_str = f"{current_data.month}月{current_data.day}日"
|
||||
|
||||
if current_date_str in holidays_list:
|
||||
return 'legal_date' # 法定日
|
||||
elif current_date_str in shift_days_list:
|
||||
return 'adjust_holidays' # 调班日
|
||||
elif current_data.weekday() in [0, 1, 2, 3, 4]:
|
||||
return 'workday' # 平常工作日(周一到周五)
|
||||
else:
|
||||
return None # 调休日/周末(不隐藏,无原因)
|
||||
|
||||
# 移除日期字符串中的前导零
|
||||
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}日'
|
||||
|
||||
@@ -88,19 +88,6 @@ class PlanningSlotTemplate(models.Model):
|
||||
}
|
||||
return action
|
||||
|
||||
# @api.depends("planning_name")
|
||||
# def _compute_display_name(self):
|
||||
# super()._compute_display_name()
|
||||
# for record in self:
|
||||
# if record.planning_name and record.role_id:
|
||||
# record.display_name = f"{record.role_id.name}-{record.planning_name}"
|
||||
# elif record.planning_name:
|
||||
# record.display_name = record.planning_name
|
||||
# elif record.role_id:
|
||||
# record.display_name = record.role_id.name
|
||||
# else:
|
||||
# record.display_name = "Unknown"
|
||||
|
||||
@api.depends('role_id','planning_name')
|
||||
def _compute_display_name(self):
|
||||
for shift_template in self:
|
||||
|
||||
@@ -57,6 +57,7 @@ class YuthonVacationReports(models.Model):
|
||||
medical_fee_ids = fields.One2many('vacation.medical.line', 'vacation_id', string='体检费明细')
|
||||
parenting_line_ids = fields.One2many('vacation.parenting.line', 'vacation_id', string='育儿假明细')
|
||||
other_fee_ids = fields.One2many('vacation.other.line', 'vacation_id', string='其他明细')
|
||||
duty_ids = fields.One2many('duty.adjustment.schedule', 'vacation_id', string='值班调休明细', compute='_compute_duty_ids')
|
||||
vacation_date = fields.Date(string='日期', default=lambda self: fields.Date.today().replace(day=1))
|
||||
show_date = fields.Date(string='日期', compute='_compute_display_date', store=True)
|
||||
display_date = fields.Char(string='日期', compute='_compute_display_date')
|
||||
@@ -68,13 +69,14 @@ class YuthonVacationReports(models.Model):
|
||||
digits=(16, 3), group_operator=None)
|
||||
remain_missed_meals = fields.Float(string="剩余误餐次数", compute='_compute_meal_fee', store=True, group_operator=None)
|
||||
medical_fee = fields.Float(string="体检费", compute='_compute_medical_fee', store=True, group_operator=None)
|
||||
duty = fields.Float(string="值班", compute='_compute_duty_fee', store=True, group_operator=None)
|
||||
duty_off_leave = fields.Float(string='值班调休', compute='_compute_duty_fee', store=True, group_operator=None)
|
||||
compensatory_leave = fields.Float(string="调休d", compute='_compute_other_leave', store=True, group_operator=None)
|
||||
leave_of_absence = fields.Float(string="事假d", digits=(16, 3), compute='_compute_other_leave', store=True,
|
||||
group_operator=None)
|
||||
statutory_leave = fields.Float(string="加班时(法定)d", compute='_compute_other_leave', store=True, group_operator=None, digits=(16, 3))
|
||||
cop_leave = fields.Float(string='补休d', digits=(16, 3), store=True, compute='_compute_working_overtime',
|
||||
group_operator=None)
|
||||
duty_off_leave = fields.Float(string='值班调休d', compute='_compute_other_leave', store=True, group_operator=None)
|
||||
marriage_leave = fields.Float(string='婚假d', compute='_compute_other_leave', store=True, group_operator=None)
|
||||
maternity_leave = fields.Float(string='产假d', compute='_compute_other_leave', store=True, group_operator=None)
|
||||
paternity_leave = fields.Float(string='陪产假d', compute='_compute_other_leave', store=True, group_operator=None)
|
||||
@@ -117,6 +119,77 @@ class YuthonVacationReports(models.Model):
|
||||
tracking=3,
|
||||
default='not_sent')
|
||||
|
||||
@api.depends('employee_id', 'vacation_date')
|
||||
def _compute_duty_ids(self):
|
||||
duty_schedule_env = self.env['duty.adjustment.schedule']
|
||||
planning_slot_env = self.env['planning.slot']
|
||||
|
||||
for record in self:
|
||||
if not record.employee_id or not record.vacation_date:
|
||||
record.duty_ids = False
|
||||
continue
|
||||
|
||||
emp_id = record.employee_id.id
|
||||
year = record.vacation_date.year
|
||||
month = record.vacation_date.month
|
||||
month_start = date(year, month, 1)
|
||||
last_day = calendar.monthrange(year, month)[1]
|
||||
month_end = date(year, month, last_day)
|
||||
|
||||
all_duty_records = duty_schedule_env.search([
|
||||
('vacation_id', '=', record.id),
|
||||
('duty_date', '>=', month_start),
|
||||
('duty_date', '<=', month_end)
|
||||
])
|
||||
# 过滤出:非已调休的记录 → 批量删除
|
||||
non_adjusted_duties = all_duty_records.filtered(lambda d: not d.is_adjustment)
|
||||
if non_adjusted_duties:
|
||||
non_adjusted_duties.unlink()
|
||||
|
||||
white_duty_slots = planning_slot_env.search([
|
||||
('employee_id', '=', emp_id),
|
||||
('planning_name', '=', '白值'),
|
||||
('start_datetime', '>=', datetime.combine(month_start, datetime.min.time())),
|
||||
('start_datetime', '<=', datetime.combine(month_end, datetime.max.time()))
|
||||
])
|
||||
existing_duty_dates = {
|
||||
d.duty_date for d in duty_schedule_env.search([
|
||||
('vacation_id', '=', record.id),
|
||||
('duty_date', '>=', month_start),
|
||||
('duty_date', '<=', month_end)
|
||||
])
|
||||
}
|
||||
create_vals = []
|
||||
for slot in white_duty_slots:
|
||||
if not slot.start_datetime:
|
||||
continue
|
||||
duty_date = slot.start_datetime.date()
|
||||
if duty_date in existing_duty_dates:
|
||||
continue
|
||||
create_vals.append({
|
||||
'employee_id': emp_id,
|
||||
'vacation_id': record.id,
|
||||
'duty_date': duty_date,
|
||||
'is_adjustment': False
|
||||
})
|
||||
# 批量创建(效率更高)
|
||||
if create_vals:
|
||||
duty_schedule_env.create(create_vals)
|
||||
record.duty_ids = duty_schedule_env.search([
|
||||
('vacation_id', '=', record.id),
|
||||
('duty_date', '>=', month_start),
|
||||
('duty_date', '<=', month_end)
|
||||
])
|
||||
|
||||
|
||||
@api.depends('duty_ids.is_adjustment')
|
||||
def _compute_duty_fee(self):
|
||||
for record in self:
|
||||
total_duty_count = len(record.duty_ids)
|
||||
duty_off_count = len([line for line in record.duty_ids if line.is_adjustment])
|
||||
record.duty_off_leave = duty_off_count
|
||||
record.duty = max(total_duty_count - duty_off_count, 0)
|
||||
|
||||
@api.depends('vacation_date', 'employee_id')
|
||||
def _compute_number_card(self):
|
||||
for record in self:
|
||||
@@ -181,7 +254,6 @@ class YuthonVacationReports(models.Model):
|
||||
'context': {'tree_view_ref': "yuthon_hr_attendance.view_hr_leave_statement_tree"},
|
||||
}
|
||||
|
||||
|
||||
def import_initial_data(self):
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
@@ -312,7 +384,7 @@ class YuthonVacationReports(models.Model):
|
||||
rec.used_this_year1 += deduct_from_current1 # 累加到本年已休
|
||||
remaining_overtime_deduct -= deduct_from_current1
|
||||
|
||||
add_overtime_lines = rec.overtime_ids.filtered(lambda o: o.workflow_record_id and o.update_type == 'add' and o.is_void != True)
|
||||
add_overtime_lines = rec.overtime_ids.filtered(lambda o: o.text != '上月额度继承' and o.update_type == 'add' and o.is_void != True)
|
||||
# 计算补休新增总天数
|
||||
workday_overtime_add = sum((line.workday or 0) for line in add_overtime_lines) / 8
|
||||
holidays_overtime_add = sum((line.public_holidays or 0) for line in add_overtime_lines) / 8
|
||||
@@ -1134,7 +1206,6 @@ class YuthonVacationReports(models.Model):
|
||||
'调休': 'compensatory_leave',
|
||||
'事假': 'leave_of_absence',
|
||||
'法定假': 'statutory_leave',
|
||||
'值班调休': 'duty_off_leave',
|
||||
'婚假': 'marriage_leave',
|
||||
'产假': 'maternity_leave',
|
||||
'陪产假': 'paternity_leave',
|
||||
@@ -1158,7 +1229,7 @@ class YuthonVacationReports(models.Model):
|
||||
current_value = getattr(rec, field_name) or 0
|
||||
setattr(rec, field_name, current_value + line.lines)
|
||||
int_fields = [
|
||||
'compensatory_leave', 'statutory_leave', 'duty_off_leave',
|
||||
'compensatory_leave', 'statutory_leave',
|
||||
'marriage_leave', 'maternity_leave', 'paternity_leave',
|
||||
'family_planning_leave', 'home_visit_leave',
|
||||
'parents_meeting_leave', 'exam_leave'
|
||||
|
||||
@@ -95,4 +95,5 @@ access_overtime_active_line,overtime.active.line,model_overtime_active_line,base
|
||||
access_export_date_wizard,export.date.wizard,model_export_date_wizard,base.group_user,1,1,1,1
|
||||
access_vacation_meal_active,vacation.meal.active,model_vacation_meal_active,base.group_user,1,1,1,1
|
||||
access_yuthon_vacation_import_wizard,yuthon.vacation.import.wizard,model_yuthon_vacation_import_wizard,base.group_user,1,1,1,1
|
||||
access_overtime_change_wizard,overtime.change.wizard,model_overtime_change_wizard,base.group_user,1,1,1,1
|
||||
access_overtime_change_wizard,overtime.change.wizard,model_overtime_change_wizard,base.group_user,1,1,1,1
|
||||
access_duty_adjustment_schedule,duty.adjustment.schedule,model_duty_adjustment_schedule,base.group_user,1,1,1,1
|
||||
|
@@ -0,0 +1,20 @@
|
||||
<odoo>
|
||||
<record id="view_duty_adjustment_schedule_tree" model="ir.ui.view">
|
||||
<field name="name">duty.adjustment.schedule.tree</field>
|
||||
<field name="model">duty.adjustment.schedule</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom" create="false" delete="false" edit="false">
|
||||
<field name="employee_id"/>
|
||||
<field name="company_id"/>
|
||||
<field name="duty_date"/>
|
||||
<field name="week_day"/>
|
||||
<field name="is_hide" column_invisible="1"/>
|
||||
<field name="hide_selection" string=" "/>
|
||||
<field name="vacation_id" column_invisible="1"/>
|
||||
<field name="is_adjustment" column_invisible="1"/>
|
||||
<button name="compensation" string="调休" type="object" class="btn-primary" invisible="is_adjustment or is_hide"/>
|
||||
<button name="revoke" string="撤销" type="object" class="btn-danger" invisible="not is_adjustment"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -225,13 +225,4 @@
|
||||
<field name="groups_id"
|
||||
eval="[(4, ref('yuthon_hr_attendance.group_he_attendance_sign_manager'))]" />
|
||||
</record>
|
||||
<record id="action_update_abnormal_shift" model="ir.actions.server">
|
||||
<field name="name">批量更新班次名称</field>
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_hr_attendance" />
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_hr_attendance" />
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.update_abnormal()</field>
|
||||
<field name="groups_id"
|
||||
eval="[(4, ref('yuthon_hr_attendance.group_he_attendance_sign_manager'))]" />
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -65,6 +65,8 @@
|
||||
<field name="expatriation" options='{ "fg_color": "white: expatriation == False"}'/>
|
||||
<field name="right_days" options='{ "fg_color": "white: right_days == False"}'/>
|
||||
<field name="test_days" options='{ "fg_color": "white: test_days == False"}'/>
|
||||
<field name="duty" options='{ "fg_color": "white: duty == False"}'/>
|
||||
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
|
||||
<field name="is_late_card" options='{ "fg_color": "white: is_late_card == False"}'/>
|
||||
<field name="is_early_card" options='{ "fg_color": "white: is_early_card == False"}'/>
|
||||
<field name="is_no_card" options='{ "fg_color": "white: is_no_card == False"}'/>
|
||||
@@ -81,7 +83,6 @@
|
||||
options='{ "fg_color": "white: statutory_leave == False"}'/>
|
||||
<field name="cop_leave" options='{ "fg_color": "white: cop_leave == False"}'/>
|
||||
<field name="parental_leave" options='{ "fg_color": "white: parental_leave == False"}'/>
|
||||
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
|
||||
<field name="marriage_leave" options='{ "fg_color": "white: marriage_leave == False"}'/>
|
||||
<field name="maternity_leave" options='{ "fg_color": "white: maternity_leave == False"}'/>
|
||||
<field name="paternity_leave" options='{ "fg_color": "white: paternity_leave == False"}'/>
|
||||
@@ -129,8 +130,12 @@
|
||||
<field name="remainder_year"/>
|
||||
<field name="should_attendance" options='{ "fg_color": "white: should_attendance == False"}'/>
|
||||
<field name="actual_attendance" options='{ "fg_color": "white: actual_attendance == False"}'/>
|
||||
<field name="expatriation" options='{ "fg_color": "white: expatriation == False"}'/>
|
||||
<field name="right_days" options='{ "fg_color": "white: right_days == False"}'/>
|
||||
<field name="test_days" options='{ "fg_color": "white: test_days == False"}'/>
|
||||
<field name="duty" options='{ "fg_color": "white: duty == False"}'/>
|
||||
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
|
||||
<field name="compensatory_leave" options='{ "fg_color": "white: compensatory_leave == False"}'/>
|
||||
<field name="is_late_card" options='{ "fg_color": "white: is_late_card == False"}'/>
|
||||
<field name="is_early_card" options='{ "fg_color": "white: is_early_card == False"}'/>
|
||||
<field name="is_no_card" options='{ "fg_color": "white: is_no_card == False"}'/>
|
||||
@@ -148,7 +153,6 @@
|
||||
options='{ "fg_color": "white: statutory_leave == False"}'/>
|
||||
<field name="cop_leave" options='{ "fg_color": "white: cop_leave == False"}'/>
|
||||
<field name="parental_leave" options='{ "fg_color": "white: parental_leave == False"}'/>
|
||||
<field name="duty_off_leave" options='{ "fg_color": "white: duty_off_leave == False"}'/>
|
||||
<field name="marriage_leave" options='{ "fg_color": "white: marriage_leave == False"}'/>
|
||||
<field name="maternity_leave" options='{ "fg_color": "white: maternity_leave == False"}'/>
|
||||
<field name="paternity_leave" options='{ "fg_color": "white: paternity_leave == False"}'/>
|
||||
@@ -371,6 +375,22 @@
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="值班明细">
|
||||
<field name="duty_ids" context="{'default_employee_id': employee_id}">
|
||||
<tree editable="bottom" delete="false" default_order="duty_date desc">
|
||||
<field name="vacation_id" column_invisible="1"/>
|
||||
<field name="employee_id" column_invisible="1"/>
|
||||
<field name="company_id" column_invisible="1"/>
|
||||
<field name="duty_date"/>
|
||||
<field name="week_day"/>
|
||||
<field name="hide_selection" string=" "/>
|
||||
<field name="is_hide" column_invisible="1"/>
|
||||
<field name="is_adjustment" column_invisible="1"/>
|
||||
<button name="compensation" string="调休" type="object" class="btn-primary" invisible="is_adjustment or is_hide"/>
|
||||
<button name="revoke" string="撤销" type="object" class="btn-danger" invisible="not is_adjustment"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
<page string="管理员修改字段" groups="base.group_system">
|
||||
<group col="2">
|
||||
<group>
|
||||
|
||||
Reference in New Issue
Block a user