Files
duty-teller/duty_teller/services/import_service.py
Nikolay Tatarinov 28973489a5 Refactor project structure and enhance Docker configuration
- Updated `.dockerignore` to exclude test and development artifacts, optimizing the Docker image size.
- Refactored `main.py` to delegate execution to `duty_teller.run.main()`, simplifying the entry point.
- Introduced a new `duty_teller` package to encapsulate core functionality, improving modularity and organization.
- Enhanced `pyproject.toml` to define a script for running the application, streamlining the execution process.
- Updated README documentation to reflect changes in project structure and usage instructions.
- Improved Alembic environment configuration to utilize the new package structure for database migrations.
2026-02-18 13:03:14 +03:00

71 lines
2.5 KiB
Python

"""Import duty schedule: delete range, insert duties/unavailable/vacation. Accepts session."""
from datetime import date, timedelta
from sqlalchemy.orm import Session
from duty_teller.db.repository import (
get_or_create_user_by_full_name,
delete_duties_in_range,
insert_duty,
)
from duty_teller.importers.duty_schedule import DutyScheduleResult
from duty_teller.utils.dates import day_start_iso, day_end_iso, duty_to_iso
def _consecutive_date_ranges(dates: list[date]) -> list[tuple[date, date]]:
"""Sort dates and merge consecutive ones into (first, last) ranges. Empty list -> []."""
if not dates:
return []
sorted_dates = sorted(set(dates))
ranges: list[tuple[date, date]] = []
start_d = end_d = sorted_dates[0]
for d in sorted_dates[1:]:
if (d - end_d).days == 1:
end_d = d
else:
ranges.append((start_d, end_d))
start_d = end_d = d
ranges.append((start_d, end_d))
return ranges
def run_import(
session: Session,
result: DutyScheduleResult,
hour_utc: int,
minute_utc: int,
) -> tuple[int, int, int, int]:
"""Run import: delete range per user, insert duty/unavailable/vacation. Returns (num_users, num_duty, num_unavailable, num_vacation)."""
from_date_str = result.start_date.isoformat()
to_date_str = result.end_date.isoformat()
num_duty = num_unavailable = num_vacation = 0
for entry in result.entries:
user = get_or_create_user_by_full_name(session, entry.full_name)
delete_duties_in_range(session, user.id, from_date_str, to_date_str)
for d in entry.duty_dates:
start_at = duty_to_iso(d, hour_utc, minute_utc)
d_next = d + timedelta(days=1)
end_at = duty_to_iso(d_next, hour_utc, minute_utc)
insert_duty(session, user.id, start_at, end_at, event_type="duty")
num_duty += 1
for d in entry.unavailable_dates:
insert_duty(
session,
user.id,
day_start_iso(d),
day_end_iso(d),
event_type="unavailable",
)
num_unavailable += 1
for start_d, end_d in _consecutive_date_ranges(entry.vacation_dates):
insert_duty(
session,
user.id,
day_start_iso(start_d),
day_end_iso(end_d),
event_type="vacation",
)
num_vacation += 1
return (len(result.entries), num_duty, num_unavailable, num_vacation)