updates
This commit is contained in:
473
Backend/seeders/room_seeder.py
Normal file
473
Backend/seeders/room_seeder.py
Normal file
@@ -0,0 +1,473 @@
|
||||
"""
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user