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: