93 lines
4.0 KiB
Python
93 lines
4.0 KiB
Python
from app import db
|
|
from datetime import datetime, timedelta
|
|
from enum import Enum
|
|
|
|
class ReservationStatus(Enum):
|
|
PENDING = 'PENDING'
|
|
CONFIRMED = 'CONFIRMED'
|
|
CANCELLED = 'CANCELLED'
|
|
COMPLETED = 'COMPLETED'
|
|
NO_SHOW = 'NO_SHOW'
|
|
|
|
class Reservation(db.Model):
|
|
__tablename__ = 'reservations'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
classroom_id = db.Column(db.Integer, db.ForeignKey('classrooms.id'), nullable=False)
|
|
commission_id = db.Column(db.Integer, db.ForeignKey('commissions.id'), nullable=False)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
|
|
|
start_time = db.Column(db.DateTime, nullable=False)
|
|
end_time = db.Column(db.DateTime, nullable=False)
|
|
purpose = db.Column(db.String(500), nullable=False)
|
|
status = db.Column(db.Enum(ReservationStatus), default=ReservationStatus.PENDING, nullable=False)
|
|
expected_attendees = db.Column(db.Integer, nullable=False)
|
|
notes = db.Column(db.Text)
|
|
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
# Relationships
|
|
classroom = db.relationship('Classroom', backref=db.backref('reservation_list', lazy=True, cascade='all, delete-orphan'))
|
|
commission = db.relationship('Commission', backref=db.backref('reservation_list', lazy=True, cascade='all, delete-orphan'))
|
|
# User already defines the relationship back to reservation
|
|
|
|
def to_dict(self):
|
|
"""Convert reservation to dictionary"""
|
|
return {
|
|
'id': self.id,
|
|
'classroom_id': self.classroom_id,
|
|
'commission_id': self.commission_id,
|
|
'user_id': self.user_id,
|
|
'start_time': self.start_time.isoformat() if self.start_time else None,
|
|
'end_time': self.end_time.isoformat() if self.end_time else None,
|
|
'purpose': self.purpose,
|
|
'status': self.status.value if self.status else None,
|
|
'expected_attendees': self.expected_attendees,
|
|
'notes': self.notes,
|
|
'created_at': self.created_at.isoformat() if self.created_at else None,
|
|
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
|
'classroom': self.classroom.to_dict() if self.classroom else None,
|
|
'commission': self.commission.to_dict() if self.commission else None,
|
|
'user': self.user.to_dict() if self.user else None
|
|
}
|
|
|
|
def is_confirmed(self):
|
|
"""Check if reservation is confirmed"""
|
|
return self.status == ReservationStatus.CONFIRMED
|
|
|
|
def can_be_cancelled(self):
|
|
"""Check if reservation can be cancelled (24 hours before start)"""
|
|
from datetime import timedelta
|
|
return self.start_time > datetime.utcnow() + timedelta(hours=24)
|
|
|
|
def check_conflict(self, other_reservation):
|
|
"""Check if this reservation conflicts with another"""
|
|
if self.classroom_id != other_reservation.classroom_id:
|
|
return False
|
|
if self.status != ReservationStatus.CONFIRMED:
|
|
return False
|
|
if other_reservation.status != ReservationStatus.CONFIRMED:
|
|
return False
|
|
|
|
# Check time overlap
|
|
return (self.start_time < other_reservation.end_time and
|
|
self.end_time > other_reservation.start_time)
|
|
|
|
@staticmethod
|
|
def find_conflicts(classroom_id, start_time, end_time, exclude_reservation_id=None):
|
|
"""Find conflicting reservations for a specific classroom and time slot"""
|
|
query = Reservation.query.filter(
|
|
Reservation.classroom_id == classroom_id,
|
|
Reservation.status == ReservationStatus.CONFIRMED,
|
|
Reservation.start_time < end_time,
|
|
Reservation.end_time > start_time
|
|
)
|
|
|
|
if exclude_reservation_id:
|
|
query = query.filter(Reservation.id != exclude_reservation_id)
|
|
|
|
return query.all()
|
|
|
|
def __repr__(self):
|
|
return f'<Reservation {self.id}>' |