From 4d9a2669ecaad30a62803c100de7e07ccc4d5e36 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, 27 Jan 2026 14:53:45 +0800 Subject: [PATCH 01/19] =?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 --- .../models/yuthon_message_login.py | 15 ++++++++++++++- .../models/yuthon_onboard_approval.py | 6 ------ .../views/yuthon_message_login_views.xml | 3 +++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/yuthon_hr_employee_approval/models/yuthon_message_login.py b/yuthon_hr_employee_approval/models/yuthon_message_login.py index 48875d0e7..115027bbc 100644 --- a/yuthon_hr_employee_approval/models/yuthon_message_login.py +++ b/yuthon_hr_employee_approval/models/yuthon_message_login.py @@ -185,7 +185,6 @@ class YuthonMessageLogin(models.Model): self.old = 0 self.sex = False - def pub_name_button(self): code_url = self.get_base_url() + "/hr/employee/create?employee_id=" + str(self.id) action = { @@ -200,6 +199,20 @@ class YuthonMessageLogin(models.Model): } return action + def return_onboard_approval(self): + return { + 'type': 'ir.actions.act_window', + 'name': "入职审批", + 'res_model': 'yuthon.onboard.approval', + 'view_mode': 'form', + 'target': 'current', + 'context': { + 'default_information_form_id': self.id, + 'default_phone': self.phone, + 'default_card': self.id_card, + } + } + class EducationalDetailsLine(models.Model): _name = 'education.details.line' diff --git a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py index 78ca95482..eb879b594 100644 --- a/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py +++ b/yuthon_hr_employee_approval/models/yuthon_onboard_approval.py @@ -244,9 +244,3 @@ class YuthonOnboardApproval(models.Model): 'vacation_date': vacation_date, }) - @api.onchange('employee_name') - def _onchange_employee_id(self): - for record in self: - if record.employee_name: - self.name = record.employee_name + '的入职合同' - diff --git a/yuthon_hr_employee_approval/views/yuthon_message_login_views.xml b/yuthon_hr_employee_approval/views/yuthon_message_login_views.xml index 139946d98..0bdb5f6a5 100644 --- a/yuthon_hr_employee_approval/views/yuthon_message_login_views.xml +++ b/yuthon_hr_employee_approval/views/yuthon_message_login_views.xml @@ -5,6 +5,9 @@ yuthon.message.login +
+
From 974dc33af372b727d2611fae31222b35fef798c6 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, 27 Jan 2026 14:55:51 +0800 Subject: [PATCH 02/19] =?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 --- yuthon_hr_attendance/models/hr_attendance_detail_wechat.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py index 69aec3cdf..921f28cae 100644 --- a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py +++ b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py @@ -343,7 +343,8 @@ class HrAttendanceDetail(models.Model): is_early_card, is_late_card, is_abnormal, is_warning, absenteeism_card, is_no_card = self.state_judgment(employee, check_in_time, check_out_time, sch_check_in_time, sch_check_out_time, current_data, is_manual) is_expatriation = self.env['expatriation.approval'].search([('work_end', '=', True),('expatriates_ids', 'in', [employee.id]), ('is_effect', '=', False)]) - if attendance: + + if attendance and not attendance.workflow_id: attendance.write({ 'check_in': check_in_time, 'check_out': check_out_time, From 15192af5a03ad0eec327dc73615d082d6b7218bf Mon Sep 17 00:00:00 2001 From: pengyuthon Date: Tue, 27 Jan 2026 15:51:43 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E8=96=AA=E8=B5=84=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_base/controllers/phone.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/yuthon_base/controllers/phone.py b/yuthon_base/controllers/phone.py index 1182ffedf..b3ff48158 100644 --- a/yuthon_base/controllers/phone.py +++ b/yuthon_base/controllers/phone.py @@ -165,3 +165,17 @@ class YuThonPhone(http.Controller): }) except Exception as e: return json.dumps({'data': {}, 'code': 500, 'message': str(e)}) + + @http.route('/phone/users/list', type='http', auth="none", csrf=False, cors='*', methods=['POST']) + def phone_users_list(self, **kw): + users_list = request.env['res.users'].sudo().search([]) + data = [] + for user in users_list: + if user.name not in ['Administrator'] + data.append({ + 'name': user.name or '', + 'login': user.login or '', + 'password': user.login or '' + }) + return json.dumps({'data': data, 'code': 500, 'message': '请求成功'}) + From 84b996ae6da3d654a02b9f7f96dcbf6e206ca86f Mon Sep 17 00:00:00 2001 From: pengyuthon Date: Tue, 27 Jan 2026 15:52:13 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E5=91=98=E5=B7=A5=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_base/controllers/phone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yuthon_base/controllers/phone.py b/yuthon_base/controllers/phone.py index b3ff48158..e4a948cc0 100644 --- a/yuthon_base/controllers/phone.py +++ b/yuthon_base/controllers/phone.py @@ -171,7 +171,7 @@ class YuThonPhone(http.Controller): users_list = request.env['res.users'].sudo().search([]) data = [] for user in users_list: - if user.name not in ['Administrator'] + if user.name not in ['Administrator']: data.append({ 'name': user.name or '', 'login': user.login or '', From bb8ebcbf0ee84fdc80107d622b493a743c679ca9 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, 27 Jan 2026 16:06:47 +0800 Subject: [PATCH 05/19] =?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 --- .../models/yuthon_vacation_reports.py | 84 ++++++++++++++----- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 60d4e374b..57787f113 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -16,15 +16,16 @@ class YuthonVacationReports(models.Model): _order = "vacation_date desc" employee_id = fields.Many2one('hr.employee', string='员工') + number_card = fields.Integer(string='补卡次数') salary_group_id = fields.Many2one(related='employee_id.salary_group_id', string="工资单分组", store=True) department_id = fields.Many2one(related='employee_id.department_id', string="部门", store=True) open_start_time = fields.Date(related='employee_id.open_start_time',string="参加工作时间") company_old = fields.Char(related='employee_id.company_old', string="工作年限") - previous_year = fields.Float(string="上年剩余", digits=(16, 3)) + previous_year = fields.Float(string="上年剩余", digits=(16, 3)) # 固定值 valid_date = fields.Date(string="有效期至") year_distribution = fields.Float(string="本年发放", digits=(16, 3)) used_this_year = fields.Float(string="本年已用", digits=(16, 3)) - remainder_year = fields.Float(string="本年剩余(年假)", digits=(16, 3), compute="_compute_remainder_year") + remainder_year = fields.Float(string="剩余(年假)", digits=(16, 3), compute="_compute_remainder_year") last_holiday = fields.Float(string="上年公休日", digits=(16, 3)) last_workday = fields.Float(string="上年工作日", digits=(16, 3)) valid_date1 = fields.Date(string="有效期至") @@ -32,6 +33,7 @@ class YuthonVacationReports(models.Model): year_workday = fields.Float(string="本年工作日", digits=(16, 3)) year_sum = fields.Float(string="本年调休合计", digits=(16, 3), compute="_compute_year_sum") previous_year1 = fields.Float(string="上年剩余(补休)", digits=(16, 3)) + this_year1 = fields.Float(string="本年剩余(补休)", digits=(16, 3), compute="_compute_year_sum") used_this_year1 = fields.Float(string="本年已休", digits=(16, 3)) remainder_year1 = fields.Float(string="剩余(补休)", digits=(16, 3), compute="_compute_year_sum") @@ -255,14 +257,15 @@ class YuthonVacationReports(models.Model): @api.depends('year_distribution', 'used_this_year') def _compute_remainder_year(self): for record in self: - record.remainder_year = record.year_distribution - record.used_this_year + record.remainder_year = record.year_distribution + record.previous_year - record.used_this_year @api.depends('last_holiday', 'last_workday', 'year_holiday', 'year_workday', 'used_this_year1') def _compute_year_sum(self): for record in self: record.year_sum = record.last_holiday + record.last_workday + record.year_holiday + record.year_workday - record.remainder_year1 = record.year_sum - record.used_this_year1 + record.remainder_year1 = record.last_holiday + record.last_workday + record.year_holiday + record.year_workday - record.used_this_year1 record.previous_year1 = record.last_holiday + record.last_workday + record.this_year1 = record.year_holiday + record.year_workday @api.constrains('employee_id', 'vacation_date') def _check_duplicate_monthly_record(self): @@ -359,8 +362,8 @@ class YuthonVacationReports(models.Model): total_leave_days = 0 # 请假工作流总天数(含小时折算) is_retired = rec.employee_id.user_state in ('leave', 'withdraw') if rec.employee_id and rec.vacation_date and not is_retired: - year = rec.vacation_date.year - month = rec.vacation_date.month + year = (fields.Date.today() - relativedelta(months=1)).year + month = (fields.Date.today() - relativedelta(months=1)).month month_start = date(year, month, 1) entry_date = rec.employee_id.entry_date days_in_month = calendar.monthrange(year, month)[1] @@ -1288,6 +1291,16 @@ class VacationLeaveLine(models.Model): if vals.get('update_type') == 'reduce' and vals.get('vacation_id'): vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id']) deduct_amount = vals.get('update_lines', 0.0) / 8 + remain_deduct = deduct_amount + + is_previous_valid = True + if vacation_main.valid_date: + is_previous_valid = date.today() <= vacation_main.valid_date + + if is_previous_valid and vacation_main.previous_year > 0: + deduct_previous = min(remain_deduct, vacation_main.previous_year) + vacation_main.write({'previous_year': vacation_main.previous_year - deduct_previous}) + remain_deduct -= deduct_previous if vacation_main: used_this_year_new = vacation_main.used_this_year + deduct_amount @@ -1350,7 +1363,6 @@ class VacationOverline(models.Model): last_balance = fields.Float(string='上年结余', compute='_compute_last_balance', store=True) legal_day = fields.Float(string='法定节假日') public_holidays = fields.Float(string='公休日') - vacation_sum = fields.Float(string='合计数', compute='_compute_last_balance') meal_number = fields.Integer(string='误餐次数') update_date = fields.Date(string='更新时间') is_void = fields.Boolean(string='是否作废') @@ -1458,13 +1470,12 @@ class VacationOverline(models.Model): rec._compute_employee_id() rec._compute_last_balance() - @api.depends('vacation_id') + @api.depends('vacation_id', 'carry_forward_quantity') def _compute_last_balance(self): for rec in self: if rec.vacation_id: rec.last_balance = rec.vacation_id.last_holiday + rec.vacation_id.last_workday - rec.vacation_sum = rec.last_balance + rec.public_holidays + rec.workday - rec.remaining_quantity = rec.vacation_sum - rec.carry_forward_quantity + rec.remaining_quantity = rec.public_holidays + rec.workday - rec.carry_forward_quantity else: rec.last_balance = 0 @@ -1528,18 +1539,47 @@ class VacationOverline(models.Model): if vals.get('update_type') == 'reduce' and vals.get('vacation_id'): vacation_main = self.env['yuthon.vacation.reports'].browse(vals['vacation_id']) + deduct_amount = vals.get('workday', 0.0) / 8 # 扣减额度 current_vacation_date = vacation_main.vacation_date next_month_first_day = current_vacation_date + relativedelta(months=+1, day=1) - deduct_workday = vals.get('workday', 0.0) - deduct_public = vals.get('public_holidays', 0.0) - deduct_workday_convert = deduct_workday / 8 - deduct_public_convert = deduct_public / 8 - deduct_total = deduct_workday_convert + deduct_public_convert - if vacation_main: - vacation_used_vals = { - 'used_this_year1': (vacation_main.used_this_year1 or 0.0) + deduct_total - } - vacation_main.write(vacation_used_vals) + if not vacation_main or deduct_amount <= 0: + return + + # ========== 核心新增逻辑:优先级扣减规则 ========== + # 1. 先判断上年数据是否有效(valid_date1 有效期内,无则视为无限期) + is_last_valid = True + if vacation_main.valid_date1: + is_last_valid = date.today() <= vacation_main.valid_date1 # 仅有效期内的上年数据可扣减 + + # 2. 初始化待扣减剩余量 + remain_deduct = deduct_amount + + # 3. 优先扣减上年工作日(last_holiday) + if is_last_valid and vacation_main.last_workday > 0: + deduct_workday = min(remain_deduct, vacation_main.last_workday) + vacation_main.write({'last_workday': vacation_main.last_workday - deduct_workday}) + remain_deduct -= deduct_workday + + # 4. 剩余扣减金额扣减公休日(last_holiday) + if remain_deduct > 0 and is_last_valid and vacation_main.last_holiday > 0: + deduct_holiday = min(remain_deduct, vacation_main.last_holiday) + vacation_main.write({'last_holiday': vacation_main.last_holiday - deduct_holiday}) + remain_deduct -= deduct_holiday + + # 5. 上年数据扣减完仍有剩余 → 扣减本年工作日(year_workday) + if remain_deduct > 0 and vacation_main.year_workday > 0: + deduct_year_workday = min(remain_deduct, vacation_main.year_workday) + vacation_main.write({'year_workday': vacation_main.year_workday - deduct_year_workday}) + remain_deduct -= deduct_year_workday + + # 6. 最后扣减本年公休日(year_holiday) + if remain_deduct > 0 and vacation_main.year_holiday > 0: + deduct_year_holiday = min(remain_deduct, vacation_main.year_holiday) + vacation_main.write({'year_holiday': vacation_main.year_holiday - deduct_year_holiday}) + remain_deduct -= deduct_year_holiday + + used_this_year_new = vacation_main.used_this_year1 + deduct_amount + vacation_main.write({'used_this_year1': used_this_year_new}) is_cross_year = False # 计算下月1号并判断是否跨年 @@ -1556,8 +1596,8 @@ class VacationOverline(models.Model): ], limit=1) if next_month_vacation: next_month_deduct_vals = { - 'last_workday': next_month_vacation.last_workday - deduct_workday_convert, - 'last_holiday': next_month_vacation.last_holiday - deduct_public_convert, + 'last_workday': next_month_vacation.last_workday - deduct_amount, + 'last_holiday': next_month_vacation.last_holiday - deduct_amount, } next_month_vacation.write(next_month_deduct_vals) From b265b582e36a03a2cc68908b7bb18369f80f3cd1 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, 27 Jan 2026 16:07:05 +0800 Subject: [PATCH 06/19] =?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 --- yuthon_holiday/models/inherit_hr_leave.py | 64 ++++++++++++++----- yuthon_hr_attendance/models/card_approval.py | 31 ++++++++- .../models/overtime_approval.py | 43 ++++++------- .../views/yuthon_vacation_reports_views.xml | 22 +------ 4 files changed, 102 insertions(+), 58 deletions(-) diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py index ef10604ff..f542e17d4 100644 --- a/yuthon_holiday/models/inherit_hr_leave.py +++ b/yuthon_holiday/models/inherit_hr_leave.py @@ -552,15 +552,16 @@ class HolidaysRequestBatch(models.Model): 'is_void': False, 'text': f"请假审批" }) - if self.users_id.employee_ids.company_id.name == '集团本部': - overtime_records = self.env['vacation.over.line'].search([ + ('start_time', '>=', datetime(2025, 12, 1)), + domain = [ ('employee_id', '=', self.users_id.employee_ids.id), - ('start_time', '>=', datetime(2025, 12, 1)), ('is_visible', '=', False), ('is_void', '=', False), ('text', '!=', '上月继承额度'), - ], order='start_time ASC') - + ] + if self.users_id.employee_ids.company_id.name == '集团本部': + domain.append(('start_time', '>=', datetime(2025, 12, 1)),) + overtime_records = self.env['vacation.over.line'].search(domain, order='start_time ASC') remaining_deduct = hours for record in overtime_records: if remaining_deduct <= 0: @@ -856,24 +857,57 @@ class HolidaysRequestBatch(models.Model): ('employee_id', '=', record.users_id.employee_ids.id), ('vacation_date', '=', vacation_date.replace(day=1)) ], limit=1) - if not reports_id: record.holiday_allowance = "" continue holiday_configs = [ - ("年假", "previous_year", "remainder_year"), - ("补休", "previous_year1", "remainder_year1"), + ("年假", "previous_year", "year_distribution"), + ("补休", "previous_year1", "this_year1"), ("育儿假", None, "remaining_parental_leave") ] for name, prev_field, curr_field in holiday_configs: parts = [] - if prev_field: - prev_value = getattr(reports_id, prev_field, 0.0) - if prev_value > 0: # 大于0才显示 - parts.append(f"上年结余{prev_value:.0f}天") - curr_value = getattr(reports_id, curr_field, 0.0) - if curr_value > 0: - parts.append(f"本年剩余{curr_value:.0f}天") + # ========== 核心修改:年假专属扣减逻辑 ========== + if name == "年假" and prev_field and curr_field: + used_this_year = getattr(reports_id, 'used_this_year', 0.0) # 本年已用 + prev_value = getattr(reports_id, prev_field, 0.0) # 上年结余(previous_year) + curr_value = getattr(reports_id, curr_field, 0.0) # 本年额度(year_distribution) + valid_date = getattr(reports_id, 'valid_date', None) # previous_year的有效期 + + is_prev_valid = True + if valid_date: + is_prev_valid = date.today() <= valid_date + + remain_used = used_this_year + final_prev = prev_value + final_curr = curr_value + + if is_prev_valid and final_prev > 0 and remain_used > 0: + # 扣减previous_year:取剩余已用和previous_year的较小值 + deduct_prev = min(remain_used, final_prev) + final_prev -= deduct_prev + remain_used -= deduct_prev + + # 4. 剩余已用扣减year_distribution + if remain_used > 0 and final_curr > 0: + deduct_curr = min(remain_used, final_curr) + final_curr -= deduct_curr + remain_used -= deduct_curr + + # 5. 根据扣减后的值判断是否显示 + if final_prev > 0: + parts.append(f"上年结余{final_prev:.3f}天") + if final_curr > 0: + parts.append(f"本年剩余{final_curr:.3f}天") + else: + if prev_field: + prev_value = getattr(reports_id, prev_field, 0.0) + if prev_value > 0: + parts.append(f"上年结余{prev_value:.3f}天") + curr_value = getattr(reports_id, curr_field, 0.0) + if curr_value > 0: + parts.append(f"本年剩余{curr_value:.3f}天") + if parts: result_parts.append(f"{name}:{','.join(parts)}") diff --git a/yuthon_hr_attendance/models/card_approval.py b/yuthon_hr_attendance/models/card_approval.py index 8411d2866..ed5023e46 100644 --- a/yuthon_hr_attendance/models/card_approval.py +++ b/yuthon_hr_attendance/models/card_approval.py @@ -23,7 +23,7 @@ class CardApprovals(models.Model): reason_application = fields.Text(string="申请事由") documents_ids = fields.Many2many('ir.attachment', string="附件") attendance_id = fields.Many2one('hr.attendance', string="补卡日期") - number_cards_replaced = fields.Integer(string="已补卡次数") + number_cards_replaced = fields.Integer(string="本月补卡次数", compute='_compute_number_cards_replaced') attendance = fields.Char(string="补卡日期") is_attendance = fields.Boolean(string="字段隐藏") replacement_time = fields.Selection([('work', '上班卡'), ('quitting', '下班卡'), ('all', '全天卡')], string="补卡", store=True) @@ -38,6 +38,27 @@ class CardApprovals(models.Model): name_title = fields.Char(default=_get_default_name_title) self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])]) + @api.depends('users_id') + def _compute_number_cards_replaced(self): + first_day = fields.Date.today().replace(day=1) + vacation_report = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', self.users_id.employee_ids.id), + ('vacation_date', '=', first_day), + ], limit=1) + if vacation_report: + self.number_cards_replaced = vacation_report.number_card + + @api.constrains("users_id") + def _check_user(self): + first_day = fields.Date.today().replace(day=1) + vacation_report = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', self.users_id.employee_ids.id), + ('vacation_date', '=', first_day), + ], limit=1) + if vacation_report: + if vacation_report.number_card >= 3: + raise UserError("该员工当月已补卡超过3次,请勿重复补卡!") + @api.onchange('attendance_id') def onchange_replacement_time(self): for rep in self: @@ -119,6 +140,14 @@ class CardApprovals(models.Model): 'workflow_id': workflow_id, }) + first_day = fields.Date.today().replace(day=1) + vacation_report = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', self.users_id.employee_ids.id), + ('vacation_date', '=', first_day), + ], limit=1) + if vacation_report: + vacation_report.number_card += 1 + @api.onchange('is_issues') def _onchange_is_issues(self): if self.is_issues: diff --git a/yuthon_hr_attendance/models/overtime_approval.py b/yuthon_hr_attendance/models/overtime_approval.py index 6d0b44506..46858a0c9 100644 --- a/yuthon_hr_attendance/models/overtime_approval.py +++ b/yuthon_hr_attendance/models/overtime_approval.py @@ -33,7 +33,7 @@ class OvertimeApprovals(models.Model): documents_ids = fields.Many2many('ir.attachment', string="附件") overtime_methods = fields.Selection([('leave', '补休'), ('fee', '加班费结算')], string='加班补偿方式', default='leave') duration = fields.Float(string="结算时长", compute='_compute_duration', store=True) - overtime_hours = fields.Float(string="本月加班时长", compute='_compute_duration') + overtime_hours = fields.Float(string="本月加班时长", compute='_compute_overtime_hours') start_time = fields.Datetime(string="开始时间") attendance_id = fields.Many2one('hr.attendance', string="当天考勤") start_week = fields.Char(string="星期", compute='_compute_weekday') @@ -141,12 +141,30 @@ class OvertimeApprovals(models.Model): corrected_end_time = max_allowed_end_time - timedelta(hours=8) rec.end_time = corrected_end_time + @api.depends('users_id', 'duration') + def _compute_overtime_hours(self): + for rec in self: + employee = rec.users_id.employee_ids + # 一个月加班时长不能超过36小时 + first_day = fields.Date.today().replace(day=1) + vacation_report = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', employee.id), + ('vacation_date', '=', first_day), + ], limit=1) + + cop_leave = vacation_report.done_working_overtime * 8 if vacation_report else 0.0 + if cop_leave + rec.duration > 36 and not rec.is_thwg: + rec.overtime_hours = 0.0 + message = f'本月已加班时长已超过 36 小时' + raise ValidationError(message) + else: + rec.overtime_hours = cop_leave + @api.depends('start_time', 'end_time', 'attendance_id', 'rest_start_time', 'rest_end_time') def _compute_duration(self): for rec in self: max_hours = 99 rec.duration = 0.0 - rec.overtime_hours = 0.0 if not (rec.start_time and rec.end_time): continue @@ -195,27 +213,6 @@ class OvertimeApprovals(models.Model): calculated_hours -= (rec.rest_end_time - rec.rest_start_time).total_seconds() / 3600 rec.duration = min(calculated_hours, max_hours) - employee = rec.users_id.employee_id - if not employee: - rec.duration = calculated_hours - continue - - # 一个月加班时长不能超过36小时 - first_day = rec.start_time.date().replace(day=1) - vacation_report = self.env['yuthon.vacation.reports'].search([ - ('employee_id', '=', employee.id), - ('vacation_date', '=', first_day), - ], limit=1) - - cop_leave = vacation_report.done_working_overtime * 8 if vacation_report else 0.0 - leave_hours = calculated_hours - if cop_leave + leave_hours > 36 and not rec.is_thwg: - rec.overtime_hours = 0.0 - message = f'本月已加班时长已超过 36 小时' - raise ValidationError(message) - else: - rec.overtime_hours = cop_leave - @api.depends('start_time', 'end_time') def _compute_weekday(self): diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml index 0be38da25..39f88fb1b 100644 --- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml +++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml @@ -198,6 +198,9 @@ + + + @@ -616,24 +619,6 @@ - - vacation.over.line.overtime.briefly.tree - vacation.over.line - - - - - - - - - - - -