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 @@
-
+
diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
index 87b2bed10..0be38da25 100644
--- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
+++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
@@ -659,7 +659,7 @@
vacation.over.line.overtime.search
vacation.over.line
-
+
@@ -676,7 +676,7 @@
- 加班情况
+ 加班明细
vacation.over.line
tree
['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type',
@@ -732,7 +732,7 @@
yuthon.vacation.reports
tree,form
[('is_filing','=', False)]
- {'search_default_now_month': 1, 'search_default_group_by_employee_id':1}
+ {'search_default_now_month': 1}