diff --git a/akl_multi_tab_plugin/static/src/akl_action_container.scss b/akl_multi_tab_plugin/static/src/akl_action_container.scss index f9c4f4b8b..c54b8b376 100644 --- a/akl_multi_tab_plugin/static/src/akl_action_container.scss +++ b/akl_multi_tab_plugin/static/src/akl_action_container.scss @@ -1,6 +1,7 @@ .akl_controller_container { overflow-y: hidden; flex: 1 1 auto; + z-index: 1; .o_view_controller { display: flex; diff --git a/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss b/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss index d07f8d598..6faae2ff6 100644 --- a/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss +++ b/k_ry_mobile_form/static/src/scss/status_bar_buttons.scss @@ -52,4 +52,7 @@ .o_form_view { padding-bottom: 80px; // 为底部悬浮栏预留空间 } + .o_content .o_form_statusbar { + position: relative !important; + } } diff --git a/soong_workflow/__manifest__.py b/soong_workflow/__manifest__.py index c38276846..5dc525e70 100644 --- a/soong_workflow/__manifest__.py +++ b/soong_workflow/__manifest__.py @@ -48,6 +48,7 @@ 'soong_workflow/static/src/css/record_scss.scss', 'soong_workflow/static/src/css/button_css.scss', 'soong_workflow/static/src/css/urgency_level.scss', + # 'soong_workflow/static/src/css/approval.scss', 'soong_workflow/static/src/js/view_button.js', 'soong_workflow/static/src/js/select_create_dialog.js', 'soong_workflow/static/src/js/urgency_level_widget.js', diff --git a/soong_workflow/templates/soong_workflow_templates.xml b/soong_workflow/templates/soong_workflow_templates.xml index 7b2195461..556684af9 100644 --- a/soong_workflow/templates/soong_workflow_templates.xml +++ b/soong_workflow/templates/soong_workflow_templates.xml @@ -128,21 +128,21 @@ -
+
- - 节点: - +
+ + 节点: + + + 状态: + +
- 状态: - -
-
- - 经办人: + 经办人:
@@ -150,7 +150,7 @@ 意见:
-
+
附件: diff --git a/soong_workflow/views/soong_workflow_record.xml b/soong_workflow/views/soong_workflow_record.xml index 3da7be2c6..fa310364c 100644 --- a/soong_workflow/views/soong_workflow_record.xml +++ b/soong_workflow/views/soong_workflow_record.xml @@ -364,7 +364,7 @@
-
+
diff --git a/yuthon_base/controllers/phone.py b/yuthon_base/controllers/phone.py index 1182ffedf..e4a948cc0 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': '请求成功'}) + 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/controllers/portal.py b/yuthon_hr_attendance/controllers/portal.py index 5e11248db..f595bfe2c 100644 --- a/yuthon_hr_attendance/controllers/portal.py +++ b/yuthon_hr_attendance/controllers/portal.py @@ -53,7 +53,10 @@ class CustomerPortal(portal.CustomerPortal): @http.route('/phone/vacation/self', type='http', auth="none", csrf=False, cors='*') def phone_vacation_self(self, **kw): - records = request.env['yuthon.vacation.reports'].sudo().search([('employee_id.id', '=', kw.get('employee_id'))]) + users_id = int(kw.get('users_id')) + user = request.env['res.users'].sudo().browse(int(users_id)) + employee_id = user.with_company(user.company_id.id).employee_id.id + records = request.env['yuthon.vacation.reports'].sudo().search([('employee_id.id', '=', employee_id)]) data = {} for record in records: year = record.vacation_date.year 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/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, 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/models/yuthon_overtime_line.py b/yuthon_hr_attendance/models/yuthon_overtime_line.py index cbe92dea1..39804c971 100644 --- a/yuthon_hr_attendance/models/yuthon_overtime_line.py +++ b/yuthon_hr_attendance/models/yuthon_overtime_line.py @@ -2,7 +2,7 @@ from odoo import api, fields, models, tools, _ from datetime import datetime, time, timedelta from odoo.exceptions import UserError from datetime import date, timedelta - +from dateutil.relativedelta import relativedelta class YuthonOvertimeLine(models.Model): @@ -36,18 +36,25 @@ class YuthonOvertimeLine(models.Model): self.ensure_one() current_year = int(self.select_year) current_month = int(self.select_month) - cutoff_date = date(current_year, current_month, 1) + cutoff_date = date(current_year, current_month, 1) + relativedelta(months=1) - timedelta(days=1) cutoff_dt = datetime.combine(cutoff_date, datetime.min.time()) domain = [ ('start_time', '<', cutoff_dt), ('remaining_quantity', '!=', 0.0), ('employee_id', '=', self.employee_id.id) ] - if current_year <= 2025 and self.employee_id.company_id.name == '集团本部': + if self.employee_id.company_id.name == '集团本部': domain = [ ('employee_id', '=', self.employee_id.id), - ('is_initial_number', '=', True), ('remaining_quantity', '!=', 0.0), + '|', + ('is_initial_number', '=', True), + '&', ('is_initial_number', '=', False), + '&', ('update_type', '=', 'add'), + '&', ('workflow_record_id', '!=', False), + '&', ('start_time', '>=', '2025-12-01 00:00:00'), + '&', ('vacation_id', '!=', False), + ('start_time', '<', cutoff_dt) ] tree_id = self.env.ref("yuthon_hr_attendance.view_yuthon_vacation_overtime_tree").id diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 60d4e374b..b820bebc1 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") @@ -44,6 +46,7 @@ class YuthonVacationReports(models.Model): parenting_line_ids = fields.One2many('vacation.parenting.line', 'vacation_id', string='育儿假明细') other_fee_ids = fields.One2many('vacation.other.line', 'vacation_id', string='其他明细') 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') done_leave = fields.Float(string='年假', compute='_compute_leave', store=True, digits=(16, 3), group_operator=None) done_working_overtime = fields.Float(string='加班时', compute='_compute_working_overtime', digits=(16, 3), @@ -255,14 +258,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): @@ -281,7 +285,7 @@ class YuthonVacationReports(models.Model): def action_open(self): self.ensure_one() - target_date = self.vacation_date.replace(day=1) - relativedelta(months=1) + target_date = self.vacation_date.replace(day=1) if target_date.month == 12: next_month = 1 next_year = target_date.year + 1 @@ -338,10 +342,25 @@ class YuthonVacationReports(models.Model): if invalid_overtimes: raise UserError('有加班单未结束,请先结束加班批次') + def update_show_date(self): + records = self.env["yuthon.vacation.reports"].browse( + self._context.get('active_ids', self._context.get('active_id', self.ids)) + ) + for record in records: + record._compute_display_date() + + def update_state(self): + records = self.env["yuthon.vacation.reports"].browse( + self._context.get('active_ids', self._context.get('active_id', self.ids)) + ) + for record in records: + record.vacation_state = 'not_sent' + @api.depends('vacation_date') def _compute_display_date(self): for rec in self: - rec.display_date = rec.vacation_date.strftime('%Y年%m月') + rec.show_date = rec.vacation_date + relativedelta(months=1) + rec.display_date = (rec.vacation_date).strftime('%Y年%m月') @api.depends('employee_id', 'vacation_date') def compute_attendance_fields(self): @@ -1156,6 +1175,7 @@ class YuthonVacationReports(models.Model): if create_vals: self.env['yuthon.overtime.line'].create(create_vals) + @api.model def overtime_line(self): self.env['yuthon.overtime.line'].search([]).unlink() today = date.today() @@ -1240,13 +1260,12 @@ class YuthonVacationReports(models.Model): return { "name": _("加班明细"), "type": "ir.actions.act_window", - "view_mode": "tree", + "views": [(False, "tree")], "res_model": "yuthon.overtime.line", "target": "current", } - class VacationLeaveLine(models.Model): _name = 'vacation.leave.line' _description = '年假明细' @@ -1288,6 +1307,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 +1379,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='是否作废') @@ -1375,7 +1403,7 @@ class VacationOverline(models.Model): ],string='结转状态', default='pending', ) - remaining_quantity = fields.Float(string='剩余数', compute="_compute_last_balance", store=True) + remaining_quantity = fields.Float(string='剩余数', compute="_compute_last_balance") def open_record1(self): tree_id = self.env.ref("yuthon_hr_attendance.view_yuthon_vacation_overtime_tree").id @@ -1458,13 +1486,12 @@ class VacationOverline(models.Model): rec._compute_employee_id() rec._compute_last_balance() - @api.depends('vacation_id') + @api.depends('vacation_id', 'carry_forward_quantity', 'duration') 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.duration - rec.carry_forward_quantity else: rec.last_balance = 0 @@ -1528,18 +1555,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 +1612,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) diff --git a/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js b/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js index 8e1b50e08..45b5533fe 100644 --- a/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js +++ b/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js @@ -13,9 +13,11 @@ export class CustomAttendanceVacationConfirmController extends ListController { } async getNextAction(lock_type) { await this.orm.call('yuthon.vacation.reports', 'next_month', []); + this.model.root.load() } async getLastAction(lock_type) { await this.orm.call('yuthon.vacation.reports', 'last_month', []); + this.model.root.load() } } diff --git a/yuthon_hr_attendance/static/src/js/button_vacation_put.js b/yuthon_hr_attendance/static/src/js/button_vacation_put.js index cf4d73925..e842c7e27 100644 --- a/yuthon_hr_attendance/static/src/js/button_vacation_put.js +++ b/yuthon_hr_attendance/static/src/js/button_vacation_put.js @@ -39,10 +39,9 @@ export class CustomAttendanceVacationPutController extends ListController { }); } - - async getAction() { - await this.orm.call('yuthon.vacation.reports', 'overtime_line', []); + const res = await this.orm.call('yuthon.vacation.reports', 'overtime_line', []); + this.actionService.doAction(res) } openYuthonVacationWizard() { diff --git a/yuthon_hr_attendance/views/vacation_overtime_active_views.xml b/yuthon_hr_attendance/views/vacation_overtime_active_views.xml index 4f793552b..b736954bc 100644 --- a/yuthon_hr_attendance/views/vacation_overtime_active_views.xml +++ b/yuthon_hr_attendance/views/vacation_overtime_active_views.xml @@ -15,10 +15,19 @@ + + vacation.overtime.active.search + vacation.overtime.active + + + + + + 加班情况(归档) vacation.overtime.active - tree + tree,search \ No newline at end of file diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml index 0be38da25..8c5fbf16c 100644 --- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml +++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml @@ -75,7 +75,7 @@ - + @@ -128,7 +128,7 @@ - + @@ -198,6 +198,9 @@ + + + @@ -384,7 +387,7 @@ - + @@ -412,8 +415,8 @@ yuthon.vacation.reports - + @@ -424,12 +427,12 @@ + context="{'group_by': 'show_date:year'}"/> + context="{'group_by': 'show_date:month'}"/> - + @@ -616,24 +619,6 @@ - - vacation.over.line.overtime.briefly.tree - vacation.over.line - - - - - - - - - - - -