56 lines
2.3 KiB
Python
56 lines
2.3 KiB
Python
"""
|
|
===============================================================================
|
|
FILE: services/reports/calculators.py
|
|
ROLE: Расчет баланса рабочего времени, обеденного перерыва и отклонений от нормы.
|
|
===============================================================================
|
|
"""
|
|
|
|
import pandas as pd
|
|
|
|
|
|
def calculate_deviation(time_in_building_str, reason="", norm_hours=8, lunch_minutes=30):
|
|
"""
|
|
Расчет отклонения от нормы.
|
|
Для удаленщиков при наличии физического времени в здании вычисляется реальное отклонение.
|
|
"""
|
|
reason_clean = str(reason).strip().lower() if pd.notna(reason) else ""
|
|
is_remote = "удален" in reason_clean or "дистанцион" in reason_clean
|
|
|
|
has_building_time = isinstance(time_in_building_str, str) and time_in_building_str not in ['00:00', '0', '', 'None', 'nan', 'NaN']
|
|
|
|
# Если есть уважительная причина (больничный, отпуск, командировка и т.д.) не удаленка
|
|
if reason_clean != "" and not is_remote:
|
|
return "0:00"
|
|
|
|
# Если удаленщик работал исключительно из дома (00:00 в здании)
|
|
if is_remote and not has_building_time:
|
|
return "0:00"
|
|
|
|
# Если сотрудника не было в здании и нет уважительной причины
|
|
if not has_building_time:
|
|
return f"-{norm_hours}:00"
|
|
|
|
try:
|
|
parts = time_in_building_str.strip().split(':')
|
|
hh = int(parts[0])
|
|
mm = int(parts[1]) if len(parts) > 1 else 0
|
|
total_in_building_minutes = hh * 60 + mm
|
|
|
|
if total_in_building_minutes == 0:
|
|
return "0:00" if is_remote else f"-{norm_hours}:00"
|
|
|
|
work_minutes = max(0, total_in_building_minutes - lunch_minutes)
|
|
norm_minutes = norm_hours * 60
|
|
diff = work_minutes - norm_minutes
|
|
|
|
if diff == 0:
|
|
return "0:00"
|
|
|
|
sign = "-" if diff < 0 else ""
|
|
abs_diff = abs(diff)
|
|
res_hh = abs_diff // 60
|
|
res_mm = abs_diff % 60
|
|
|
|
return f"{sign}{res_hh}:{res_mm:02d}"
|
|
except Exception:
|
|
return "0:00" if is_remote else f"-{norm_hours}:00" |