From 4bb4a550ffabf40b1abfd36e7133d51f724091b0 Mon Sep 17 00:00:00 2001 From: younes Date: Sun, 16 Nov 2025 13:18:52 +0100 Subject: [PATCH] [FIX] attendances: fix bug --- .../models/hr_attendance_transactions.py | 182 ++++++++++++++---- 1 file changed, 149 insertions(+), 33 deletions(-) diff --git a/odex25_hr/attendances/models/hr_attendance_transactions.py b/odex25_hr/attendances/models/hr_attendance_transactions.py index 68016d7a1..8d4dd2bd5 100644 --- a/odex25_hr/attendances/models/hr_attendance_transactions.py +++ b/odex25_hr/attendances/models/hr_attendance_transactions.py @@ -65,58 +65,167 @@ class HrAttendanceTransactions(models.Model): rec.additional_hours = rec.office_hours - rec.plan_hours # rec.carried_hours = rec.office_hours - rec.plan_hours + # def get_shift_timings(self, item): + # calendar = item.calendar_id + + # if calendar.is_full_day: + # min_sign_in = calendar.full_min_sign_in + # full_max_sign_in = calendar.full_max_sign_in + # max_sign_out = calendar.full_max_sign_out + # working_hours = calendar.working_hours + # else: + # if item.sequence == 1: + # min_sign_in = calendar.shift_one_min_sign_in + # full_max_sign_in = calendar.shift_one_max_sign_in + # max_sign_out = calendar.shift_one_max_sign_out + # working_hours = calendar.shift_one_working_hours + # elif item.sequence == 2: + # min_sign_in = calendar.shift_two_min_sign_in + # full_max_sign_in = calendar.shift_two_max_sign_in + # max_sign_out = calendar.shift_two_max_sign_out + # working_hours = calendar.shift_two_working_hours + # else: + # min_sign_in = max_sign_out = working_hours = None # or default fallback + + # return min_sign_in, full_max_sign_in , max_sign_out, working_hours def get_shift_timings(self, item): calendar = item.calendar_id + date = item.date + weekday = date.strftime('%A').lower() # اسم اليوم مثل 'monday' + # جلب اليوم الخاص إن وجد + sp_days = calendar.special_days_partcial if not calendar.is_full_day else calendar.special_days + sp_timing = None + + for sp in sp_days: + # تحقق من اليوم ونوع الشفت إن وجد + if sp.name.lower() == weekday and ( + (calendar.is_full_day and not sp.shift) or + (not calendar.is_full_day and sp.shift == ('one' if item.sequence == 1 else 'two')) + ): + if sp.date_from and sp.date_to and str(date) >= sp.date_from and str(date) <= sp.date_to: + sp_timing = sp + break + elif sp.date_from and not sp.date_to and str(date) >= sp.date_from: + sp_timing = sp + break + elif not sp.date_from and sp.date_to and str(date) <= sp.date_to: + sp_timing = sp + break + elif not sp.date_from and not sp.date_to: + sp_timing = sp + break + + # الآن نحسب التوقيتات بناءً على نوع الجدول وفترة العمل if calendar.is_full_day: - min_sign_in = calendar.full_min_sign_in - full_max_sign_in = calendar.full_max_sign_in - max_sign_out = calendar.full_max_sign_out - working_hours = calendar.working_hours + min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.full_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.full_max_sign_in + max_sign_out = sp_timing.end_sign_out if sp_timing else calendar.full_max_sign_out + working_hours = (sp_timing.working_hours if sp_timing else calendar.working_hours) - calendar.break_duration else: if item.sequence == 1: - min_sign_in = calendar.shift_one_min_sign_in - full_max_sign_in = calendar.shift_one_max_sign_in - max_sign_out = calendar.shift_one_max_sign_out - working_hours = calendar.shift_one_working_hours + min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.shift_one_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.shift_one_max_sign_in + max_sign_out = sp_timing.end_sign_out if sp_timing else calendar.shift_one_max_sign_out + working_hours = (sp_timing.working_hours if sp_timing else calendar.shift_one_working_hours) - calendar.shift_one_break_duration elif item.sequence == 2: - min_sign_in = calendar.shift_two_min_sign_in - full_max_sign_in = calendar.shift_two_max_sign_in - max_sign_out = calendar.shift_two_max_sign_out - working_hours = calendar.shift_two_working_hours + min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.shift_two_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.shift_two_max_sign_in + max_sign_out = sp_timing.end_sign_out if sp_timing else calendar.shift_two_max_sign_out + working_hours = (sp_timing.working_hours if sp_timing else calendar.shift_two_working_hours) - calendar.shift_two_break_duration else: - min_sign_in = max_sign_out = working_hours = None # or default fallback + min_sign_in = full_max_sign_in = max_sign_out = working_hours = None - return min_sign_in, full_max_sign_in , max_sign_out, working_hours + return min_sign_in, full_max_sign_in, max_sign_out, working_hours def _compute_expected_times(self, item): - """Helper function to compute expected sign-in and sign-out times based on calendar settings.""" - expected_sign_in = 0 - expected_sign_out = 0 + """Compute expected sign-in and sign-out times considering calendar and special days.""" + calendar = item.calendar_id + date = item.date + weekday = date.strftime('%A').lower() - full_max_sign_in = item.calendar_id.full_max_sign_in - full_min_sign_in = item.calendar_id.full_min_sign_in - working_hours = item.calendar_id.working_hours + # اختيار قائمة الأيام الخاصة بناءً على نوع الدوام + sp_days = calendar.special_days_partcial if not calendar.is_full_day else calendar.special_days + sp_timing = None - if not item.calendar_id.is_full_day: + # البحث عن يوم خاص يطابق اليوم الحالي والفترة + for sp in sp_days: + if sp.name.lower() == weekday and ( + (calendar.is_full_day and not sp.shift) or + (not calendar.is_full_day and sp.shift == ('one' if item.sequence == 1 else 'two')) + ): + if sp.date_from and sp.date_to and str(date) >= sp.date_from and str(date) <= sp.date_to: + sp_timing = sp + break + elif sp.date_from and not sp.date_to and str(date) >= sp.date_from: + sp_timing = sp + break + elif not sp.date_from and sp.date_to and str(date) <= sp.date_to: + sp_timing = sp + break + elif not sp.date_from and not sp.date_to: + sp_timing = sp + break + + # تعيين التوقيتات حسب وجود يوم خاص أو لا + if calendar.is_full_day: + full_min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.full_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.full_max_sign_in + working_hours = sp_timing.working_hours if sp_timing else calendar.working_hours + else: if item.sequence == 1: - full_max_sign_in = item.calendar_id.shift_one_max_sign_in - full_min_sign_in = item.calendar_id.shift_one_min_sign_in - working_hours = item.calendar_id.shift_one_working_hours + full_min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.shift_one_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.shift_one_max_sign_in + working_hours = sp_timing.working_hours if sp_timing else calendar.shift_one_working_hours elif item.sequence == 2: - full_max_sign_in = item.calendar_id.shift_two_max_sign_in - full_min_sign_in = item.calendar_id.shift_two_min_sign_in - working_hours = item.calendar_id.shift_two_working_hours + full_min_sign_in = sp_timing.start_sign_in if sp_timing else calendar.shift_two_min_sign_in + full_max_sign_in = sp_timing.end_sign_in if sp_timing else calendar.shift_two_max_sign_in + working_hours = sp_timing.working_hours if sp_timing else calendar.shift_two_working_hours + else: + # fallback default + return 0, 0 + # حساب توقيت الدخول المتوقع if item.sign_in < full_min_sign_in: expected_sign_in = full_min_sign_in elif full_min_sign_in <= item.sign_in <= full_max_sign_in: expected_sign_in = item.sign_in - elif item.sign_in > full_max_sign_in: + else: expected_sign_in = full_max_sign_in + # توقيت الخروج المتوقع = الدخول + عدد الساعات expected_sign_out = expected_sign_in + working_hours + return expected_sign_in, expected_sign_out + + # def _compute_expected_times(self, item): + # """Helper function to compute expected sign-in and sign-out times based on calendar settings.""" + # expected_sign_in = 0 + # expected_sign_out = 0 + + # full_max_sign_in = item.calendar_id.full_max_sign_in + # full_min_sign_in = item.calendar_id.full_min_sign_in + # working_hours = item.calendar_id.working_hours + + # if not item.calendar_id.is_full_day: + # if item.sequence == 1: + # full_max_sign_in = item.calendar_id.shift_one_max_sign_in + # full_min_sign_in = item.calendar_id.shift_one_min_sign_in + # working_hours = item.calendar_id.shift_one_working_hours + # elif item.sequence == 2: + # full_max_sign_in = item.calendar_id.shift_two_max_sign_in + # full_min_sign_in = item.calendar_id.shift_two_min_sign_in + # working_hours = item.calendar_id.shift_two_working_hours + + # if item.sign_in < full_min_sign_in: + # expected_sign_in = full_min_sign_in + # elif full_min_sign_in <= item.sign_in <= full_max_sign_in: + # expected_sign_in = item.sign_in + # elif item.sign_in > full_max_sign_in: + # expected_sign_in = full_max_sign_in + + # expected_sign_out = expected_sign_in + working_hours + # return expected_sign_in, expected_sign_out def set_lateness_and_exit(self, item , expected_sign_in=None , expected_sign_out=None): if not expected_sign_in and not expected_sign_out: @@ -173,6 +282,8 @@ class HrAttendanceTransactions(models.Model): def _calculate_working_hours(self, day_trans): """ Helper method to calculate total working hours """ + print({'office_hours': sum(day_trans.mapped('office_hours')) + sum(day_trans.mapped('total_mission_hours'))}) + print(sum(day_trans.mapped('office_hours')) , sum(day_trans.mapped('total_mission_hours'))) day_trans.update({'office_hours': sum(day_trans.mapped('office_hours')) + sum(day_trans.mapped('total_mission_hours'))}) return ( sum(day_trans.mapped('office_hours')) + sum(day_trans.mapped('total_permission_hours')) @@ -436,11 +547,11 @@ class HrAttendanceTransactions(models.Model): for spday in sp_days: if spday.name.lower() == weekday and ((shift and spday.shift == shift) or (not shift and True)): if spday.date_from and spday.date_to \ - and at_date >= spday.date_from and at_date <= spday.date_to: + and str(at_date) >= spday.date_from and str(at_date) <= spday.date_to: return spday - elif spday.date_from and not spday.date_to and at_date >= spday.date_from: + elif spday.date_from and not spday.date_to and str(at_date) >= spday.date_from: return spday - elif not spday.date_from and spday.date_to and at_date <= spday.date_to: + elif not spday.date_from and spday.date_to and str(at_date) <= spday.date_to: return spday elif not spday.date_from and not spday.date_to: return spday @@ -651,7 +762,7 @@ class HrAttendanceTransactions(models.Model): return {'shift': shift_dict, 'out_ids': linked_out_ids, 'creep': creep} def manage_permission(self, trans_id, shift_in, shift_out, sign_in, sign_out, breaks, state=None): - #print(trans_id, "*********************manage_permission***********************************") + print(trans_id, "*********************manage_permission***********************************") trans, feedback = self.browse(trans_id)[0], [] # حساب التوقيع المتوقع للدخول والخروج بناء علي بصمة الدخول expected_sign_in, expected_sign_out = self._compute_expected_times(trans) @@ -796,7 +907,7 @@ class HrAttendanceTransactions(models.Model): if state is not None: return feedback def manage_mission(self, trans_id, shift_in, shift_out, sign_in, sign_out, breaks, state=None): - #print(trans_id, "*********************manage_mission***********************************") + print(trans_id, "*********************manage_mission***********************************") trans , feedback = self.browse(trans_id)[0] , [] expected_sign_in, expected_sign_out = self._compute_expected_times(trans) full_min_sign_in, full_max_sign_in, full_max_sign_out, working_hours = self.get_shift_timings(trans) @@ -839,6 +950,11 @@ class HrAttendanceTransactions(models.Model): continue elif trans.sign_in == 0.0 or trans.sign_out == 0.0: mission_hours = min(trans.plan_hours, emp_mission.hours) + print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") + print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") + print(mission_hours) + print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") + print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") miss_dic = {'is_official': True, 'official_id': mission.id, 'total_mission_hours': mission_hours, } if state != 'check':trans.update(miss_dic) if state is not None:feedback.append({'mission_id': mission.id, 'miss_start': mission_df, 'miss_end': mission_dt, 'type': 'all'})