diff --git a/yuthon_holiday/models/inherit_hr_leave_allocation.py b/yuthon_holiday/models/inherit_hr_leave_allocation.py index 42e40b6b7..9f86c829a 100644 --- a/yuthon_holiday/models/inherit_hr_leave_allocation.py +++ b/yuthon_holiday/models/inherit_hr_leave_allocation.py @@ -6,6 +6,20 @@ import calendar class HrLeaveAllocation(models.Model): _inherit = 'hr.leave.allocation' + HOURS_PER_DAY = 8.0 + + @api.depends('holiday_status_id', 'allocation_type', 'number_of_hours_display', 'number_of_days_display', 'date_to') + def _compute_from_holiday_status_id(self): + super()._compute_from_holiday_status_id() + for allocation in self: + if allocation._get_request_unit() == 'hour': + allocation.number_of_days = allocation.number_of_hours_display / self.HOURS_PER_DAY + + @api.depends('number_of_days', 'holiday_status_id', 'employee_id', 'holiday_type') + def _compute_number_of_hours_display(self): + for allocation in self: + allocation.number_of_hours_display = allocation.number_of_days * self.HOURS_PER_DAY + holiday_type = fields.Selection([ ('employee', '按员工角色'), ('company', 'By Company'), diff --git a/yuthon_hr_attendance/models/planning_template_inherit.py b/yuthon_hr_attendance/models/planning_template_inherit.py index 34f412956..ab243ca82 100644 --- a/yuthon_hr_attendance/models/planning_template_inherit.py +++ b/yuthon_hr_attendance/models/planning_template_inherit.py @@ -124,6 +124,10 @@ class Planning(models.Model): if att_id: att_id.compute_attend() + vacation_id = self.env['yuthon.vacation.reports'].search([('employee_id', '=', slot.resource_id.employee_id.id), ('vacation_date', '=', new_start_datetime.date().replace(day=1))]) + if vacation_id: + vacation_id.update_line() + @api.depends('template_id.color') def _compute_color(self): diff --git a/yuthon_hr_attendance/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py index 30f212fe7..43fb8e9cb 100644 --- a/yuthon_hr_attendance/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -1506,6 +1506,30 @@ class YuthonVacationReports(models.Model): else: return True + def _process_shift_days1(self, current_data): + """ + 只判断:是否为法定节假日 + 返回:True = 法定节假日 + False = 非法定节假日 + """ + current_year = current_data.year + query_start = datetime(current_year, 1, 1) + query_end = datetime(current_year, 12, 31, 23, 59, 59) + # 只取法定节假日配置 + calendar_leaves = self.env['resource.calendar.leaves'].sudo().search([ + ("calendar_id.name", "=", "行政考勤工作日"), + ("date_from", ">=", query_start), + ("date_from", "<=", query_end) + ]) + + holidays_list = [] + for leave in calendar_leaves: + if leave.holidays: + holidays_list.extend(leave.holidays.split(',')) + holidays_list = [self.remove_leading_zero(date) for date in holidays_list] + current_date_str = f"{current_data.month}月{current_data.day}日" + return current_date_str in holidays_list + def all_put(self): vacation_ids = self.env["yuthon.vacation.reports"].browse(self._context.get('active_ids', self._context.get('active_id'))) for rec in vacation_ids: @@ -1798,18 +1822,21 @@ class YuthonVacationReports(models.Model): 'overtime_ids.is_void', 'overtime_ids.workflow_record_id', 'other_fee_ids.holiday_type', - 'other_fee_ids.lines' + 'other_fee_ids.lines', + 'employee_id', + 'vacation_date' ) def _compute_working_overtime(self): for record in self: - total_add1 = 0.0 # 加班时 - total_add2 = 0.0 # (已用补休) - total_add = 0.0 # (剩余补休) + # ===================== 原有逻辑 开始 ===================== + total_add1 = 0.0 + total_add2 = 0.0 + total_add = 0.0 legal_total = 0.0 + for line in record.overtime_ids: if line.is_void: continue - line_total = (line.workday or 0) + (line.public_holidays or 0) legal_total += (line.legal_day or 0) if line.update_type == 'add': @@ -1819,7 +1846,6 @@ class YuthonVacationReports(models.Model): if line.workflow_record_id and line.update_type == 'add' and line.overtime_methods == 'leave': total_add1 += line_total - if line.workflow_record_id and line.update_type == 'reduce': total_add2 += line_total @@ -1827,10 +1853,105 @@ class YuthonVacationReports(models.Model): for other_line in record.other_fee_ids: if other_line.holiday_type and other_line.holiday_type.name == '调休': adjust_holiday_days += other_line.lines or 0 + # ===================== 原有逻辑 结束 ===================== - record.working_overtime = (total_add / 8) + adjust_holiday_days + # ===================== 新增:排班加班逻辑(含你的新规则) ===================== + employee = record.employee_id + vacation_date = record.vacation_date + + if employee and vacation_date: + # 1. 获取【当前员工最新一条排班】 + shift_planning = self.env['yuthon.shift.planning'].search([], order='start_date desc', limit=1) + rest_weekday = None + if shift_planning: + # 2. 查5个排班表,取固定休息日 + shift_models = [ + 'yuthon.shift.planning.a.line', + 'yuthon.shift.planning.b.line', + 'yuthon.shift.planning.c.line', + 'yuthon.shift.ever.white.line', + 'yuthon.shift.ever.noon.line', + + ] + rest_code = False + for model in shift_models: + line = self.env[model].search([ + ('shift_planning_id', '=', shift_planning.id), + ('employee_id', '=', employee.id) + ], limit=1) + if line: + rest_code = line.regular_holidays + break + + week_map = {'one': 0, 'two': 1, 'three': 2, 'four': 3, 'five': 4, 'six': 5, 'seven': 6} + rest_weekday = week_map.get(rest_code) + + # 3. 遍历当月所有天 + dt = fields.Date.from_string(vacation_date) + year, month = dt.year, dt.month + _, days = calendar.monthrange(year, month) + + for day in range(1, days + 1): + curr_date = datetime(year, month, day).date() + date_str = fields.Date.to_string(curr_date) + prev_date_str = fields.Date.to_string(curr_date - timedelta(days=1)) + + slot = self.env['planning.slot'].search([ + ('employee_id', '=', employee.id), + ('start_datetime', '<=', date_str + ' 16:00:00'), + ('end_datetime', '>=', prev_date_str + ' 16:00:00'), + ], limit=1) + plan_name = slot.display_name or '' # 修正:用 name 不是 plan_name + + # 日期类型判断 + is_legal_holiday = self._process_shift_days1(curr_date) + + # ===================== 规则1:固定休息日前一天 ===================== + if rest_weekday is not None and curr_date.weekday() == rest_weekday - 1: + if not slot: + continue + work_hours = 0.0 + if plan_name in ('旧白', '旧晚'): + work_hours = 12.0 if is_legal_holiday else 4.0 + elif plan_name in ('旧白固加', '旧晚固加'): + work_hours = 12.0 + else: + # 不属于以上班次 → 固定算8小时 + work_hours = 8.0 + + # 计入加班 + if is_legal_holiday: + legal_total += work_hours + else: + total_add += work_hours + total_add1 += work_hours + + if slot: + work_hours = 0.0 + is_special_shift = any(key in plan_name for key in ['旧白', '旧晚', '旧固加白', '旧固加晚', '全天班', '固加早', '固加夜', '固加中']) + if is_special_shift: + if '旧固加白' in plan_name or '旧固加晚' in plan_name: + work_hours = 12.0 + elif '全天班' in plan_name: + work_hours = 24.0 if is_legal_holiday else 8.0 + elif '旧白' in plan_name or '旧晚' in plan_name: + work_hours = 12.0 if is_legal_holiday else 4.0 + elif '固加早' in plan_name or '固加夜' in plan_name or '固加中' in plan_name: + work_hours = 8.0 + else: + if is_legal_holiday: + work_hours = 8.0 + + if is_legal_holiday: + legal_total += work_hours + else: + total_add += work_hours + total_add1 += work_hours + + record.working_overtime = (total_add / 8) + adjust_holiday_days + record.this_year1 = total_add / 8 record.done_working_overtime = total_add1 - record.statutory_leave = legal_total/8 + record.statutory_leave = legal_total record.cop_leave = total_add2 / 8 @api.depends('overtime_ids.workday', 'overtime_ids.legal_day', 'overtime_ids.public_holidays', 'overtime_ids.update_type', 'overtime_ids.is_void') diff --git a/yuthon_issue/models/inherit_room_booking.py b/yuthon_issue/models/inherit_room_booking.py index 98d0448dd..85d2ea2ca 100644 --- a/yuthon_issue/models/inherit_room_booking.py +++ b/yuthon_issue/models/inherit_room_booking.py @@ -66,33 +66,33 @@ class RoomBooking(models.Model): if '党' in meeting_type_name: if meet.issue_library_id.is_party and not meet.issue_library_id.is_party_passed: party_value = str(record.start_datetime.date()) + record.meeting_type_id.name - meet.issue_library_id.party_char = f'{party_value}' + meet.issue_library_id.party_char = party_value meet.issue_library_id.issue_state_party = 'meeting' meet.issue_library_id.issue_state = False if '班子' in meeting_type_name: if meet.issue_library_id.is_class and not meet.issue_library_id.is_class_passed: class_value = str(record.start_datetime.date()) + f'第{record.number_of_meetings}次' + record.meeting_type_id.name - meet.issue_library_id.class_char = f'{class_value}' + meet.issue_library_id.class_char = class_value meet.issue_library_id.issue_state_class = 'meeting' meet.issue_library_id.issue_state = False if '董事' in meeting_type_name: if meet.issue_library_id.is_boss and not meet.issue_library_id.is_boss_passed: boss_value = str(record.start_datetime.date()) + record.meeting_type_id.name - meet.issue_library_id.boss_char = f'{boss_value}' + meet.issue_library_id.boss_char = boss_value meet.issue_library_id.issue_state_boss = 'meeting' meet.issue_library_id.issue_state = False elif '套' in meeting_type_name: if meet.issue_library_id.is_party and (meet.issue_library_id.is_party_passed == 'reject' or not meet.issue_library_id.is_party_passed): party_value = str(record.start_datetime.date()) + record.meeting_type_id.name - meet.issue_library_id.party_char = f'{party_value}' + meet.issue_library_id.party_char = party_value meet.issue_library_id.issue_state_party = 'meeting' meet.issue_library_id.issue_state = False elif meet.issue_library_id.is_class and (meet.issue_library_id.is_class_passed == 'r eject' or not meet.issue_library_id.is_class_passed): class_value = str(record.start_datetime.date()) + f'第{record.number_of_meetings}次' + record.meeting_type_id.name - meet.issue_library_id.class_char = f'{class_value}' + meet.issue_library_id.class_char = class_value meet.issue_library_id.issue_state_class = 'meeting' meet.issue_library_id.issue_state = False @@ -372,7 +372,7 @@ class IssueMeetingLine(models.Model): for suffix in suffix_list: clean_party_char = clean_party_char.removesuffix(suffix) clean_party_char = clean_party_char.replace('', '').replace('', '') - record.issue_library_id.party_char = f'{clean_party_char + agree_name}' + record.issue_library_id.party_char = clean_party_char + agree_name record.issue_library_id.issue_state_party = 'on_meet' # 3. 班子会相关 @@ -385,7 +385,7 @@ class IssueMeetingLine(models.Model): for suffix in suffix_list: clean_class_char = clean_class_char.removesuffix(suffix) clean_class_char = clean_class_char.replace('', '').replace('', '') - record.issue_library_id.class_char = f'{clean_class_char + agree_name}' + record.issue_library_id.class_char = clean_class_char + agree_name record.issue_library_id.issue_state_class = 'on_meet' # 4. 董事会相关 @@ -397,7 +397,7 @@ class IssueMeetingLine(models.Model): for suffix in suffix_list: clean_boss_char = clean_boss_char.removesuffix(suffix) clean_boss_char = clean_boss_char.replace('', '').replace('', '') - record.issue_library_id.boss_char = f'{clean_boss_char + agree_name}' + record.issue_library_id.boss_char = clean_boss_char + agree_name record.issue_library_id.issue_state_boss = 'on_meet' # 套开相关 @@ -414,7 +414,7 @@ class IssueMeetingLine(models.Model): for suffix in suffix_list: clean_party_char = clean_party_char.removesuffix(suffix) clean_party_char = clean_party_char.replace('', '').replace('', '') - record.issue_library_id.party_char = f'{clean_party_char + agree_name}' + record.issue_library_id.party_char = clean_party_char + agree_name record.issue_library_id.issue_state_party = 'on_meet' if is_push else 'will' elif (record.issue_library_id.is_class and @@ -427,7 +427,7 @@ class IssueMeetingLine(models.Model): for suffix in suffix_list: clean_class_char = clean_class_char.removesuffix(suffix) clean_class_char = clean_class_char.replace('', '').replace('', '') - record.issue_library_id.class_char = f'{clean_class_char + agree_name}' + record.issue_library_id.class_char = clean_class_char + agree_name record.issue_library_id.issue_state_class = 'on_meet' if is_push else 'will' def unlink(self): diff --git a/yuthon_issue/models/issue_library.py b/yuthon_issue/models/issue_library.py index fd1eedd7f..3b3e1c4b0 100644 --- a/yuthon_issue/models/issue_library.py +++ b/yuthon_issue/models/issue_library.py @@ -141,12 +141,18 @@ class IssueLibrary(models.Model): records = self.env['issue.library'].browse(active_ids) count = 0 for record in records: - # 只清理party_char的HTML标签 + # 清理party_char的HTML标签 if record.party_char: clean_value = re.sub(r'<[^>]+>', '', record.party_char) if clean_value != record.party_char: record.party_char = clean_value count += 1 + # 清理class_char的HTML标签 + if record.class_char: + clean_value = re.sub(r'<[^>]+>', '', record.class_char) + if clean_value != record.class_char: + record.class_char = clean_value + count += 1 return { 'type': 'ir.actions.client', 'tag': 'display_notification', diff --git a/yuthon_issue/views/issue_library_views.xml b/yuthon_issue/views/issue_library_views.xml index def33a6d7..d5507f318 100644 --- a/yuthon_issue/views/issue_library_views.xml +++ b/yuthon_issue/views/issue_library_views.xml @@ -466,6 +466,7 @@
diff --git a/yuthon_official/models/yuthon_official.py b/yuthon_official/models/yuthon_official.py index 941f1658d..3a7aea583 100644 --- a/yuthon_official/models/yuthon_official.py +++ b/yuthon_official/models/yuthon_official.py @@ -37,6 +37,14 @@ class YuthonOfficial(models.Model): 'flat_id', string="抄送单位" ) + main_unit_type = fields.Selection([ + ('gov', '行政事业单位'), + ('other', '其他单位') + ], string='主送单位类型') + copy_unit_type = fields.Selection([ + ('gov', '行政事业单位'), + ('other', '其他单位') + ], string='抄送单位类型') department_ids = fields.Many2many('hr.department', string='部门范围') employee_ids = fields.Many2many('hr.employee', string='人员范围') users_role_ids = fields.Many2many('soong.user.role', string='角色范围') @@ -183,6 +191,20 @@ class YuthonOfficial(models.Model): else: self.reference_cold = False + @api.onchange('main_flats_ids') + def _onchange_main_flats_ids(self): + if self.main_flats_ids: + self.main_unit_type = self.main_flats_ids[0].unit_type + else: + self.main_unit_type = False + + @api.onchange('copy_flats_ids') + def _onchange_copy_flats_ids(self): + if self.copy_flats_ids: + self.copy_unit_type = self.copy_flats_ids[0].unit_type + else: + self.copy_unit_type = False + @api.onchange('company_id1') def onchange_company_id1(self): current_year = fields.Date.today().year @@ -422,6 +444,20 @@ class YuthonPropertyOfficial(models.Model): else: self.reference_cold = False + @api.onchange('main_flats_ids') + def _onchange_main_flats_ids(self): + if self.main_flats_ids: + self.main_unit_type = self.main_flats_ids[0].unit_type + else: + self.main_unit_type = False + + @api.onchange('copy_flats_ids') + def _onchange_copy_flats_ids(self): + if self.copy_flats_ids: + self.copy_unit_type = self.copy_flats_ids[0].unit_type + else: + self.copy_unit_type = False + @api.onchange('company_id1') def onchange_company_id1(self): current_year = fields.Date.today().year diff --git a/yuthon_official/views/yuthon_official_views.xml b/yuthon_official/views/yuthon_official_views.xml index b169585ae..55c1bd818 100644 --- a/yuthon_official/views/yuthon_official_views.xml +++ b/yuthon_official/views/yuthon_official_views.xml @@ -78,6 +78,8 @@ + + diff --git a/yuthon_property_approval/__manifest__.py b/yuthon_property_approval/__manifest__.py index 30db0c254..60447fd0d 100644 --- a/yuthon_property_approval/__manifest__.py +++ b/yuthon_property_approval/__manifest__.py @@ -115,7 +115,9 @@ 'report/property_lease_contract_print_report.xml', 'report/property_lease_contract_print_templates.xml', 'report/property_supervising_approval_print_report.xml', - 'report/property_supervising_approval_print_templates.xml' + 'report/property_supervising_approval_print_templates.xml', + 'report/property_open_rent_print_report.xml', + 'report/property_open_rent_print_templates.xml' ], diff --git a/yuthon_property_approval/models/property_open_rent.py b/yuthon_property_approval/models/property_open_rent.py index e3f2ddb04..79977e40d 100644 --- a/yuthon_property_approval/models/property_open_rent.py +++ b/yuthon_property_approval/models/property_open_rent.py @@ -271,6 +271,13 @@ class PropertyOpenRent(models.Model): name_title = fields.Char(default=_get_default_name_title) self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])]) + + def action_print_property_open_rent(self): + """打印公开招租审批""" + self.ensure_one() + report_ref = self.env.ref('yuthon_property_approval.action_property_open_rent_print_report') + return report_ref.sudo().report_action(self) + # # # class PropertyOpenRentLine(models.Model): diff --git a/yuthon_property_approval/report/property_open_rent_print_report.xml b/yuthon_property_approval/report/property_open_rent_print_report.xml new file mode 100644 index 000000000..a0286050b --- /dev/null +++ b/yuthon_property_approval/report/property_open_rent_print_report.xml @@ -0,0 +1,24 @@ + + + + + + Open Rent Small Top Margin + A4 + 5 + Portrait + + + + 公开招租审批 + + property.open.rent + qweb-pdf + yuthon_property_approval.property_open_rent_print_template + yuthon_property_approval.property_open_rent_print_template + '公开招租审批%s_%s_%s' % (object.display_name or object.code or '', object.user_id.name or '', ((object.log_ids.filtered(lambda l: l.name == '归档')[-1].lase_click_date or object.log_ids.filtered(lambda l: l.name == '归档')[-1].date_create).strftime('%Y-%m-%d') if object.log_ids.filtered(lambda l: l.name == '归档') else '')) + + report + + + \ No newline at end of file diff --git a/yuthon_property_approval/report/property_open_rent_print_templates.xml b/yuthon_property_approval/report/property_open_rent_print_templates.xml new file mode 100644 index 000000000..5b20ae9d4 --- /dev/null +++ b/yuthon_property_approval/report/property_open_rent_print_templates.xml @@ -0,0 +1,94 @@ + + + + \ No newline at end of file diff --git a/yuthon_property_approval/views/property_open_rent_views.xml b/yuthon_property_approval/views/property_open_rent_views.xml index aaa579e81..d24a83edd 100644 --- a/yuthon_property_approval/views/property_open_rent_views.xml +++ b/yuthon_property_approval/views/property_open_rent_views.xml @@ -16,6 +16,12 @@ property.open.rent
+
+
diff --git a/yuthon_property_approval/wizard/binding_information_wizard.py b/yuthon_property_approval/wizard/binding_information_wizard.py index c043c05a2..729309c37 100644 --- a/yuthon_property_approval/wizard/binding_information_wizard.py +++ b/yuthon_property_approval/wizard/binding_information_wizard.py @@ -114,7 +114,7 @@ class BindingInformationWizard(models.Model): self.bank_id.write({ 'name': name, }) - + self.bank_id._compute_property_employee_id() bank_accounts = self.bank_id.lessee_ids.bank_ids.mapped('bank') clean_accounts = [x for x in bank_accounts if x.strip() if x] bank_ids = self.env['property.bank.statements'].search([