diff --git a/yuthon_hr_attendance/__manifest__.py b/yuthon_hr_attendance/__manifest__.py
index f2b41a42c..9afb7c4d6 100644
--- a/yuthon_hr_attendance/__manifest__.py
+++ b/yuthon_hr_attendance/__manifest__.py
@@ -70,6 +70,7 @@
'wizard/hr_attendance_month_wizard_views.xml',
+ 'wizard/pay_carryover_wizard_views.xml',
'wizard/yuthon_delete_planning_wizard_views.xml',
'wizard/attendance_controls_wizard.xml',
'wizard/attendance_correct_wizard.xml',
diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
index cb9cca8f3..79ab8cc95 100644
--- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py
+++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py
@@ -103,16 +103,18 @@ class YuthonVacationReports(models.Model):
)
records.write({'vacation_state': 'not_sent'})
- def update_wg_is_confirm(self):
+ def update_is_confirm(self):
records = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id', self.ids))
)
- for record in records:
- inherit_vals = {
- 'year_distribution': record.leave,
- 'year_workday': record.working_overtime,
- }
- record.write(inherit_vals)
+ overtime_records = self.env['vacation.over.line'].search([
+ ('vacation_id', 'in', records.ids),
+ ('text', '=', '上月额度继承'),
+ ])
+ if overtime_records:
+ overtime_records.write({
+ 'is_initial_number': True
+ })
def write(self, vals):
result = super(YuthonVacationReports, self).write(vals)
@@ -327,7 +329,7 @@ class YuthonVacationReports(models.Model):
rec.actual_attendance = max(actual_attendance + statutory_days, 0)
rec.att_mount = actual_attendance
- def update_is_confirm(self):
+ def update_is_confirm1(self):
records = self.env["yuthon.vacation.reports"].browse(
self._context.get('active_ids', self._context.get('active_id', self.ids))
)
@@ -946,6 +948,7 @@ class VacationOverline(models.Model):
overtime_methods = fields.Selection([('leave', '补休'), ('fee', '加班费结算')], string='加班补偿方式', default='leave')
text = fields.Text(string='备注')
is_confirm = fields.Boolean(string="是否确认")
+ is_initial_number = fields.Boolean(string="初始额度")
overtime_name = fields.Char(string="标题", compute="_compute_overtime", store=True)
start_time = fields.Datetime(string="开始时间", compute="_compute_overtime", store=True)
@@ -981,22 +984,30 @@ class VacationOverline(models.Model):
elif not rec.employee_id:
rec.employee_id = False
- @api.depends('workflow_record_id')
+ @api.depends('workflow_record_id', 'is_initial_number', 'workday')
def _compute_overtime(self):
for rec in self:
- if rec.workflow_record_id and rec.update_type == 'add':
+ rec.overtime_name = ''
+ rec.start_time = False
+ rec.end_time = False
+ rec.duration = 0
+
+ if rec.is_initial_number:
+ rec.duration = rec.workday or 0
+ rec.overtime_name = '2025年12月结余初始数'
+ rec.start_time = datetime(2025, 12, 1, 1, 0, 0)
+ rec.end_time = datetime(2025, 12, 1, 9, 0, 0)
+
+ elif rec.workflow_record_id and rec.update_type == 'add':
res_model = rec.workflow_record_id.res_model
res_id = rec.workflow_record_id.res_id
- overtime_id = rec.env[res_model].search([('id', '=', res_id)])
- rec.overtime_name = overtime_id.name
- rec.start_time = overtime_id.start_time
- rec.end_time = overtime_id.end_time
- rec.duration = overtime_id.duration
- else:
- rec.overtime_name = ''
- rec.start_time = ''
- rec.end_time = ''
- rec.duration = 0
+ if res_model and res_id and res_model in self.env:
+ overtime_id = rec.env[res_model].search([('id', '=', res_id)], limit=1)
+ if overtime_id:
+ rec.overtime_name = overtime_id.name or ''
+ rec.start_time = overtime_id.start_time or ''
+ rec.end_time = overtime_id.end_time or ''
+ rec.duration = overtime_id.duration or 0
def action_void(self):
self.is_void = True
diff --git a/yuthon_hr_attendance/security/ir.model.access.csv b/yuthon_hr_attendance/security/ir.model.access.csv
index 979eba957..cdc58f6eb 100644
--- a/yuthon_hr_attendance/security/ir.model.access.csv
+++ b/yuthon_hr_attendance/security/ir.model.access.csv
@@ -84,4 +84,5 @@ access_applet_security_quick_perm_wizard,access_applet_security_quick_perm_wizar
access_vacation_reports_wizard,vacation.reports.wizard,model_vacation_reports_wizard,base.group_user,1,1,1,1
access_yuthon_holiday_statement,access_yuthon_holiday_statement,model_yuthon_holiday_statement,base.group_user,1,1,1,1
-access_yuthon_meal_case,access_yuthon_meal_case,model_yuthon_meal_case,base.group_user,1,1,1,1
\ No newline at end of file
+access_yuthon_meal_case,access_yuthon_meal_case,model_yuthon_meal_case,base.group_user,1,1,1,1
+access_pay_carryover_wizard,pay.carryover.wizard,model_pay_carryover_wizard,base.group_user,1,1,1,1
\ No newline at end of file
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 a545b4b9a..26329d388 100644
--- a/yuthon_hr_attendance/static/src/js/button_vacation_put.js
+++ b/yuthon_hr_attendance/static/src/js/button_vacation_put.js
@@ -33,6 +33,19 @@ export class CustomAttendanceVacationPutController extends ListController {
context: {},
});
}
+
+ openPayCarryoverWizard(){
+ this.actionService.doAction({
+ type: 'ir.actions.act_window',
+ res_model: 'pay.carryover.wizard',
+ name: '加班费结转弹窗',
+ view_mode: 'form',
+ view_type: 'form',
+ views: [[false, 'form']],
+ target: 'new', // 以弹窗形式打开
+ context: {},
+ });
+ }
}
registry.category("views").add("custom_vacation_put_button", {
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 828a3c312..7586f0994 100644
--- a/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml
+++ b/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml
@@ -11,5 +11,10 @@
批量发送
+
+
+
diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
index b7afc8b20..51ad09346 100644
--- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
+++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml
@@ -542,7 +542,7 @@
加班情况
vacation.over.line
tree
- [('workflow_record_id','!=', False), ('update_type', '=', 'add')]
+ ['|', ('workflow_record_id','!=', False), ('is_initial_number', '=', True), ('update_type', '=', 'add')]
@@ -603,13 +603,6 @@
code
action = model.update_is_confirm()
-
- wg一次性
-
-
- code
- action = model.update_wg_is_confirm()
-
更新报表
diff --git a/yuthon_hr_attendance/wizard/__init__.py b/yuthon_hr_attendance/wizard/__init__.py
index 64fc3344d..d498d8fea 100644
--- a/yuthon_hr_attendance/wizard/__init__.py
+++ b/yuthon_hr_attendance/wizard/__init__.py
@@ -10,3 +10,4 @@ from . import vacation_confirm_wizard
from . import vacation_put_wizard
from . import applet_security_quick_perm_wizard
from . import vacation_reports_wizard
+from . import pay_carryover_wizard
diff --git a/yuthon_hr_attendance/wizard/pay_carryover_wizard.py b/yuthon_hr_attendance/wizard/pay_carryover_wizard.py
new file mode 100644
index 000000000..270c06774
--- /dev/null
+++ b/yuthon_hr_attendance/wizard/pay_carryover_wizard.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+import calendar
+
+from dateutil.relativedelta import relativedelta
+
+from odoo import models, api, fields, _
+from odoo.tools.float_utils import float_round
+from odoo.exceptions import ValidationError, UserError
+from datetime import date
+from datetime import timedelta
+from datetime import datetime, time
+
+
+class PayCarryoverWizard(models.TransientModel):
+ _name = 'pay.carryover.wizard'
+ _description = '加班费结转'
+
+ select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
+ ('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
+ ('9', '九月'), ('10', '十月'), ('11', '十一月'),
+ ('12', '十二月')], string='选择月份',
+ default=lambda self: self._get_default_month())
+ select_year = fields.Selection(selection=[(str(i), str(i)) for i in range(2024, 2060)], string='选择年份',
+ default=lambda self: str(datetime.now().year))
+
+ def action_confirm(self):
+ year = int(self.select_year)
+ month = int(self.select_time)
+ vacation_date = datetime(year, month, 1).date()
+ reports = self.env["yuthon.vacation.reports"].search([('vacation_date', '=', vacation_date),
+ ('employee_id.name', '=', '易尚廉')
+ ])
+ is_2025_december = (year == 2026 and month == 1)
+ for rec in reports:
+ if rec.overtime_ids:
+ for overtime in rec.overtime_ids:
+ if overtime.text == '上月额度继承' and overtime.workday > 40:
+ reduce_workday = overtime.workday - 40
+ new_overtime = self.env['vacation.over.line'].create([{
+ 'vacation_id': rec.id,
+ 'employee_id': overtime.employee_id.id,
+ 'department_id': overtime.department_id.id,
+ 'update_type': 'reduce',
+ 'workday': reduce_workday,
+ 'update_date': fields.Date.today(),
+ 'is_void': False,
+ 'overtime_methods': 'fee',
+ 'text': f'{self.select_time}月份加班结算',
+ }])
+ if is_2025_december and overtime.is_initial_number:
+ overtime.write({
+ 'carry_forward_quantity': reduce_workday,
+ 'carry_forward_state': 'partial',
+ 'carry_forward_date': fields.Date.today()
+ })
+ else:
+ overtime_records = self.env['vacation.over.line'].search([
+ ('employee_id', '=', self.users_id.employee_ids.id),
+ ('start_time', '>=', datetime(2026, 1, 1)),
+ ('remaining_quantity', '>', 0),
+ ('is_void', '=', False),
+ ('text', '!=', '上月继承额度'),
+ ], order='start_time ASC')
+ remaining_deduct = reduce_workday
+ for record in overtime_records:
+ if remaining_deduct <= 0:
+ break
+ current_remaining = record.remaining_quantity
+ deduct_amount = min(remaining_deduct, current_remaining)
+ if remaining_deduct > current_remaining:
+ carry_state = 'partial'
+ else:
+ carry_state = 'completed'
+ record.write({
+ 'carry_forward_date': fields.Date.to_string(fields.Date.today()),
+ 'carry_forward_quantity': deduct_amount,
+ 'carry_forward_state': carry_state,
+ })
+ remaining_deduct -= deduct_amount
+
+ def _get_default_month(self):
+ current_month = datetime.now().month
+ return str(current_month)
diff --git a/yuthon_hr_attendance/wizard/pay_carryover_wizard_views.xml b/yuthon_hr_attendance/wizard/pay_carryover_wizard_views.xml
new file mode 100644
index 000000000..958abc55a
--- /dev/null
+++ b/yuthon_hr_attendance/wizard/pay_carryover_wizard_views.xml
@@ -0,0 +1,19 @@
+
+
+
+ pay.carryover.wizard
+ pay.carryover.wizard
+
+
+
+
+
diff --git a/yuthon_official/models/yuthon_official.py b/yuthon_official/models/yuthon_official.py
index 9c72cb626..253207519 100644
--- a/yuthon_official/models/yuthon_official.py
+++ b/yuthon_official/models/yuthon_official.py
@@ -80,7 +80,7 @@ class YuthonOfficial(models.Model):
def end_approval(self):
self.write({'work_end': True})
- if self.main_flats_id.name == '广州市天河投资集团有限公司':
+ if any(flat.name == '广州市天河投资集团有限公司' for flat in self.main_flats_ids):
process_id = self.env['yuthon.sub.enterprises'].search([('issuance_process_id', '=', self.id)])
all_document_ids = list(self.official_documents_ids.ids)
for log in self.log_ids: