113 lines
4.1 KiB
Python
113 lines
4.1 KiB
Python
from pathlib import Path
|
|
from openpyxl import load_workbook, Workbook
|
|
from openpyxl.styles import Font, PatternFill, Alignment
|
|
from app import db
|
|
from app.models import Guest
|
|
|
|
|
|
REQUIRED_COLUMNS = ["Отдел", "ФИО", "Должность", "e-mail", "название фото"]
|
|
|
|
|
|
def read_guests_from_excel(file_path):
|
|
"""Читает список гостей из Excel-файла."""
|
|
file_path = Path(file_path)
|
|
wb = load_workbook(file_path, data_only=True)
|
|
ws = wb.active
|
|
|
|
# Определяем заголовки
|
|
headers = [str(cell.value).strip() if cell.value else "" for cell in ws[1]]
|
|
|
|
missing = [col for col in REQUIRED_COLUMNS if col not in headers]
|
|
if missing:
|
|
raise ValueError(f"В файле отсутствуют обязательные столбцы: {', '.join(missing)}")
|
|
|
|
col_indices = {col: headers.index(col) for col in REQUIRED_COLUMNS}
|
|
guests_data = []
|
|
|
|
for row in ws.iter_rows(min_row=2, values_only=True):
|
|
full_name = str(row[col_indices["ФИО"]]).strip() if row[col_indices["ФИО"]] else ""
|
|
email = str(row[col_indices["e-mail"]]).strip() if row[col_indices["e-mail"]] else ""
|
|
|
|
if not full_name or not email:
|
|
continue
|
|
|
|
guests_data.append({
|
|
"department": str(row[col_indices["Отдел"]]).strip() if row[col_indices["Отдел"]] else "",
|
|
"full_name": full_name,
|
|
"position": str(row[col_indices["Должность"]]).strip() if row[col_indices["Должность"]] else "",
|
|
"email": email,
|
|
"photo_filename": str(row[col_indices["название фото"]]).strip() if row[col_indices["название фото"]] else "",
|
|
})
|
|
|
|
return guests_data
|
|
|
|
|
|
def import_guests_from_excel(file_path):
|
|
"""Импортирует гостей из Excel в базу данных."""
|
|
guests_data = read_guests_from_excel(file_path)
|
|
imported = 0
|
|
updated = 0
|
|
|
|
for data in guests_data:
|
|
guest = Guest.query.filter_by(email=data["email"]).first()
|
|
if guest:
|
|
guest.department = data["department"]
|
|
guest.full_name = data["full_name"]
|
|
guest.position = data["position"]
|
|
guest.photo_filename = data["photo_filename"]
|
|
guest.is_active = True
|
|
updated += 1
|
|
else:
|
|
guest = Guest(**data)
|
|
db.session.add(guest)
|
|
imported += 1
|
|
|
|
db.session.commit()
|
|
return {"imported": imported, "updated": updated, "total": len(guests_data)}
|
|
|
|
|
|
def export_report_to_excel(output_path, event_name="Корпоратив"):
|
|
"""Выгружает отчёт о посещаемости в Excel."""
|
|
guests = Guest.query.order_by(Guest.department, Guest.full_name).all()
|
|
|
|
wb = Workbook()
|
|
ws = wb.active
|
|
ws.title = "Отчёт"
|
|
|
|
headers = ["Отдел", "ФИО", "Должность", "Email", "Название фото", "Статус", "Время входа"]
|
|
ws.append(headers)
|
|
|
|
# Стили заголовков
|
|
for cell in ws[1]:
|
|
cell.font = Font(bold=True)
|
|
cell.fill = PatternFill(start_color="DDDDDD", end_color="DDDDDD", fill_type="solid")
|
|
cell.alignment = Alignment(horizontal="center")
|
|
|
|
for guest in guests:
|
|
status = "Пришёл" if guest.is_checked_in else "Не пришёл"
|
|
check_in_time = guest.last_check_in.strftime("%d.%m.%Y %H:%M:%S") if guest.last_check_in else ""
|
|
ws.append([
|
|
guest.department,
|
|
guest.full_name,
|
|
guest.position or "",
|
|
guest.email,
|
|
guest.photo_filename or "",
|
|
status,
|
|
check_in_time,
|
|
])
|
|
|
|
# Автоширина колонок
|
|
for column in ws.columns:
|
|
max_length = 0
|
|
column_letter = column[0].column_letter
|
|
for cell in column:
|
|
try:
|
|
if cell.value:
|
|
max_length = max(max_length, len(str(cell.value)))
|
|
except Exception:
|
|
pass
|
|
ws.column_dimensions[column_letter].width = min(max_length + 2, 50)
|
|
|
|
wb.save(output_path)
|
|
return output_path
|