From 807143815b6d3d1b5974c1cd53a4bcb535a59417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= <9664676+pengyuthon@user.noreply.gitee.com> Date: Tue, 2 Dec 2025 10:41:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/attendance_time_data.xml | 28 +++++ yuthon_hr_attendance/data/data_other.xml | 4 +- yuthon_hr_attendance/models/hr_attendance.py | 61 +++++++---- .../models/yuthon_run_planning.py | 102 +++++++++++------- .../views/yuthon_run_planning_views.xml | 6 +- .../models/inherit_yuthon_property.py | 14 +++ .../views/inherit_yuthon_property_views.xml | 1 + 7 files changed, 154 insertions(+), 62 deletions(-) diff --git a/yuthon_hr_attendance/data/attendance_time_data.xml b/yuthon_hr_attendance/data/attendance_time_data.xml index bdaf2e407..fff00f95d 100644 --- a/yuthon_hr_attendance/data/attendance_time_data.xml +++ b/yuthon_hr_attendance/data/attendance_time_data.xml @@ -298,6 +298,34 @@ -1 + + + 定时任务:行政班次上班打卡提醒 + + code + model.executive_day_remind_in() + + + 1 + days + + -1 + + + + + 定时任务:行政班次下班打卡提醒 + + code + model.executive_day_remind_out() + + + 1 + days + + -1 + + diff --git a/yuthon_hr_attendance/data/data_other.xml b/yuthon_hr_attendance/data/data_other.xml index 3f09ce2b6..9bd8db905 100644 --- a/yuthon_hr_attendance/data/data_other.xml +++ b/yuthon_hr_attendance/data/data_other.xml @@ -2,7 +2,7 @@ - 定时任务:计划行政上班提醒 + 定时任务:保安部计划行政上班提醒 code model.card_lc_shift_remind_on_administrative() @@ -16,7 +16,7 @@ - 定时任务:计划行政下班提醒 + 定时任务:保安部计划行政下班提醒 code model.card_lc_shift_remind_out_administrative() diff --git a/yuthon_hr_attendance/models/hr_attendance.py b/yuthon_hr_attendance/models/hr_attendance.py index 6d1827675..1a42c341f 100644 --- a/yuthon_hr_attendance/models/hr_attendance.py +++ b/yuthon_hr_attendance/models/hr_attendance.py @@ -791,7 +791,7 @@ class HrAttendance(models.Model): else: record.week = False - def _common_card_remind(self, dept_name=None, planning_name=None, is_check_in=True, method_name=None): + def _common_card_remind(self, dept_name=None, planning_name=None, is_check_in=True, method_name=None, is_executive=False): """通用打卡提醒函数""" if not method_name: return @@ -803,24 +803,38 @@ class HrAttendance(models.Model): end_window = next_call + timedelta(minutes=5) if not (start_window <= fields.Datetime.now() + timedelta(hours=8) <= end_window): return - slot_start = datetime.combine(current_date, datetime.min.time()) - slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time()) - domain = [ - ('template_id.planning_name', '=', planning_name), - ('start_datetime', '>=', slot_start), - ('start_datetime', '<', slot_end), - ('role_id.name', '=', dept_name), - ] - planning_slots = self.env['planning.slot'].search(domain) - for slot in planning_slots: - if is_check_in: - is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1) - if not is_card: - self.card_in_comment(slot.employee_id, planning_name) - else: - is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1) - if not is_card: - self.card_out_comment(slot.employee_id, planning_name) + if is_executive: + domain = [('current_data', '=', current_date)] + attendances = self.env['hr.attendance'].search(domain) + attended_employee_ids = attendances.mapped('employee_id') + for employee in attended_employee_ids: + if is_check_in: + is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1) + if not is_card: + self.card_in_comment(employee, '行政班次') + else: + is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1) + if not is_card: + self.card_out_comment(employee, '行政班次') + else: + slot_start = datetime.combine(current_date, datetime.min.time()) + slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time()) + domain = [ + ('template_id.planning_name', '=', planning_name), + ('start_datetime', '>=', slot_start), + ('start_datetime', '<', slot_end), + ('role_id.name', '=', dept_name), + ] + planning_slots = self.env['planning.slot'].search(domain) + for slot in planning_slots: + if is_check_in: + is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1) + if not is_card: + self.card_in_comment(slot.employee_id, planning_name) + else: + is_card = self.env['hr.attendance'].search([('employee_id', '=', slot.employee_id.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1) + if not is_card: + self.card_out_comment(slot.employee_id, planning_name) # 保安部 - 早班 def ba_card_white_up(self): @@ -939,6 +953,15 @@ class HrAttendance(models.Model): self._common_card_remind(dept_name='保安部', planning_name='保安计划行政', is_check_in=False, method_name='card_lc_shift_remind_out_administrative') + # 行政班次 + def executive_day_remind_in(self): + self._common_card_remind(planning_name='行政班次', is_check_in=True, + method_name='executive_day_remind_in', is_executive=True) + + def executive_day_remind_out(self): + self._common_card_remind(planning_name='行政班次', is_check_in=False, + method_name='executive_day_remind_out', is_executive=True) + def card_in_comment(self, employee_id, planning_name): data = f"您的班次是{planning_name},还有5分钟上班,记得打卡" url = '#小程序://天投云/XttsPpKg3MEpY7h' diff --git a/yuthon_hr_attendance/models/yuthon_run_planning.py b/yuthon_hr_attendance/models/yuthon_run_planning.py index 4b7cdc1c2..d37a4f2d7 100644 --- a/yuthon_hr_attendance/models/yuthon_run_planning.py +++ b/yuthon_hr_attendance/models/yuthon_run_planning.py @@ -17,7 +17,18 @@ class YuthonRunPlanning(models.Model): department_id = fields.Many2one("hr.department", string="部门", required=True) start_date = fields.Date(string='生效日期', default=fields.Datetime.today()) end_date = fields.Date(string='失效日期') + is_effect = fields.Boolean(string="是否生效", compute="_compute_is_effect") + @api.depends('start_date', 'end_date') + def _compute_is_effect(self): + today = fields.Date.today() + for record in self: + if not record.start_date: + record.is_effect = False + elif not record.end_date: + record.is_effect = record.start_date <= today + else: + record.is_effect = record.start_date <= today <= record.end_date def action_planning_wizard_run(self): return { @@ -48,20 +59,25 @@ class YuthonRunPlanning(models.Model): # 运行班 def run_confirm(self): - selected_month = self.start_date.month - year = datetime.now().year - first_day_of_month = datetime(year, selected_month, 1) + latest_slot = self.env['planning.slot'].search([ + ('department_id.name', '=', '运行班') + ], order='start_datetime desc', limit=1) + # 从最新排班中提取年/月 + latest_datetime = latest_slot.start_datetime + latest_year = latest_datetime.year + latest_month = latest_datetime.month + + # 计算下个月的年/月 + target_month = latest_month + 1 + target_year = latest_year + if target_month > 12: + target_month = 1 + target_year += 1 + first_day_of_month = datetime(target_year, target_month, 1) # 计算结束日期(当月的最后一天) - next_month = (selected_month % 12) + 1 - next_year = year + (1 if next_month == 1 else 0) + next_month = target_month % 12 + 1 + next_year = target_year + (1 if next_month == 1 else 0) last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1) - existing_slots = self.env['planning.slot'].search([ - ('department_id.name', '=', '运行班'), - ('start_datetime', '>=', first_day_of_month), - ('start_datetime', '<=', last_day_of_month), - ]) - if len(existing_slots) > 0: - raise UserError(f"该月已经有排程,请选择其他时间。") role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1) start_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time) end_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).end_time) @@ -147,20 +163,25 @@ class YuthonRunPlanning(models.Model): } # 高压班 def high_confirm(self): - selected_month = self.start_date.month - year = datetime.now().year - first_day_of_month = datetime(year, selected_month, 1) - # 计算结束日期(下个月的第一天) - next_month = (selected_month % 12) + 1 - next_year = year + (1 if next_month == 1 else 0) # 如果是12月,年份加1 - last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1) - existing_slots = self.env['planning.slot'].search([ + latest_slot = self.env['planning.slot'].search([ ('department_id.name', '=', '高压班'), - ('start_datetime', '>=', first_day_of_month), - ('start_datetime', '<=', last_day_of_month), - ]) - if len(existing_slots) > 0: - raise UserError(f"该月已经有排程,请选择其他时间。") + ], order='start_datetime desc', limit=1) + # 从最新排班中提取年/月 + latest_datetime = latest_slot.start_datetime + latest_year = latest_datetime.year + latest_month = latest_datetime.month + + # 计算下个月的年/月 + target_month = latest_month + 1 + target_year = latest_year + if target_month > 12: + target_month = 1 + target_year += 1 + first_day_of_month = datetime(target_year, target_month, 1) + # 计算结束日期(当月的最后一天) + next_month = target_month % 12 + 1 + next_year = target_year + (1 if next_month == 1 else 0) + last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1) role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1) start_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time) end_time = int(self.env['planning.slot.template'].search([('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).end_time) @@ -220,20 +241,25 @@ class YuthonRunPlanning(models.Model): } # 综合班 def integrated_confirm(self): - selected_month = self.start_date.month - year = datetime.now().year - first_day_of_month = datetime(year, selected_month, 1) - # 计算结束日期(下个月的第一天) - next_month = (selected_month % 12) + 1 - next_year = year + (1 if next_month == 1 else 0) # 如果是12月,年份加1 - last_day_of_month = datetime(next_year, next_month, 1)- timedelta(days=1) - existing_slots = self.env['planning.slot'].search([ + latest_slot = self.env['planning.slot'].search([ ('department_id.name', '=', '综合班'), - ('start_datetime', '>=', first_day_of_month), - ('start_datetime', '<=', last_day_of_month), - ]) - if len(existing_slots) > 0: - raise UserError(f"该月已经有排程,请选择其他时间。") + ], order='start_datetime desc', limit=1) + # 从最新排班中提取年/月 + latest_datetime = latest_slot.start_datetime + latest_year = latest_datetime.year + latest_month = latest_datetime.month + + # 计算下个月的年/月 + target_month = latest_month + 1 + target_year = latest_year + if target_month > 12: + target_month = 1 + target_year += 1 + first_day_of_month = datetime(target_year, target_month, 1) + # 计算结束日期(当月的最后一天) + next_month = target_month % 12 + 1 + next_year = target_year + (1 if next_month == 1 else 0) + last_day_of_month = datetime(next_year, next_month, 1) - timedelta(days=1) role_a = self.env['planning.role'].search([('name', '=', '工程部')], limit=1) start_time = int(self.env['planning.slot.template'].search( [('role_id', '=', role_a.id), ('planning_name', '=', '白班')]).start_time) diff --git a/yuthon_hr_attendance/views/yuthon_run_planning_views.xml b/yuthon_hr_attendance/views/yuthon_run_planning_views.xml index 4cc6368c0..87a636370 100644 --- a/yuthon_hr_attendance/views/yuthon_run_planning_views.xml +++ b/yuthon_hr_attendance/views/yuthon_run_planning_views.xml @@ -20,7 +20,7 @@
-
@@ -73,7 +73,7 @@
-
@@ -115,7 +115,7 @@
-
diff --git a/yuthon_property_approval/models/inherit_yuthon_property.py b/yuthon_property_approval/models/inherit_yuthon_property.py index 022faeb8d..a6594ea2a 100644 --- a/yuthon_property_approval/models/inherit_yuthon_property.py +++ b/yuthon_property_approval/models/inherit_yuthon_property.py @@ -185,6 +185,20 @@ class PropertyBankStatements(models.Model): lessee_ids = fields.Many2many('property.tenant.information', string='承租方', compute="_compute_property_employee_id", store=True) admin_id = fields.Many2one('res.users', string="片区管理员", compute="_compute_property_employee_id", store=True) + def write_off_details(self): + self.ensure_one() + modify_lines = self.env['receivable.modify.line'].search([ + ('bank_id', '=', self.id) + ]) + receivable_ids = modify_lines.mapped('receivable_id').filtered(lambda r: r.id) + return { + 'type': 'ir.actions.act_window', + 'res_model': 'property.accounts.receivable', + 'view_mode': 'tree', + 'view_id': self.env.ref('yuthon_property.view_property_accounts_receivable_tree').id, + 'domain': [('id', 'in', receivable_ids.ids)], + } + @api.depends('name') def _compute_property_employee_id(self): for record in self: diff --git a/yuthon_property_approval/views/inherit_yuthon_property_views.xml b/yuthon_property_approval/views/inherit_yuthon_property_views.xml index aa1057a92..c4c8df29b 100644 --- a/yuthon_property_approval/views/inherit_yuthon_property_views.xml +++ b/yuthon_property_approval/views/inherit_yuthon_property_views.xml @@ -668,6 +668,7 @@