проект теперь работает с использованием локальной базы данных SQLite. Все данные аккумулируются и хранятся в ней. Впереди - разработка веб интерфейса.

This commit is contained in:
2026-08-03 12:59:23 +03:00
parent d39618c891
commit 0efbe4ff99
14 changed files with 976 additions and 300 deletions
+21 -19
View File
@@ -128,22 +128,26 @@ def generate_summary_excel(merged_df, date_str="27.07.2026", filename=None):
current_row = 4
# 3. НЕИЗВЕСТНО (По умолчанию РАСКРЫТО, нумерация 1. ФИО)
# 3. НЕИЗВЕСТНО (По умолчанию РАСКРЫТО, чистые ФИО без цифр)
unexplained = merged_df[(merged_df['Пришел'] == False) & (merged_df['Вид_отсутствия'].isna())]
ws.cell(row=current_row, column=1, value="неизвестно")
ws.cell(row=current_row, column=2, value=len(unexplained))
format_row_cells(ws, current_row, FILL_UNEXPLAINED, is_bold=True, bold_font=bold_font)
current_row += 1
for idx, fio in enumerate(sorted(unexplained['Сотрудник'].dropna().unique()), 1):
ws.cell(row=current_row, column=1, value=f"{idx}. {fio}")
for fio in sorted(unexplained['Сотрудник'].dropna().unique()):
ws.cell(row=current_row, column=1, value=fio)
format_row_cells(ws, current_row, FILL_UNEXPLAINED, is_bold=False)
ws.row_dimensions[current_row].outlineLevel = 1
ws.row_dimensions[current_row].hidden = False
current_row += 1
# 4. КАТЕГОРИИ ОТСУТСТВИЙ (Свернуты hidden=True)
absent_only = merged_df[(merged_df['Пришел'] == False) & (merged_df['Вид_отсутствия'].notna())]
# 4. КАТЕГОРИИ ОТСУТСТВИЙ (Свернуты hidden=True, ИСКЛЮЧЕНИЯ ИСКЛЮЧЕНЫ)
absent_only = merged_df[
(merged_df['Пришел'] == False) &
(merged_df['Вид_отсутствия'].notna()) &
(~merged_df['Вид_отсутствия'].astype(str).str.startswith('Исключение'))
]
absent_groups = absent_only.groupby('Вид_отсутствия')
for idx_cat, (cat_name, group) in enumerate(absent_groups):
@@ -155,14 +159,14 @@ def generate_summary_excel(merged_df, date_str="27.07.2026", filename=None):
format_row_cells(ws, current_row, cat_fill, is_bold=True, bold_font=bold_font)
current_row += 1
for idx, fio in enumerate(sorted(group['Сотрудник'].dropna().unique()), 1):
ws.cell(row=current_row, column=1, value=f"{idx}. {fio}")
for fio in sorted(group['Сотрудник'].dropna().unique()):
ws.cell(row=current_row, column=1, value=fio)
format_row_cells(ws, current_row, cat_fill, is_bold=False)
ws.row_dimensions[current_row].outlineLevel = 1
ws.row_dimensions[current_row].hidden = True
current_row += 1
# 5. ИТОГО НА РАБОТЕ (Раскрывающийся список, свернут hidden=True)
# 5. ИТОГО НА РАБОТЕ (Свернут hidden=True)
is_working_mask = (merged_df['Пришел'] == True) | (
merged_df['Вид_отсутствия'].astype(str).str.lower().str.contains('командировк|удален|дистанцион|разъездн', regex=True, na=False)
)
@@ -174,14 +178,14 @@ def generate_summary_excel(merged_df, date_str="27.07.2026", filename=None):
current_row += 1
if not present.empty:
for idx, fio in enumerate(sorted(present['Сотрудник'].dropna().unique()), 1):
ws.cell(row=current_row, column=1, value=f"{idx}. {fio}")
for fio in sorted(present['Сотрудник'].dropna().unique()):
ws.cell(row=current_row, column=1, value=fio)
format_row_cells(ws, current_row, FILL_PRESENT, is_bold=False)
ws.row_dimensions[current_row].outlineLevel = 1
ws.row_dimensions[current_row].hidden = True
current_row += 1
# 6. АНОМАЛИИ (В самом низу таблицы, раскрывающийся список)
# 6. АНОМАЛИИ (Свернут hidden=True)
anomalies = merged_df[(merged_df['Пришел'] == True) & (merged_df['Вид_отсутствия'].notna())]
ws.cell(row=current_row, column=1, value="Аномалии")
@@ -189,15 +193,15 @@ def generate_summary_excel(merged_df, date_str="27.07.2026", filename=None):
format_row_cells(ws, current_row, FILL_ANOMALY, is_bold=True, bold_font=bold_font)
current_row += 1
chars_per_line_b = 30 # Влезает символов в столбец B шириной 230px (32.0 units)
chars_per_line_b = 30
if not anomalies.empty:
for idx, (_, row) in enumerate(anomalies.iterrows(), 1):
for _, row in anomalies.iterrows():
fio = row.get('Сотрудник', '')
reason = row.get('Вид_отсутствия', 'Неизвестная причина')
reason_text = f"В 1С: {reason}"
cell_a = ws.cell(row=current_row, column=1, value=f"{idx}. {fio} (На работе)")
cell_a = ws.cell(row=current_row, column=1, value=f"{fio} (На работе)")
cell_b = ws.cell(row=current_row, column=2, value=reason_text)
cell_a.fill = FILL_ANOMALY
@@ -219,7 +223,7 @@ def generate_summary_excel(merged_df, date_str="27.07.2026", filename=None):
current_row += 1
ws.column_dimensions['A'].width = 45.0
ws.column_dimensions['B'].width = 32.0 # Ровно 230px в Excel
ws.column_dimensions['B'].width = 32.0
try:
wb.save(output_path)
@@ -274,7 +278,6 @@ def generate_detailed_excel(merged_df, date_str="26.07.2026", filename=None):
in_building_str = str(row.get(hours_col, '00:00'))
# Расчет отклонения с учетом вычета 30 мин обеда и причины в 1С
deviation_val = calculate_deviation(in_building_str, reason=absence_reason if has_reason else "", norm_hours=8, lunch_minutes=30)
ws.append([
@@ -291,11 +294,10 @@ def generate_detailed_excel(merged_df, date_str="26.07.2026", filename=None):
row_num = 5 + idx
# Разграничение заливки для Детального отчета:
if is_present and has_reason:
row_fill = GREEN_FILL # Аномалия (Пришел в отпуске/на больничном) -> Бледно-зеленый
row_fill = GREEN_FILL
elif not is_present:
row_fill = YELLOW_FILL if has_reason else LIGHT_RED_FILL # Обычные отсутствия / Неизвестные
row_fill = YELLOW_FILL if has_reason else LIGHT_RED_FILL
else:
row_fill = None