diff --git a/src/dutylog/services/report_service.py b/src/dutylog/services/report_service.py index 7e2c521..6ea98f9 100644 --- a/src/dutylog/services/report_service.py +++ b/src/dutylog/services/report_service.py @@ -94,14 +94,14 @@ class ReportService: title_text = f"{title} за период {start_date.strftime('%d.%m.%Y')} - {end_date.strftime('%d.%m.%Y')}" ws.cell(row=1, column=1, value=title_text) - ws.merge_cells("A1:F1") + ws.merge_cells("A1:E1") title_cell = ws.cell(row=1, column=1) title_cell.font = Font(bold=True, size=14) title_cell.alignment = Alignment(horizontal="center", vertical="center") ws.row_dimensions[1].height = 25 row_num = 3 - headers = ["Дата", "Резидент", "Комната", "Часы", "Админ", "Примечание"] + headers = ["Резидент", "Комната", "Часы", "Админы", "Примечания"] for col_num, header in enumerate(headers, 1): cell = ws.cell(row=row_num, column=col_num) cell.value = header @@ -113,42 +113,55 @@ class ReportService: ws.row_dimensions[row_num].height = 20 row_num += 1 - total = 0 + resident_data = {} for transaction in transactions: - resident = await self.residents_repository.get_by_id( - transaction.resident_id - ) + resident = await self.residents_repository.get_by_id(transaction.resident_id) if not resident: continue - room = await self.rooms_repository.get_by_id(resident.room) - room_number = room.number if room else "—" + resident_key = resident.id + + if resident_key not in resident_data: + room = await self.rooms_repository.get_by_id(resident.room) + resident_data[resident_key] = { + "name": resident.real_name or "Без имени", + "room": room.number if room else "—", + "hours": 0, + "admins": set(), + "remarks": [], + } + + resident_data[resident_key]["hours"] += transaction.amount - admin_username = "—" if transaction.admin_id: admin = await self.users_repository.get_user_by_id(transaction.admin_id) if admin and admin.username: - admin_username = f"@{admin.username}" + resident_data[resident_key]["admins"].add(f"@{admin.username}") + + if transaction.remark: + resident_data[resident_key]["remarks"].append(transaction.remark) - msk_time = transaction.created_at.astimezone(MSK_TZ).replace(tzinfo=None) + sorted_residents = sorted(resident_data.items(), key=lambda x: x[1]["name"]) - ws.cell(row=row_num, column=1, value=msk_time).border = border - ws.cell(row=row_num, column=1).number_format = "DD.MM.YYYY HH:MM" - ws.cell(row=row_num, column=2, value=resident.real_name or "Без имени").border = border - ws.cell(row=row_num, column=3, value=room_number).border = border - ws.cell(row=row_num, column=4, value=transaction.amount).border = border - ws.cell(row=row_num, column=5, value=admin_username).border = border - ws.cell(row=row_num, column=6, value=transaction.remark or "—").border = border + total = 0 + for resident_id, data in sorted_residents: + admins_str = ", ".join(sorted(data["admins"])) if data["admins"] else "—" + remarks_str = ", ".join(data["remarks"]) if data["remarks"] else "—" - ws.cell(row=row_num, column=1).alignment = Alignment(horizontal="center") + ws.cell(row=row_num, column=1, value=data["name"]).border = border + ws.cell(row=row_num, column=2, value=data["room"]).border = border + ws.cell(row=row_num, column=3, value=data["hours"]).border = border + ws.cell(row=row_num, column=4, value=admins_str).border = border + ws.cell(row=row_num, column=5, value=remarks_str).border = border + + ws.cell(row=row_num, column=2).alignment = Alignment(horizontal="center") ws.cell(row=row_num, column=3).alignment = Alignment(horizontal="center") - ws.cell(row=row_num, column=4).alignment = Alignment(horizontal="center") - total += transaction.amount + total += data["hours"] row_num += 1 summary_row = row_num - ws.merge_cells(f"A{summary_row}:C{summary_row}") + ws.merge_cells(f"A{summary_row}:B{summary_row}") summary_cell = ws[f"A{summary_row}"] summary_cell.value = "Итого часов:" summary_cell.font = summary_font @@ -156,20 +169,19 @@ class ReportService: summary_cell.alignment = Alignment(horizontal="right", vertical="center") summary_cell.border = border - ws.cell(row=summary_row, column=4, value=total).font = summary_font - ws.cell(row=summary_row, column=4).fill = summary_fill - ws.cell(row=summary_row, column=4).alignment = Alignment(horizontal="center") - ws.cell(row=summary_row, column=4).border = border + ws.cell(row=summary_row, column=3, value=total).font = summary_font + ws.cell(row=summary_row, column=3).fill = summary_fill + ws.cell(row=summary_row, column=3).alignment = Alignment(horizontal="center") + ws.cell(row=summary_row, column=3).border = border + ws.cell(row=summary_row, column=4, value="").fill = summary_fill + ws.cell(row=summary_row, column=4).border = border + ws.cell(row=summary_row, column=5, value="").fill = summary_fill ws.cell(row=summary_row, column=5).border = border - - ws.cell(row=summary_row, column=6, value="").fill = summary_fill - ws.cell(row=summary_row, column=6).border = border - ws.column_dimensions["A"].width = 18 - ws.column_dimensions["B"].width = 25 + ws.column_dimensions["A"].width = 25 + ws.column_dimensions["B"].width = 10 ws.column_dimensions["C"].width = 10 - ws.column_dimensions["D"].width = 10 - ws.column_dimensions["E"].width = 15 - ws.column_dimensions["F"].width = 30 + ws.column_dimensions["D"].width = 20 + ws.column_dimensions["E"].width = 40