Files
Hotel-Booking/Backend/seeders/room_seeder.py
Iliyan Angelov 5a8ca3c475 updates
2025-12-06 03:27:35 +02:00

474 lines
19 KiB
Python

"""
Room Seeder
Seeds the database with room types and rooms
All images are from Unsplash (free stock photos)
"""
import json
import sys
from pathlib import Path
from datetime import datetime, timezone
from decimal import Decimal
# Add parent directory to path to import modules
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from sqlalchemy.orm import Session
from src.shared.config.database import SessionLocal
from src.shared.config.logging_config import get_logger
from src.rooms.models.room import Room, RoomStatus
from src.rooms.models.room_type import RoomType
# Import all models to ensure relationships are loaded correctly
from src.models import *
logger = get_logger(__name__)
def get_room_types_data():
"""Generate room types data"""
now = datetime.now(timezone.utc)
return [
{
'name': 'Standard Room',
'description': 'Comfortable and well-appointed standard rooms perfect for business travelers and couples. Features modern amenities and elegant decor.',
'base_price': Decimal('150.00'),
'capacity': 2,
'amenities': json.dumps([
'Free WiFi',
'Flat-screen TV',
'Air Conditioning',
'Mini Bar',
'Work Desk',
'In-room Safe',
'Coffee Maker',
'Hair Dryer'
])
},
{
'name': 'Deluxe Room',
'description': 'Spacious deluxe rooms with enhanced amenities and premium furnishings. Ideal for guests seeking extra comfort and space.',
'base_price': Decimal('220.00'),
'capacity': 2,
'amenities': json.dumps([
'Free WiFi',
'Smart TV',
'Air Conditioning',
'Premium Mini Bar',
'Work Desk',
'In-room Safe',
'Nespresso Machine',
'Hair Dryer',
'Bathrobe & Slippers',
'City View'
])
},
{
'name': 'Executive Suite',
'description': 'Luxurious suites with separate living areas, perfect for extended stays or guests who prefer extra space and privacy.',
'base_price': Decimal('350.00'),
'capacity': 3,
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Air Conditioning',
'Premium Mini Bar',
'Separate Living Area',
'In-room Safe',
'Nespresso Machine',
'Hair Dryer',
'Bathrobe & Slippers',
'Panoramic View',
'Premium Toiletries',
'Welcome Amenities'
])
},
{
'name': 'Presidential Suite',
'description': 'The ultimate in luxury accommodation. Spacious multi-room suite with premium amenities, private terrace, and personalized butler service.',
'base_price': Decimal('800.00'),
'capacity': 4,
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Air Conditioning',
'Premium Mini Bar',
'Separate Living & Dining Areas',
'In-room Safe',
'Nespresso Machine',
'Hair Dryer',
'Bathrobe & Slippers',
'Panoramic View',
'Premium Toiletries',
'Welcome Amenities',
'Private Terrace',
'Butler Service',
'Private Bar',
'Jacuzzi'
])
},
{
'name': 'Ocean View Room',
'description': 'Stunning ocean view rooms with floor-to-ceiling windows and private balconies. Perfect for romantic getaways and relaxation.',
'base_price': Decimal('280.00'),
'capacity': 2,
'amenities': json.dumps([
'Free WiFi',
'Smart TV',
'Air Conditioning',
'Premium Mini Bar',
'Work Desk',
'In-room Safe',
'Nespresso Machine',
'Hair Dryer',
'Bathrobe & Slippers',
'Ocean View',
'Private Balcony',
'Premium Toiletries'
])
},
{
'name': 'Family Room',
'description': 'Spacious family-friendly rooms designed to accommodate families with children. Features extra beds and family amenities.',
'base_price': Decimal('300.00'),
'capacity': 4,
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Air Conditioning',
'Mini Bar',
'Extra Beds',
'In-room Safe',
'Coffee Maker',
'Hair Dryer',
'Family Amenities',
'Game Console',
'Child Safety Features'
])
}
]
def get_rooms_data(room_type_map):
"""Generate rooms data based on room types"""
now = datetime.now(timezone.utc)
rooms = []
# Standard Rooms (Floors 1-3, Rooms 101-130)
standard_type = room_type_map.get('Standard Room')
if standard_type:
for floor in range(1, 4):
for room_num in range(1, 11):
room_number = f"{floor}{room_num:02d}"
rooms.append({
'room_type_id': standard_type.id,
'room_number': room_number,
'floor': floor,
'status': RoomStatus.available,
'price': Decimal('150.00'),
'featured': room_num <= 2, # First 2 rooms per floor are featured
'capacity': 2,
'room_size': '25 sqm',
'view': 'City View',
'images': json.dumps([
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Flat-screen TV',
'Air Conditioning',
'Mini Bar',
'Work Desk',
'In-room Safe'
]),
'description': f'Comfortable standard room on floor {floor} with modern amenities and city view. Perfect for business travelers and couples.'
})
# Deluxe Rooms (Floors 4-6, Rooms 401-430)
deluxe_type = room_type_map.get('Deluxe Room')
if deluxe_type:
for floor in range(4, 7):
for room_num in range(1, 11):
room_number = f"{floor}{room_num:02d}"
rooms.append({
'room_type_id': deluxe_type.id,
'room_number': room_number,
'floor': floor,
'status': RoomStatus.available,
'price': Decimal('220.00'),
'featured': room_num <= 2,
'capacity': 2,
'room_size': '35 sqm',
'view': 'City View',
'images': json.dumps([
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Smart TV',
'Air Conditioning',
'Premium Mini Bar',
'Work Desk',
'Nespresso Machine',
'Bathrobe & Slippers'
]),
'description': f'Spacious deluxe room on floor {floor} with premium amenities and enhanced comfort. Ideal for guests seeking extra space.'
})
# Executive Suites (Floors 7-8, Rooms 701-720)
executive_type = room_type_map.get('Executive Suite')
if executive_type:
for floor in range(7, 9):
for room_num in range(1, 11):
room_number = f"{floor}{room_num:02d}"
rooms.append({
'room_type_id': executive_type.id,
'room_number': room_number,
'floor': floor,
'status': RoomStatus.available,
'price': Decimal('350.00'),
'featured': room_num <= 3,
'capacity': 3,
'room_size': '55 sqm',
'view': 'Panoramic View',
'images': json.dumps([
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Separate Living Area',
'Premium Mini Bar',
'Nespresso Machine',
'Bathrobe & Slippers',
'Premium Toiletries',
'Welcome Amenities'
]),
'description': f'Luxurious executive suite on floor {floor} with separate living area and panoramic views. Perfect for extended stays.'
})
# Presidential Suites (Floor 9, Rooms 901-905)
presidential_type = room_type_map.get('Presidential Suite')
if presidential_type:
for room_num in range(1, 6):
room_number = f"9{room_num:02d}"
rooms.append({
'room_type_id': presidential_type.id,
'room_number': room_number,
'floor': 9,
'status': RoomStatus.available,
'price': Decimal('800.00'),
'featured': True, # All presidential suites are featured
'capacity': 4,
'room_size': '120 sqm',
'view': 'Panoramic View',
'images': json.dumps([
'https://images.unsplash.com/photo-1596394516093-501ba68a0ba6?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Separate Living & Dining Areas',
'Private Terrace',
'Butler Service',
'Premium Mini Bar',
'Private Bar',
'Jacuzzi',
'Premium Toiletries',
'Welcome Amenities'
]),
'description': f'Ultimate luxury in our exclusive presidential suite. Features grand living room, formal dining, private terrace, and personal butler service. Suite {room_num}.'
})
# Ocean View Rooms (Floor 10, Rooms 1001-1020)
ocean_type = room_type_map.get('Ocean View Room')
if ocean_type:
for room_num in range(1, 21):
room_number = f"10{room_num:02d}"
rooms.append({
'room_type_id': ocean_type.id,
'room_number': room_number,
'floor': 10,
'status': RoomStatus.available,
'price': Decimal('280.00'),
'featured': room_num <= 5,
'capacity': 2,
'room_size': '30 sqm',
'view': 'Ocean View',
'images': json.dumps([
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1587925358603-dc217c8a64f8?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1564501049412-61c2a3083791?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Smart TV',
'Air Conditioning',
'Premium Mini Bar',
'Private Balcony',
'Nespresso Machine',
'Bathrobe & Slippers',
'Ocean View'
]),
'description': f'Stunning ocean view room with floor-to-ceiling windows and private balcony. Perfect for romantic getaways and relaxation.'
})
# Family Rooms (Floor 1, Rooms 111-120)
family_type = room_type_map.get('Family Room')
if family_type:
for room_num in range(11, 21):
room_number = f"1{room_num:02d}"
rooms.append({
'room_type_id': family_type.id,
'room_number': room_number,
'floor': 1,
'status': RoomStatus.available,
'price': Decimal('300.00'),
'featured': room_num <= 13,
'capacity': 4,
'room_size': '45 sqm',
'view': 'City View',
'images': json.dumps([
'https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1618773928121-c32242e63f39?w=1200&h=800&fit=crop',
'https://images.unsplash.com/photo-1590490360182-c33d57733427?w=1200&h=800&fit=crop'
]),
'amenities': json.dumps([
'Free WiFi',
'Smart TV (Multiple)',
'Air Conditioning',
'Mini Bar',
'Extra Beds',
'Game Console',
'Child Safety Features',
'Family Amenities'
]),
'description': f'Spacious family-friendly room on floor 1 designed to accommodate families with children. Features extra beds and family amenities.'
})
return rooms
def seed_room_types(db: Session):
"""Seed room types into the database"""
try:
room_types_data = get_room_types_data()
room_type_map = {}
now = datetime.now(timezone.utc)
for room_type_data in room_types_data:
existing = db.query(RoomType).filter(RoomType.name == room_type_data['name']).first()
if existing:
logger.info(f"Room type '{room_type_data['name']}' already exists. Updating...")
for key, value in room_type_data.items():
setattr(existing, key, value)
existing.updated_at = now
room_type_map[existing.name] = existing
else:
logger.info(f"Creating room type: {room_type_data['name']}")
room_type = RoomType(
**room_type_data,
created_at=now,
updated_at=now
)
db.add(room_type)
db.flush() # Flush to get the ID
room_type_map[room_type.name] = room_type
db.commit()
logger.info(f'Successfully seeded {len(room_type_map)} room types!')
return room_type_map
except Exception as e:
db.rollback()
logger.error(f'Error seeding room types: {str(e)}', exc_info=True)
raise
def seed_rooms(db: Session, room_type_map: dict, clear_existing: bool = False):
"""Seed rooms into the database"""
try:
if clear_existing:
logger.info('Clearing existing rooms...')
db.query(Room).delete()
db.commit()
logger.info('Existing rooms cleared.')
rooms_data = get_rooms_data(room_type_map)
now = datetime.now(timezone.utc)
created_count = 0
updated_count = 0
for room_data in rooms_data:
existing = db.query(Room).filter(Room.room_number == room_data['room_number']).first()
if existing:
logger.debug(f"Room '{room_data['room_number']}' already exists. Updating...")
for key, value in room_data.items():
setattr(existing, key, value)
existing.updated_at = now
updated_count += 1
else:
logger.debug(f"Creating room: {room_data['room_number']}")
room = Room(
**room_data,
created_at=now,
updated_at=now
)
db.add(room)
created_count += 1
db.commit()
logger.info(f'Successfully seeded rooms! Created: {created_count}, Updated: {updated_count}, Total: {len(rooms_data)}')
except Exception as e:
db.rollback()
logger.error(f'Error seeding rooms: {str(e)}', exc_info=True)
raise
def seed_rooms_and_types(db: Session, clear_existing: bool = False):
"""Seed both room types and rooms"""
room_type_map = seed_room_types(db)
seed_rooms(db, room_type_map, clear_existing=clear_existing)
return room_type_map
def main():
import argparse
parser = argparse.ArgumentParser(description='Seed room types and rooms')
parser.add_argument(
'--clear-rooms',
action='store_true',
help='Clear existing rooms before seeding (room types are updated, not cleared)'
)
args = parser.parse_args()
db = SessionLocal()
try:
seed_rooms_and_types(db, clear_existing=args.clear_rooms)
except Exception as e:
logger.error(f'Failed to seed rooms: {str(e)}', exc_info=True)
sys.exit(1)
finally:
db.close()
if __name__ == '__main__':
main()