|
|
""" |
|
|
Converters for bidirectional transformation between domain objects and API models. |
|
|
""" |
|
|
|
|
|
from datetime import date |
|
|
from typing import Dict, List, Optional |
|
|
|
|
|
from solverforge_legacy.solver import SolverStatus |
|
|
from solverforge_legacy.solver.score import HardSoftScore |
|
|
|
|
|
from . import domain |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def date_to_iso(d: Optional[date]) -> Optional[str]: |
|
|
"""Convert a date to ISO format string.""" |
|
|
return d.isoformat() if d else None |
|
|
|
|
|
|
|
|
def iso_to_date(s: Optional[str]) -> Optional[date]: |
|
|
"""Convert an ISO format string to a date.""" |
|
|
return date.fromisoformat(s) if s else None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def work_calendar_to_model(wc: domain.WorkCalendar) -> domain.WorkCalendarModel: |
|
|
"""Convert a WorkCalendar domain object to its API model.""" |
|
|
return domain.WorkCalendarModel( |
|
|
id=wc.id, |
|
|
from_date=date_to_iso(wc.from_date), |
|
|
to_date=date_to_iso(wc.to_date), |
|
|
) |
|
|
|
|
|
|
|
|
def crew_to_model(crew: domain.Crew) -> domain.CrewModel: |
|
|
"""Convert a Crew domain object to its API model.""" |
|
|
return domain.CrewModel(id=crew.id, name=crew.name) |
|
|
|
|
|
|
|
|
def job_to_model(job: domain.Job) -> domain.JobModel: |
|
|
"""Convert a Job domain object to its API model.""" |
|
|
return domain.JobModel( |
|
|
id=job.id, |
|
|
name=job.name, |
|
|
duration_in_days=job.duration_in_days, |
|
|
min_start_date=date_to_iso(job.min_start_date), |
|
|
max_end_date=date_to_iso(job.max_end_date), |
|
|
ideal_end_date=date_to_iso(job.ideal_end_date), |
|
|
tags=list(job.tags), |
|
|
crew=crew_to_model(job.crew) if job.crew else None, |
|
|
start_date=date_to_iso(job.start_date), |
|
|
end_date=date_to_iso(job.get_end_date()), |
|
|
) |
|
|
|
|
|
|
|
|
def schedule_to_model(schedule: domain.MaintenanceSchedule) -> domain.MaintenanceScheduleModel: |
|
|
"""Convert a MaintenanceSchedule domain object to its API model.""" |
|
|
return domain.MaintenanceScheduleModel( |
|
|
work_calendar=work_calendar_to_model(schedule.work_calendar), |
|
|
crews=[crew_to_model(c) for c in schedule.crews], |
|
|
jobs=[job_to_model(j) for j in schedule.jobs], |
|
|
start_date_range=[date_to_iso(d) for d in schedule.start_date_range], |
|
|
score=str(schedule.score) if schedule.score else None, |
|
|
solver_status=schedule.solver_status.name if schedule.solver_status else None, |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def model_to_work_calendar(model: domain.WorkCalendarModel) -> domain.WorkCalendar: |
|
|
"""Convert a WorkCalendarModel to its domain object.""" |
|
|
return domain.WorkCalendar( |
|
|
id=model.id, |
|
|
from_date=iso_to_date(model.from_date), |
|
|
to_date=iso_to_date(model.to_date), |
|
|
) |
|
|
|
|
|
|
|
|
def model_to_crew(model: domain.CrewModel) -> domain.Crew: |
|
|
"""Convert a CrewModel to its domain object.""" |
|
|
return domain.Crew(id=model.id, name=model.name) |
|
|
|
|
|
|
|
|
def model_to_schedule(model: domain.MaintenanceScheduleModel) -> domain.MaintenanceSchedule: |
|
|
""" |
|
|
Convert a MaintenanceScheduleModel to its domain object. |
|
|
|
|
|
Handles reference resolution for crew assignments. |
|
|
""" |
|
|
|
|
|
work_calendar = model_to_work_calendar(model.work_calendar) |
|
|
|
|
|
|
|
|
crews: List[domain.Crew] = [model_to_crew(c) for c in model.crews] |
|
|
crew_lookup: Dict[str, domain.Crew] = {c.id: c for c in crews} |
|
|
|
|
|
|
|
|
jobs: List[domain.Job] = [] |
|
|
for job_model in model.jobs: |
|
|
|
|
|
crew = None |
|
|
if job_model.crew: |
|
|
if isinstance(job_model.crew, str): |
|
|
crew = crew_lookup.get(job_model.crew) |
|
|
elif isinstance(job_model.crew, domain.CrewModel): |
|
|
crew = crew_lookup.get(job_model.crew.id) |
|
|
|
|
|
job = domain.Job( |
|
|
id=job_model.id, |
|
|
name=job_model.name, |
|
|
duration_in_days=job_model.duration_in_days, |
|
|
min_start_date=iso_to_date(job_model.min_start_date), |
|
|
max_end_date=iso_to_date(job_model.max_end_date), |
|
|
ideal_end_date=iso_to_date(job_model.ideal_end_date), |
|
|
tags=set(job_model.tags) if job_model.tags else set(), |
|
|
crew=crew, |
|
|
start_date=iso_to_date(job_model.start_date) if job_model.start_date else None, |
|
|
) |
|
|
jobs.append(job) |
|
|
|
|
|
|
|
|
start_date_range = ( |
|
|
[iso_to_date(d) for d in model.start_date_range] |
|
|
if model.start_date_range |
|
|
else [] |
|
|
) |
|
|
|
|
|
|
|
|
score = None |
|
|
if model.score: |
|
|
score = HardSoftScore.parse(model.score) |
|
|
|
|
|
|
|
|
solver_status = SolverStatus.NOT_SOLVING |
|
|
if model.solver_status: |
|
|
solver_status = SolverStatus[model.solver_status] |
|
|
|
|
|
return domain.MaintenanceSchedule( |
|
|
work_calendar=work_calendar, |
|
|
crews=crews, |
|
|
jobs=jobs, |
|
|
start_date_range=start_date_range, |
|
|
score=score, |
|
|
solver_status=solver_status, |
|
|
) |
|
|
|