diff --git a/yuthon_hr_attendance/models/yuthon_overtime_line.py b/yuthon_hr_attendance/models/yuthon_overtime_line.py index 6c0d97cc1..cbe92dea1 100644 --- a/yuthon_hr_attendance/models/yuthon_overtime_line.py +++ b/yuthon_hr_attendance/models/yuthon_overtime_line.py @@ -10,14 +10,53 @@ class YuthonOvertimeLine(models.Model): _description = '加班明细' employee_id = fields.Many2one('hr.employee', string="员工") + select_month = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'), + ('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'), + ('9', '九月'), ('10', '十月'), ('11', '十一月'), + ('12', '十二月')], string='月份', + default=lambda self: str(datetime.now().month)) + select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2060)], string='年份', + default=lambda self: str(datetime.now().year)) last_balance = fields.Float(string="上年结余") valid_date = fields.Date(string="有效至") workday = fields.Float(string='工作日') public_holidays = fields.Float(string='公休日') - vacation_sum = fields.Float(string='合计数') + vacation_sum = fields.Float(string='合计数', compute='_compute_vacation_sum') carry_forward_quantity = fields.Float(string="结转时长") carry_forward_date = fields.Date(string="结转日期") - remaining_quantity = fields.Float(string="剩余数") + remaining_quantity = fields.Float(string="剩余数", compute='_compute_vacation_sum') + + @api.depends('workday', 'public_holidays', 'last_balance', 'carry_forward_quantity') + def _compute_vacation_sum(self): + for rec in self: + rec.vacation_sum = rec.public_holidays + rec.workday + rec.last_balance + rec.remaining_quantity = rec.vacation_sum - rec.carry_forward_quantity def open_record(self): - pass \ No newline at end of file + self.ensure_one() + current_year = int(self.select_year) + current_month = int(self.select_month) + cutoff_date = date(current_year, current_month, 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 == '集团本部': + domain = [ + ('employee_id', '=', self.employee_id.id), + ('is_initial_number', '=', True), + ('remaining_quantity', '!=', 0.0), + ] + + tree_id = self.env.ref("yuthon_hr_attendance.view_yuthon_vacation_overtime_tree").id + return { + 'views': [[tree_id, 'tree']], + 'name': f'加班明细', + 'type': 'ir.actions.act_window', + 'res_model': 'vacation.over.line', + 'view_mode': 'tree,form', + 'domain': domain, + 'target': 'current' + } \ No newline at end of file diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 86f239173..60d4e374b 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -1006,6 +1006,246 @@ class YuthonVacationReports(models.Model): "view_mode": "form", } + @api.model + def last_month(self): + base_line = self.env['yuthon.overtime.line'].search([], order='create_date asc', limit=1) + base_year = int(base_line.select_year) + base_month = int(base_line.select_month) + base_date = date(base_year, base_month, 1) + self.env['yuthon.overtime.line'].search([]).unlink() + # 上上个月第一天(用于select_month赋值) + last_month_first = (base_date - relativedelta(months=2)).replace(day=1) + # 上上个月最后一天(时间筛选的截止点) + current_month_last = (base_date - relativedelta(months=1)).replace(day=1) - timedelta(days=1) + current_month_last_dt = datetime.combine(current_month_last, datetime.min.time()) + if self.env.user.company_id.name == '集团本部': + domain = [ + ('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', '<', current_month_last_dt) + ] + else: + domain = [ + ('workflow_record_id', '!=', False), + ('update_type', '=', 'add'), + ('remaining_quantity', '!=', 0.0), + ('start_time', '<', current_month_last_dt) + ] + over_lines = self.env['vacation.over.line'].search(domain) + if not over_lines: + return + + employee_summary = {} + for line in over_lines: + emp_id = line.employee_id.id + if not emp_id: + continue + + if emp_id not in employee_summary: + employee_summary[emp_id] = { + 'employee_id': emp_id, + 'last_balance': line.last_balance, + 'valid_date': line.valid_date, + 'workday': 0.0, + 'public_holidays': 0.0, + 'carry_forward_quantity': 0.0, + 'carry_forward_date': line.carry_forward_date, + 'remaining_quantity': 0.0, + 'select_month': str(last_month_first.month), + 'select_year': str(last_month_first.year) + } + + summary = employee_summary[emp_id] + if line.is_initial_number: + summary['workday'] += (line.workday or 0.0) - (line.last_balance or 0.0) + else: + summary['workday'] += line.workday or 0.0 + + summary['public_holidays'] += line.public_holidays or 0.0 + summary['carry_forward_quantity'] += line.carry_forward_quantity or 0.0 + + create_vals = [] + for emp_id, vals in employee_summary.items(): + create_vals.append(vals) + if create_vals: + self.env['yuthon.overtime.line'].create(create_vals) + + @api.model + def next_month(self): + base_line = self.env['yuthon.overtime.line'].search([], order='create_date asc', limit=1) + base_year = int(base_line.select_year) + base_month = int(base_line.select_month) + base_date = date(base_year, base_month, 1) + self.env['yuthon.overtime.line'].search([]).unlink() + next_month_first = (base_date + relativedelta(months=1)).replace(day=1) + next_month_last = (base_date + relativedelta(months=2)).replace(day=1) - timedelta(days=1) + next_month_last_dt = datetime.combine(next_month_last, datetime.min.time()) + dec_2025_end = datetime(2025, 12, 31, 23, 59, 59) + if self.env.user.company_id.name == '集团本部': + domain = [ + ('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', '<', next_month_last_dt) + ] + else: + domain = [ + ('workflow_record_id', '!=', False), + ('update_type', '=', 'add'), + ('remaining_quantity', '!=', 0.0), + ('start_time', '<', next_month_last_dt) + ] + over_lines = self.env['vacation.over.line'].search(domain) + if not over_lines: + return + + filtered_lines = [] + for line in over_lines: + if not line.is_initial_number and line.start_time <= dec_2025_end: + continue + filtered_lines.append(line) + + if not filtered_lines: + return + + employee_summary = {} + for line in filtered_lines: + emp_id = line.employee_id.id + if not emp_id: + continue + + # 初始化员工汇总数据 + if emp_id not in employee_summary: + employee_summary[emp_id] = { + 'employee_id': emp_id, + 'last_balance': line.last_balance, + 'valid_date': line.valid_date, + 'workday': 0.0, + 'public_holidays': 0.0, + 'carry_forward_quantity': 0.0, + 'carry_forward_date': line.carry_forward_date, + 'select_month': str(next_month_first.month), + 'select_year': str(next_month_first.year) + } + + summary = employee_summary[emp_id] + if line.is_initial_number: + # 初始数据:workday = 本条workday - 本条last_balance + summary['workday'] += (line.workday or 0.0) - (line.last_balance or 0.0) + else: + # 非初始数据:正常累加workday(原有逻辑) + summary['workday'] += line.workday or 0.0 + + summary['public_holidays'] += line.public_holidays or 0.0 + summary['carry_forward_quantity'] += line.carry_forward_quantity or 0.0 + + create_vals = [] + for emp_id, vals in employee_summary.items(): + create_vals.append(vals) + if create_vals: + self.env['yuthon.overtime.line'].create(create_vals) + + def overtime_line(self): + self.env['yuthon.overtime.line'].search([]).unlink() + today = date.today() + last_month_first = (today - relativedelta(months=1)).replace(day=1) + current_month_first = today.replace(day=1) + current_month_first_dt = datetime.combine(current_month_first, datetime.min.time()) + dec_2025_end = datetime(2025, 12, 31, 23, 59, 59) + + # 原有domain(先筛选出基础数据) + if self.env.user.company_id.name == '集团本部': + domain = [ + ('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', '<', current_month_first_dt) + ] + else: + domain = [ + ('workflow_record_id', '!=', False), + ('update_type', '=', 'add'), + ('remaining_quantity', '!=', 0.0), + ('start_time', '<', current_month_first_dt) + ] + + over_lines = self.env['vacation.over.line'].search(domain) + if not over_lines: + return + + filtered_lines = [] + for line in over_lines: + # 当前记录不是初始化记录 + start_time在2025-12月底前 → 跳过 + if not line.is_initial_number and line.start_time <= dec_2025_end: + continue + # 其他情况(初始化记录本身 / 无初始化记录 / 非初始化记录但时间在12月底后)→ 保留 + filtered_lines.append(line) + + if not filtered_lines: + return + employee_summary = {} + for line in filtered_lines: + emp_id = line.employee_id.id + if not emp_id: + continue + + if emp_id not in employee_summary: + employee_summary[emp_id] = { + 'employee_id': emp_id, + 'last_balance': line.last_balance, + 'valid_date': line.valid_date, + 'workday': 0.0, + 'public_holidays': 0.0, + 'vacation_sum': 0.0, + 'carry_forward_quantity': 0.0, + 'carry_forward_date': line.carry_forward_date, + 'select_month': str(last_month_first.month), + 'select_year': str(last_month_first.year) + } + + summary = employee_summary[emp_id] + if line.is_initial_number: + # 初始数据:workday = 本条workday - 本条last_balance + summary['workday'] += (line.workday or 0.0) - (line.last_balance or 0.0) + else: + # 非初始数据:正常累加workday(原有逻辑) + summary['workday'] += line.workday or 0.0 + + summary['public_holidays'] += line.public_holidays or 0.0 + summary['carry_forward_quantity'] += line.carry_forward_quantity or 0.0 + + create_vals = [] + for emp_id, vals in employee_summary.items(): + create_vals.append(vals) + + if create_vals: + self.env['yuthon.overtime.line'].create(create_vals) + + return { + "name": _("加班明细"), + "type": "ir.actions.act_window", + "view_mode": "tree", + "res_model": "yuthon.overtime.line", + "target": "current", + } + + class VacationLeaveLine(models.Model): _name = 'vacation.leave.line' 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 ef52c8ffa..8e1b50e08 100644 --- a/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js +++ b/yuthon_hr_attendance/static/src/js/button_vacation_confirm.js @@ -12,10 +12,10 @@ export class CustomAttendanceVacationConfirmController extends ListController { await this.orm.call('vacation.over.line', 'confirm', []); } async getNextAction(lock_type) { - await this.orm.call('vacation.meal.line', 'confirm', []); + await this.orm.call('yuthon.vacation.reports', 'next_month', []); } async getLastAction(lock_type) { - await this.orm.call('vacation.meal.line', 'confirm', []); + await this.orm.call('yuthon.vacation.reports', 'last_month', []); } } 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 51b4db269..cf4d73925 100644 --- a/yuthon_hr_attendance/static/src/js/button_vacation_put.js +++ b/yuthon_hr_attendance/static/src/js/button_vacation_put.js @@ -39,17 +39,10 @@ export class CustomAttendanceVacationPutController extends ListController { }); } - openVacationOverWizard() { - this.actionService.doAction({ - type: 'ir.actions.act_window', - res_model: 'yuthon.overtime.line', - name: '加班合计数报表', - view_mode: 'tree', - view_type: 'form', - views: [[false, 'tree']], - target: 'current', - context: {'tree_view_ref': "yuthon_hr_attendance.view_yuthon_overtime_line_tree"}, - }); + + + async getAction() { + await this.orm.call('yuthon.vacation.reports', 'overtime_line', []); } openYuthonVacationWizard() { diff --git a/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml b/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml index 38e5c0581..c7187f397 100644 --- a/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml +++ b/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml @@ -7,7 +7,7 @@ - diff --git a/yuthon_hr_attendance/views/yuthon_overtime_line_views.xml b/yuthon_hr_attendance/views/yuthon_overtime_line_views.xml index 26dd21690..e5274afcc 100644 --- a/yuthon_hr_attendance/views/yuthon_overtime_line_views.xml +++ b/yuthon_hr_attendance/views/yuthon_overtime_line_views.xml @@ -6,6 +6,8 @@ + + @@ -14,7 +16,7 @@ -