ifixkart-backend/Backend/tests/test_service_engine.py

160 lines
4.7 KiB
Python

import pytest
from datetime import datetime, timedelta
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import app.models.db_base # Ensures all tables registered in metadata
from app.core.database.db_session import Base
from app.models.CustomerDeviceModel import CustomerDevice
from app.models.ServiceModel import ServiceCatalog, ServiceJob, ServiceAppointment, ServiceJobAssignment
from app.models.TechnicianModel import TechnicianProfile, TechnicianSkill, TechnicianWorkingHours
from app.services.SlotAllocationService import SlotAllocationService
# Setup in-memory SQLite database for testing
DATABASE_URL = "sqlite:///:memory:"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@pytest.fixture(scope="function")
def db_session():
Base.metadata.create_all(bind=engine)
db = TestingSessionLocal()
try:
yield db
finally:
db.close()
Base.metadata.drop_all(bind=engine)
def test_dynamic_slot_allocation_success(db_session):
# 1. Setup seed catalog services
service = ServiceCatalog(
service_id="serv_1",
name="Screen Replacement",
base_price=5000.00,
estimated_duration_minutes=60,
workflow_type="REPAIR_QUOTE",
active=True
)
db_session.add(service)
# 2. Setup technician profile
tech = TechnicianProfile(
technician_id="tech_1",
user_id="user_tech_1",
active=True
)
db_session.add(tech)
# 3. Setup technician skill
skill = TechnicianSkill(
technician_id="tech_1",
service_type_id="serv_1",
skill_level=3
)
db_session.add(skill)
# 4. Setup working hours (Monday is weekday 0)
wh = TechnicianWorkingHours(
working_hour_id="wh_1",
technician_id="tech_1",
day_of_week=0,
start_time="09:00",
end_time="11:00"
)
db_session.add(wh)
db_session.commit()
# Calculate slots for next Monday (e.g. 2026-08-31)
target_date = datetime(2026, 8, 31).date()
allocation_service = SlotAllocationService()
slots = allocation_service.get_available_slots(db_session, target_date, "serv_1")
# Since duration is 60 mins and working hours are 09:00 - 11:00:
# 09:00 - 10:00 -> Slot 1
# 09:30 - 10:30 -> Slot 2
# 10:00 - 11:00 -> Slot 3
assert len(slots) == 3
assert slots[0]["start_time"] == "2026-08-31T09:00:00"
assert slots[2]["start_time"] == "2026-08-31T10:00:00"
def test_dynamic_slot_allocation_overlap(db_session):
# 1. Setup seed catalog services & technician
service = ServiceCatalog(
service_id="serv_1",
name="Screen Replacement",
base_price=5000.00,
estimated_duration_minutes=60,
active=True
)
db_session.add(service)
tech = TechnicianProfile(
technician_id="tech_1",
user_id="user_tech_1",
active=True
)
db_session.add(tech)
skill = TechnicianSkill(
technician_id="tech_1",
service_type_id="serv_1",
skill_level=3
)
db_session.add(skill)
wh = TechnicianWorkingHours(
working_hour_id="wh_1",
technician_id="tech_1",
day_of_week=0,
start_time="09:00",
end_time="11:00"
)
db_session.add(wh)
# 2. Book an overlapping slot (09:30 - 10:30)
device = CustomerDevice(
device_id="dev_1",
customer_id="cust_1",
brand="Apple",
model="iPhone 14"
)
db_session.add(device)
job = ServiceJob(
job_id="job_1",
job_no="SRV-12345",
customer_id="cust_1",
device_id="dev_1",
service_id="serv_1",
status="BOOKED"
)
db_session.add(job)
appt = ServiceAppointment(
appointment_id="appt_1",
service_job_id="job_1",
scheduled_start=datetime(2026, 8, 31, 9, 30),
scheduled_end=datetime(2026, 8, 31, 10, 30),
status="CONFIRMED"
)
db_session.add(appt)
assignment = ServiceJobAssignment(
assignment_id="assign_1",
service_job_id="job_1",
appointment_id="appt_1",
technician_id="tech_1"
)
db_session.add(assignment)
db_session.commit()
# Re-calculate availability
target_date = datetime(2026, 8, 31).date()
allocation_service = SlotAllocationService()
slots = allocation_service.get_available_slots(db_session, target_date, "serv_1")
# Overlapping appt is 09:30 - 10:30.
# Slot 09:00 - 10:00 overlaps (ends after 09:30) -> overlap!
# Slot 09:30 - 10:30 overlaps -> overlap!
# Slot 10:00 - 11:00 overlaps (starts before 10:30) -> overlap!
# So there should be 0 available slots!
assert len(slots) == 0