160 lines
4.7 KiB
Python
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
|