diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py index 3f6d42fe6..9c50b91bf 100644 --- a/yuthon_holiday/models/inherit_hr_leave.py +++ b/yuthon_holiday/models/inherit_hr_leave.py @@ -518,62 +518,84 @@ class HolidaysRequestBatch(models.Model): return date_ranges def _create_overtime_leave_line(self, period_start, leave_data, hours, period, leave_type_name): - deduct_days = hours/8 - period_start = period_start.replace(day=1) - 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) - actual_vacation_report = vacation_report - vacation_report1 = self.env['yuthon.vacation.reports'].search([ - ('employee_id', '=', self.users_id.employee_ids.id), - ('vacation_date', '=', period_start), - ], limit=1) - if vacation_report1 and vacation_report1.vacation_state != 'confirmed': - actual_vacation_report = vacation_report1 - existing_overtime_line = self.env['vacation.over.line'].search([ - ('vacation_id', '=', actual_vacation_report.id), - ('employee_id', '=', self.users_id.employee_ids.id), - ('workflow_record_id', '=', leave_data.get('workflow_id', False)), - ('update_type', '=', 'reduce'), - ('text', '=', '请假审批'), - ('is_void', '=', False), - ('workday', '=', hours), - ], limit=1) - if not existing_overtime_line: - self.env['vacation.over.line'].create({ - 'vacation_id': actual_vacation_report.id if actual_vacation_report else False, - 'employee_id': self.users_id.employee_ids.id, - 'workflow_record_id': leave_data['workflow_id'], - 'update_type': 'reduce', - 'workday': hours, - 'legal_day': 0, - 'public_holidays': 0, - 'meal_number': 0, - 'update_date': fields.Date.today(), - 'is_void': False, - 'text': f"请假审批" - }) - ('start_time', '>=', datetime(2025, 12, 1)), - remaining_deduct = deduct_days - actual_vacation_report.used_this_year1 += deduct_days - # 优先扣减上年剩余(补休) - if actual_vacation_report.dynamic_previous_year1 > 0: - if actual_vacation_report.dynamic_previous_year1 >= remaining_deduct: - actual_vacation_report.dynamic_previous_year1 -= remaining_deduct - remaining_deduct = 0.0 - else: - remaining_deduct -= actual_vacation_report.dynamic_previous_year1 - actual_vacation_report.dynamic_previous_year1 = 0.0 - # 剩余部分扣减本年剩余(补休) - if remaining_deduct > 0 and actual_vacation_report.this_year1 > 0: - if actual_vacation_report.this_year1 >= remaining_deduct: - actual_vacation_report.this_year1 -= remaining_deduct - else: - actual_vacation_report.this_year1 = 0.0 - actual_vacation_report._compute_working_overtime() + """ + 创建补休请假扣减记录(跨月自动拆分,分月创建) + :param period_start: 原始周期开始时间(datetime.date) + :param leave_data: 请假数据字典(含workflow_id等) + :param hours: 总请假小时数(float) + :param period: 请假时间段 {'start': date, 'end': date} + :param leave_type_name: 假期类型名称 + """ + employee_id = self.users_id.employee_ids.id if self.users_id.employee_ids else False + leave_start = leave_data['start'] # 请假开始日期(date) + leave_end = leave_data['end'] # 请假结束日期(date) + month_intervals = [] + current_start = leave_start + while current_start <= leave_end: + current_month = current_start.month + current_year = current_start.year + next_month = current_month + 1 if current_month < 12 else 1 + next_year = current_year if current_month < 12 else current_year + 1 + current_month_end = date(next_year, next_month, 1) - timedelta(days=1) + interval_end = min(current_month_end, leave_end) + month_intervals.append({ + 'start': current_start, + 'end': interval_end, + 'period_start': date(current_year, current_month, 1) + }) + current_start = interval_end + timedelta(days=1) + holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '补休')]) + for interval in month_intervals: + interval_start = interval['start'] + interval_end = interval['end'] + interval_hours = self._compute_duration_day(holiday_status_id, interval_start, interval_end) * 8 + + # 跳过小时数为0的无效区间 + if interval_hours <= 1e-6: + continue + period_start = interval['period_start'] # + vacation_report1 = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', employee_id), + ('vacation_date', '=', period_start), + ], limit=1) + 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) + # 确定最终使用的报表 + actual_vacation_report = vacation_report + if vacation_report1 and vacation_report1.vacation_state != 'confirmed': + actual_vacation_report = vacation_report1 + if not actual_vacation_report: + continue + + existing_overtime_line = self.env['vacation.over.line'].search([ + ('vacation_id', '=', actual_vacation_report.id), + ('employee_id', '=', employee_id), + ('workflow_record_id', '=', leave_data.get('workflow_id', False)), + ('update_type', '=', 'reduce'), + ('text', '=', f"请假审批"), + ('is_void', '=', False), + ('workday', '=', interval_hours), + ], limit=1) + if not existing_overtime_line: + self.env['vacation.over.line'].create({ + 'vacation_id': actual_vacation_report.id, + 'employee_id': employee_id, + 'workflow_record_id': leave_data.get('workflow_id', False), + 'update_type': 'reduce', + 'workday': interval_hours, + 'legal_day': 0, + 'public_holidays': 0, + 'meal_number': 0, + 'update_date': fields.Date.today(), + 'is_void': False, + 'text': f"请假审批" + }) + actual_vacation_report.update_line() + actual_vacation_report._compute_working_overtime() domain = [ ('employee_id', '=', self.users_id.employee_ids.id), ('is_visible', '=', False), @@ -601,101 +623,159 @@ class HolidaysRequestBatch(models.Model): }) remaining_deduct -= deduct_amount - def _create_annual_leave_line(self, period_start, leave_data, hours, period): - """更新年假记录,使用小时作为单位(增加重复校验,避免重复创建)""" - deduct_days = hours / 8 - period_start = period_start.replace(day=1) - 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) - actual_vacation_report = vacation_report - vacation_report1 = self.env['yuthon.vacation.reports'].search([ - ('employee_id', '=', self.users_id.employee_ids.id), - ('vacation_date', '=', period_start), - ], limit=1) - if vacation_report1 and vacation_report1.vacation_state != 'confirmed': - actual_vacation_report = vacation_report1 + """ + 创建年假扣减记录(跨月自动拆分,分月创建) + :param period_start: 原始周期开始时间(datetime.date) + :param leave_data: 请假数据字典(含workflow_id等) + :param hours: 总年假请假小时数(float) + :param period: 请假时间段 {'start': date, 'end': date} + :param leave_type_name: 假期类型名称(年假) + """ + employee_id = self.users_id.employee_ids.id if self.users_id.employee_ids else False + leave_start = period['start'] # 年假开始日期(date) + leave_end = period['end'] # 年假结束日期(date) + month_intervals = [] - existing_annual_leave_line = self.env['vacation.leave.line'].search([ - ('vacation_id', '=', actual_vacation_report.id), - ('employee_id', '=', self.users_id.employee_ids.id), - ('workflow_record_id', '=', leave_data.get('workflow_id', False)), - ('update_type', '=', 'reduce'), - ('allocation_type', '=', 'vacation'), - ('update_lines', '=', hours), - ('text', '=', '请假审批'), - ('is_void', '=', False), - ], limit=1) - if not existing_annual_leave_line: - self.env['vacation.leave.line'].create({ - 'vacation_id': actual_vacation_report.id if actual_vacation_report else False, - 'employee_id': self.users_id.employee_ids.id, - 'workflow_record_id': leave_data['workflow_id'], - 'update_type': 'reduce', - 'update_date': fields.Date.today(), - 'update_lines': hours, - 'is_void': False, - 'allocation_type': 'vacation', - 'text': f"请假审批" + current_start = leave_start + while current_start <= leave_end: + current_month = current_start.month + current_year = current_start.year + next_month = current_month + 1 if current_month < 12 else 1 + next_year = current_year if current_month < 12 else current_year + 1 + current_month_end = date(next_year, next_month, 1) - timedelta(days=1) + interval_end = min(current_month_end, leave_end) + month_intervals.append({ + 'start': current_start, + 'end': interval_end, + 'period_start': date(current_year, current_month, 1) }) - actual_vacation_report.used_this_year += deduct_days - remaining_deduct = deduct_days - # 优先扣减上年剩余(年假) - if actual_vacation_report.dynamic_previous_year > 0: - if actual_vacation_report.dynamic_previous_year >= remaining_deduct: - actual_vacation_report.dynamic_previous_year -= remaining_deduct - remaining_deduct = 0.0 - else: - remaining_deduct -= actual_vacation_report.dynamic_previous_year - actual_vacation_report.dynamic_previous_year = 0.0 - # 4.2 剩余部分扣减本年剩余(年假) - if remaining_deduct > 0 and actual_vacation_report.dynamic_remainder_year > 0: - if actual_vacation_report.dynamic_remainder_year >= remaining_deduct: - actual_vacation_report.dynamic_remainder_year -= remaining_deduct - else: - actual_vacation_report.dynamic_remainder_year = 0.0 + current_start = interval_end + timedelta(days=1) + holiday_status_id = self.env['hr.leave.type'].search([('name', '=', '年假')], limit=1) + for interval in month_intervals: + interval_start = interval['start'] + interval_end = interval['end'] + interval_hours = self._compute_duration_day(holiday_status_id, interval_start, interval_end) * 8 + period_start = interval['period_start'] + first_day = fields.Date.today().replace(day=1) + + # 兜底报表(当月1号) + vacation_report = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', employee_id), + ('vacation_date', '=', first_day), + ], limit=1) + actual_vacation_report = vacation_report + + # 优先匹配当月未确认的报表 + vacation_report1 = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', employee_id), + ('vacation_date', '=', period_start), + ], limit=1) + if vacation_report1 and vacation_report1.vacation_state != 'confirmed': + actual_vacation_report = vacation_report1 + if not actual_vacation_report: + continue + + # 3.3 检查当前月的记录是否已存在(避免重复) + existing_annual_leave_line = self.env['vacation.leave.line'].search([ + ('vacation_id', '=', actual_vacation_report.id), + ('employee_id', '=', employee_id), + ('workflow_record_id', '=', leave_data.get('workflow_id', False)), + ('update_type', '=', 'reduce'), + ('allocation_type', '=', 'vacation'), + ('update_lines', '=', interval_hours), + ('text', '=', f"请假审批"), + ('is_void', '=', False), + ], limit=1) + + # 不存在则创建当前月的年假扣减记录 + if not existing_annual_leave_line: + self.env['vacation.leave.line'].create({ + 'vacation_id': actual_vacation_report.id, + 'employee_id': employee_id, + 'workflow_record_id': leave_data['workflow_id'], + 'update_type': 'reduce', + 'update_date': fields.Date.today(), + 'update_lines': interval_hours, + 'is_void': False, + 'allocation_type': 'vacation', + 'text': f"请假审批" + }) + actual_vacation_report.update_line() def _create_other_leave_line(self, period_start, leave_data, days, period, leave_type_name): + """ + 创建其他假减记录(跨月自动拆分) + :param period_start: 原始周期开始时间(datetime.date) + :param leave_data: 请假数据字典(含workflow_id等) + :param days: 总请假天数(浮点型) + :param period: 请假时间段 {'start': date, 'end': date} + :param leave_type_name: 假期类型名称 + """ holiday_type = self.env['hr.leave.type'].search([('name', '=', leave_type_name)], limit=1) - first_day = fields.Date.today().replace(day=1) - period_start = period_start.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) - actual_vacation_report = vacation_report - vacation_report1 = self.env['yuthon.vacation.reports'].search([ - ('employee_id', '=', self.users_id.employee_ids.id), - ('vacation_date', '=', period_start), - ], limit=1) - if vacation_report1 and vacation_report1.vacation_state != 'confirmed': - actual_vacation_report = vacation_report1 + employee_id = self.users_id.employee_ids.id if self.users_id.employee_ids else False + leave_start = period['start'] + leave_end = period['end'] + month_intervals = [] - existing_leave_line = self.env['vacation.other.line'].search([ - ('vacation_id', '=', actual_vacation_report.id), - ('employee_id', '=', self.users_id.employee_ids.id), - ('workflow_record_id', '=', leave_data.get('workflow_id', False)), - ('holiday_type', '=', holiday_type.id), - ('lines', '=', days), - ('update_type', '=', 'reduce'), - ('text', '=', '请假审批'), - ('is_void', '=', False), - ], limit=1) - if not existing_leave_line: - self.env['vacation.other.line'].create({ - 'vacation_id': actual_vacation_report.id if actual_vacation_report else False, - 'employee_id': self.users_id.employee_ids.id, - 'workflow_record_id': leave_data['workflow_id'], - 'update_type': 'reduce', - 'lines': days, - 'holiday_type': holiday_type.id, - 'update_date': fields.Date.today(), - 'is_void': False, - 'text': f"请假审批" + current_start = leave_start + while current_start <= leave_end: + current_month = current_start.month + current_year = current_start.year + next_month = current_month + 1 if current_month < 12 else 1 + next_year = current_year if current_month < 12 else current_year + 1 + current_month_end = date(next_year, next_month, 1) - timedelta(days=1) + interval_end = min(current_month_end, leave_end) + # 加入拆分后的区间列表 + month_intervals.append({ + 'start': current_start, + 'end': interval_end, + 'period_start': date(current_year, current_month, 1) }) + current_start = interval_end + timedelta(days=1) + + # 3. 遍历拆分后的每个月区间,分别创建记录 + for interval in month_intervals: + interval_start = interval['start'] + interval_end = interval['end'] + interval_days = self._compute_duration_day(holiday_type, interval_start, interval_end) + period_start = interval['period_start'] + vacation_report1 = self.env['yuthon.vacation.reports'].search([ + ('employee_id', '=', employee_id), + ('vacation_date', '=', period_start), + ], limit=1) + 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) + actual_vacation_report = vacation_report + if vacation_report1 and vacation_report1.vacation_state != 'confirmed': + actual_vacation_report = vacation_report1 + if not actual_vacation_report: + continue # 无报表,跳过创建 + existing_leave_line = self.env['vacation.other.line'].search([ + ('vacation_id', '=', actual_vacation_report.id), + ('employee_id', '=', employee_id), + ('workflow_record_id', '=', leave_data.get('workflow_id', False)), + ('holiday_type', '=', holiday_type.id), + ('lines', '=', interval_days), + ('update_type', '=', 'reduce'), + ('text', '=', '请假审批'), + ('is_void', '=', False), + ], limit=1) + if not existing_leave_line: + self.env['vacation.other.line'].create({ + 'vacation_id': actual_vacation_report.id, + 'employee_id': employee_id, + 'workflow_record_id': leave_data.get('workflow_id', False), + 'update_type': 'reduce', + 'lines': interval_days, + 'holiday_type': holiday_type.id, + 'update_date': fields.Date.today(), + 'is_void': False, + 'text': f"请假审批" + }) def update_attendance(self, employee_id, start_date, end_date, code): """ @@ -847,8 +927,8 @@ class HolidaysRequestBatch(models.Model): overtime_days = reports_id.working_overtime if total_annual_leave_days > leave_days: raise UserError('年假天数额度不足,无法请假') - if total_compensatory_leave_days > overtime_days: - raise UserError('补休天数额度不足,无法请假') + # if total_compensatory_leave_days > overtime_days: + # raise UserError('补休天数额度不足,无法请假') @api.onchange('leave_ids', 'hour_leave_ids', 'employee_id') diff --git a/yuthon_hr_attendance/models/hr_attendance.py b/yuthon_hr_attendance/models/hr_attendance.py index 522781e5a..0b048de29 100644 --- a/yuthon_hr_attendance/models/hr_attendance.py +++ b/yuthon_hr_attendance/models/hr_attendance.py @@ -264,18 +264,19 @@ class HrAttendance(models.Model): today = date.today() current_year = today.year current_month = today.month - first_day = date(current_year, current_month, 1) - next_month = current_month + 1 if current_month < 12 else 1 - next_year = current_year if current_month < 12 else current_year + 1 - last_day = date(next_year, next_month, 1) - timedelta(days=1) - - # 搜索本月的考勤记录 + if current_month == 1: + last_month = 12 + last_month_year = current_year - 1 + else: + last_month = current_month - 1 + last_month_year = current_year + last_month_first_day = date(last_month_year, last_month, 1) + yesterday = today - timedelta(days=1) attendance_records = self.env['hr.attendance'].search([ - ('current_data', '>=', first_day), - ('current_data', '<=', last_day), + ('current_data', '>=', last_month_first_day), # 上个月1号及以后 + ('current_data', '<=', yesterday), # 昨天及以前(跳过今天) ('shift_name', '!=', '休息') ]) - # 按员工分组,整理异常记录(结构:{员工ID: [异常文案列表, 员工对象]}) employee_abnormal = {} for rec in attendance_records: emp = rec.employee_id @@ -681,10 +682,9 @@ class HrAttendance(models.Model): next_day = current_date + timedelta(days=1) start_datetime = datetime.combine(current_date, datetime.min.time()) - timedelta(hours=8) # 3. 确定有效上下班时间 - if template.check_out_end < template.check_out_start: + check_out_end = self.float_to_datetime(current_date, template.check_out_end) + if template.day2 == '次日': check_out_end = self.float_to_datetime(next_day, template.check_out_end) - else: - check_out_end = self.float_to_datetime(current_date, template.check_out_end) domain = [ ('employee_id', '=', employee_id.id), ('checkin_time', '>=', start_datetime), diff --git a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py index 06a33a526..83bd2075a 100644 --- a/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py +++ b/yuthon_hr_attendance/models/hr_attendance_detail_wechat.py @@ -288,10 +288,9 @@ class HrAttendanceDetail(models.Model): next_day = current_data + timedelta(days=1) start_datetime = datetime.combine(current_data, datetime.min.time()) - timedelta(hours=8) # 判断是否需要包含次日记录 - if template.check_out_end < template.check_out_start: + end_datetime = datetime.combine(current_data, datetime.max.time()) - timedelta(hours=8) + if template.day2 == '次日': end_datetime = datetime.combine(next_day, datetime.max.time()) - timedelta(hours=8) - else: - end_datetime = datetime.combine(current_data, datetime.max.time()) - timedelta(hours=8) # 筛选当前员工当天的打卡记录 domain = [ ('employee_id', '=', employee.id), @@ -302,10 +301,9 @@ class HrAttendanceDetail(models.Model): checkin_times = [rec.checkin_time + timedelta(hours=8) for rec in attendance_records if rec.checkin_time] check_in_start = self.float_to_datetime(current_data, template.check_in_start) - if template.check_in_start > template.check_in_end: + check_in_end = self.float_to_datetime(current_data, template.check_in_end) + if template.day2 == '次日': check_in_end = self.float_to_datetime(next_day, template.check_in_end) - else: - check_in_end = self.float_to_datetime(current_data, template.check_in_end) valid_checkins = [ t for t in checkin_times if check_in_start <= t <= check_in_end @@ -314,11 +312,9 @@ class HrAttendanceDetail(models.Model): # 上班时间:在上班范围内的最小打卡时间 check_in_time = min(valid_checkins) - timedelta(hours=8) if valid_checkins else None check_out_start = self.float_to_datetime(current_data, template.check_out_start) - - if template.check_out_end < template.check_out_start: + check_out_end = self.float_to_datetime(current_data, template.check_out_end) + if template.day2 == '次日': check_out_end = self.float_to_datetime(next_day, template.check_out_end) - else: - check_out_end = self.float_to_datetime(current_data, template.check_out_end) # 筛选在下班时间范围内的打卡记录 valid_checkouts = [t for t in checkin_times if check_out_start <= t <= check_out_end] # 取最大的有效下班时间 diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 21f6f215d..3d77d51f2 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -21,7 +21,7 @@ class YuthonVacationReports(models.Model): year_id = fields.Many2one('base.year', string='年份', compute="_compute_display_date", store=True) employee_id = fields.Many2one('hr.employee', string='员工') number_card = fields.Integer(string='补卡次数') - remaining_number_card = fields.Integer(string='剩余补卡次数', default=4) + remaining_number_card = fields.Integer(string='剩余补卡次数', default=3) 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="参加工作时间") @@ -62,6 +62,7 @@ class YuthonVacationReports(models.Model): working_overtime = fields.Float(string='剩余补休', compute='_compute_working_overtime', store=True, digits=(16, 3), group_operator=None) meal_fee = fields.Float(string="误餐次数", compute='_compute_meal_fee', store=True, group_operator=None) + remain_missed_meals = fields.Float(string="剩余误餐次数", compute='_compute_meal_fee', store=True, group_operator=None) medical_fee = fields.Float(string="体检费", compute='_compute_medical_fee', store=True, group_operator=None) compensatory_leave = fields.Float(string="调休", compute='_compute_other_leave', store=True, group_operator=None) leave_of_absence = fields.Float(string="事假", digits=(16, 3), compute='_compute_other_leave', store=True, @@ -111,6 +112,48 @@ class YuthonVacationReports(models.Model): tracking=3, default='not_sent') + @api.model + def leave_line(self): + today = date.today() + start_date = date(today.year, today.month, 1) + next_month = today.month + 1 if today.month < 12 else 1 + next_year = today.year if today.month < 12 else today.year + 1 + end_date = date(next_year, next_month, 1) - timedelta(days=1) + return { + 'type': 'ir.actions.act_window', + 'name': '请假情况', + "views": [(False, "tree")], + 'res_model': 'hr.leave', + 'domain': [ + ('date_from', '>=', start_date), + ('date_from', '<=', end_date), + ('company_id', 'in', self.env.companies.ids) + ], + 'target': 'current', + 'context': {'tree_view_ref': "yuthon_hr_attendance.view_hr_leave_statement_tree"}, + } + + @api.model + def meal_line(self): + today = date.today() + start_date = date(today.year, today.month, 1) + next_month = today.month + 1 if today.month < 12 else 1 + next_year = today.year if today.month < 12 else today.year + 1 + end_date = date(next_year, next_month, 1) - timedelta(days=1) + return { + 'type': 'ir.actions.act_window', + 'name': '误餐情况', + "views": [(False, "tree")], + 'res_model': 'vacation.meal.line', + 'domain': [ + ('vacation_date', '>=', start_date), + ('vacation_date', '<=', end_date), + ('company_id', 'in', self.env.companies.ids) + ], + 'target': 'current', + 'context': {'tree_view_ref': "yuthon_hr_attendance.view_vacation_meal_line_tree"} + } + def update_vacation_task(self): today = date.today() current_month_first = today.replace(day=1) @@ -118,6 +161,28 @@ class YuthonVacationReports(models.Model): for vacation in vacation_ids: vacation.update_line() + def update_is_visible(self): + target_calendar_names = [ + '行政考勤-本部', + '行政考勤-物管', + '行政考勤-粮储' + ] + target_calendars = self.env['resource.calendar'].search([ + ('name', 'in', target_calendar_names) + ]) + target_employee_ids = set() + if target_calendars: + for calendar in target_calendars: + employee_ids = calendar.resource_user_ids.ids + target_employee_ids.update(employee_ids) + over_ids = self.env["yuthon.vacation.reports"].browse( + self._context.get('active_ids', self._context.get('active_id'))) + for rec in over_ids: + if rec.employee_id.id in target_employee_ids: + rec.remaining_number_card = 0 + else: + rec.remaining_number_card = 3 + def update_line(self): self.manage_reject() @@ -952,6 +1017,19 @@ class YuthonVacationReports(models.Model): 继承核心逻辑 :return: ''' + target_calendar_names = [ + '行政考勤-本部', + '行政考勤-物管', + '行政考勤-粮储' + ] + target_calendars = self.env['resource.calendar'].search([ + ('name', 'in', target_calendar_names) + ]) + target_employee_ids = set() + if target_calendars: + for calendar in target_calendars: + employee_ids = calendar.resource_user_ids.ids + target_employee_ids.update(employee_ids) for rec in self: last_month_last = rec.vacation_date - timedelta(days=1) last_month_first = last_month_last.replace(day=1) @@ -1004,8 +1082,10 @@ class YuthonVacationReports(models.Model): if rec.working_overtime: overtime_hours = rec.working_overtime * 8 self._update_over_lines(rec, [rec], overtime_hours) - if rec.employee_id.company_id.name == '集团本部': - rec.remaining_number_card = 4 + if rec.employee_id.id not in target_employee_ids: + rec.remaining_number_card = 3 + else: + rec.remaining_number_card = 0 if rec.remaining_parental_leave and last_month_record.parenting_line_ids: update_date = last_month_record.parenting_line_ids[0].update_date end_date = last_month_record.parenting_line_ids[0].end_date @@ -1176,14 +1256,17 @@ class YuthonVacationReports(models.Model): @api.depends('meal_fee_ids.update_lines', 'meal_fee_ids.update_type', 'meal_fee_ids.is_void') def _compute_meal_fee(self): for record in self: + meal_add = 0 meal_total = 0 for line in record.meal_fee_ids: if not line.is_void: if line.update_type == 'add': meal_total += int(line.update_lines or 0) + meal_add += int(line.update_lines or 0) elif line.update_type == 'reduce': meal_total -= int(line.update_lines or 0) - record.meal_fee = meal_total + record.meal_fee = meal_add + record.remain_missed_meals = meal_total def all_confirm(self): vacation_ids = self.env["yuthon.vacation.reports"].browse( @@ -1778,12 +1861,6 @@ class VacationOverline(models.Model): else: active_model.create(active_vals) - def update_is_visible(self): - over_ids = self.env["vacation.over.line"].browse( - self._context.get('active_ids', self._context.get('active_id'))) - for rec in over_ids: - rec.is_visible = True - def update_line(self): over_ids = self.env["vacation.over.line"].browse( self._context.get('active_ids', self._context.get('active_id'))) 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 e842c7e27..a4fb129a1 100644 --- a/yuthon_hr_attendance/static/src/js/button_vacation_put.js +++ b/yuthon_hr_attendance/static/src/js/button_vacation_put.js @@ -8,35 +8,9 @@ export class CustomAttendanceVacationPutController extends ListController { super.setup(); } - openHrLeaveWizard() { - const now = new Date(); - const lastMonthYear = now.getMonth() === 0 ? now.getFullYear() - 1 : now.getFullYear(); - const lastMonth = now.getMonth() === 0 ? 11 : now.getMonth() - 1; - const lastMonthFirstDay = new Date(lastMonthYear, lastMonth, 1); - const currentMonthFirstDay = new Date(now.getFullYear(), now.getMonth(), 1); - const formatDate = (date) => { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - return `${year}-${month}-${day} 00:00:00`; - }; - const lastMonthStart = formatDate(lastMonthFirstDay); - const lastMonthEnd = formatDate(currentMonthFirstDay); - this.actionService.doAction({ - type: 'ir.actions.act_window', - res_model: 'hr.leave', - name: '请假情况', - view_mode: 'tree,form', - view_type: 'tree', - views: [[false, 'tree']], - target: 'current', - context: {'tree_view_ref': "yuthon_hr_attendance.view_hr_leave_statement_tree"}, - domain: [ - '&', - ['date_from', '>=', lastMonthStart], - ['date_from', '<', lastMonthEnd] - ], - }); + async getLeaveAction() { + const res = await this.orm.call('yuthon.vacation.reports', 'leave_line', []); + this.actionService.doAction(res) } async getAction() { @@ -44,37 +18,9 @@ export class CustomAttendanceVacationPutController extends ListController { this.actionService.doAction(res) } - openYuthonVacationWizard() { - const now = new Date(); - const lastMonthYear = now.getMonth() === 0 ? now.getFullYear() - 1 : now.getFullYear(); - const lastMonth = now.getMonth() === 0 ? 11 : now.getMonth() - 1; - const lastMonthFirstDay = new Date(lastMonthYear, lastMonth, 1); - const currentMonthFirstDay = new Date(now.getFullYear(), now.getMonth(), 1); - const formatDate = (date) => { - const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - return `${year}-${month}-${day} 00:00:00`; - }; - const lastMonthStart = formatDate(lastMonthFirstDay); - const lastMonthEnd = formatDate(currentMonthFirstDay); - this.actionService.doAction({ - type: 'ir.actions.act_window', - res_model: 'vacation.meal.line', - name: '误餐情况', - view_mode: 'tree', - view_type: 'form', - views: [[false, 'tree']], - target: 'current', - context: {'tree_view_ref': "yuthon_hr_attendance.view_vacation_meal_line_tree", - 'group_by': ['employee_id'], - }, - domain: [ - '&', - ['start_date', '>=', lastMonthStart], - ['start_date', '<', lastMonthEnd] - ], - }); + async getMealAction() { + const res = await this.orm.call('yuthon.vacation.reports', 'meal_line', []); + this.actionService.doAction(res) } } 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 c7187f397..8dc2e1203 100644 --- a/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml +++ b/yuthon_hr_attendance/static/src/xml/button_vacation_put.xml @@ -2,7 +2,7 @@ - @@ -12,7 +12,7 @@ - diff --git a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml index 335ec2efe..503e15631 100644 --- a/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml +++ b/yuthon_hr_attendance/views/yuthon_vacation_reports_views.xml @@ -206,7 +206,7 @@ - + @@ -435,6 +435,9 @@ + + + @@ -464,7 +467,7 @@ - + @@ -680,13 +683,6 @@ code action = model.update_line() - - - - - - - 误餐情况 vacation.meal.line @@ -784,7 +780,7 @@ code - action = model.update_working_overtime() + action = model.update_is_visible() 更新报表 diff --git a/yuthon_hr_attendance/wizard/export_date_wizard.py b/yuthon_hr_attendance/wizard/export_date_wizard.py index 60dfe1764..2403f3676 100644 --- a/yuthon_hr_attendance/wizard/export_date_wizard.py +++ b/yuthon_hr_attendance/wizard/export_date_wizard.py @@ -106,9 +106,9 @@ class ExportDateWizard(models.TransientModel): filtered_ids = filtered_records.ids - fields_name = ['employee_id', 'department_id', 'holiday_status_id', 'caption', + fields_name = ['employee_id', 'department_id', 'holiday_status_id', 'date_from', 'date_to', 'length_leave', 'application_reason', 'mobile_phone'] - field_label = ['发起人', '部门', '休假类型', '标题', '开始时间', '结束时间', + field_label = ['发起人', '部门', '休假类型', '开始时间', '结束时间', '请假时长', '申请原因', '手机号'] data = { @@ -213,7 +213,7 @@ class ExportDateWizard(models.TransientModel): """导出加班归档明细""" active_ids = json.loads(self.active_ids) if self.active_ids else [] - domain = [('carry_forward_date', '>=', start_date), ('carry_forward_date', '<', end_date)] + domain = [('carry_forward_date', '>=', start_date), ('carry_forward_date', '<', end_date), ('is_void','=', False)] if active_ids: domain = [('id', 'in', active_ids)] + domain diff --git a/yuthon_hr_employee/models/inherit_res_user.py b/yuthon_hr_employee/models/inherit_res_user.py index 51774a068..6ed06dd23 100644 --- a/yuthon_hr_employee/models/inherit_res_user.py +++ b/yuthon_hr_employee/models/inherit_res_user.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from odoo import api, fields, models, _ from odoo.exceptions import UserError +import pypinyin class ResUsers(models.Model): @@ -20,4 +21,13 @@ class ResUsers(models.Model): } self.env['hr.employee'].create(employee_data) else: - raise UserError('该用户:%s已经创建员工,请不要重复操作' % employee_id.name) \ No newline at end of file + raise UserError('该用户:%s已经创建员工,请不要重复操作' % employee_id.name) + + def all_users_email(self): + employee_ids = self.browse(self._context.get('active_ids', self._context.get('active_id'))) + for employee in employee_ids: + if not employee.partner_id.email: + pinyin_list = pypinyin.lazy_pinyin(employee.name, style=pypinyin.NORMAL) + name_pinyin = ''.join(pinyin_list).lower() + email = f"{name_pinyin}@thtjzt.com" + employee.partner_id.write({'email': email}) \ No newline at end of file diff --git a/yuthon_hr_employee/views/inherit_hr_job_views.xml b/yuthon_hr_employee/views/inherit_hr_job_views.xml index 312856978..845d9b0d1 100644 --- a/yuthon_hr_employee/views/inherit_hr_job_views.xml +++ b/yuthon_hr_employee/views/inherit_hr_job_views.xml @@ -82,7 +82,7 @@ 1 - + diff --git a/yuthon_hr_employee/views/inherit_res_user_views.xml b/yuthon_hr_employee/views/inherit_res_user_views.xml index 8b49f1753..4e499e603 100644 --- a/yuthon_hr_employee/views/inherit_res_user_views.xml +++ b/yuthon_hr_employee/views/inherit_res_user_views.xml @@ -8,6 +8,14 @@ records.all_create_users() + + 更新邮件信息 + + + code + records.all_users_email() + + res.users.tree.inherit res.users