updates
This commit is contained in:
329
Backend/seeds_data/seed_bookings.py
Executable file
329
Backend/seeds_data/seed_bookings.py
Executable file
@@ -0,0 +1,329 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script to seed sample bookings for testing check-in/check-out and housekeeping notifications.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
# Add both the seeds_data directory and the Backend directory to the path
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import and_
|
||||
from src.shared.config.database import SessionLocal
|
||||
# Import all models needed for SQLAlchemy relationship setup
|
||||
# Import base models first
|
||||
from src.auth.models.role import Role
|
||||
from src.auth.models.user import User
|
||||
from src.rooms.models.room import Room, RoomStatus
|
||||
from src.rooms.models.room_type import RoomType # For Room relationship
|
||||
from src.rooms.models.rate_plan import RatePlan # For RoomType relationship
|
||||
from src.rooms.models.room_maintenance import RoomMaintenance # For Room relationship
|
||||
from src.rooms.models.room_inspection import RoomInspection # For Room relationship
|
||||
from src.rooms.models.room_attribute import RoomAttribute # For Room relationship
|
||||
from src.hotel_services.models.housekeeping_task import HousekeepingTask # For Room relationship
|
||||
from src.bookings.models.booking import Booking, BookingStatus
|
||||
from src.bookings.models.group_booking import GroupBooking # For Booking relationship
|
||||
|
||||
# Import all related models to satisfy SQLAlchemy relationships
|
||||
# This is necessary because SQLAlchemy needs all related models loaded
|
||||
try:
|
||||
from src.auth.models.refresh_token import RefreshToken
|
||||
from src.reviews.models.review import Review
|
||||
from src.reviews.models.favorite import Favorite
|
||||
from src.hotel_services.models.service import Service # For ServiceBooking relationship
|
||||
from src.hotel_services.models.service_booking import ServiceBooking
|
||||
from src.hotel_services.models.service_usage import ServiceUsage # For Booking relationship
|
||||
from src.bookings.models.checkin_checkout import CheckInCheckOut
|
||||
from src.payments.models.payment import Payment
|
||||
from src.payments.models.invoice import Invoice
|
||||
from src.ai.models.chat import Chat
|
||||
from src.loyalty.models.user_loyalty import UserLoyalty
|
||||
from src.loyalty.models.loyalty_tier import LoyaltyTier # For UserLoyalty relationship
|
||||
from src.loyalty.models.loyalty_point_transaction import LoyaltyPointTransaction # For UserLoyalty relationship
|
||||
from src.loyalty.models.referral import Referral
|
||||
from src.loyalty.models.package import Package # For RoomType relationship
|
||||
from src.guest_management.models.guest_preference import GuestPreference
|
||||
from src.guest_management.models.guest_note import GuestNote
|
||||
from src.guest_management.models.guest_communication import GuestCommunication
|
||||
from src.guest_management.models.guest_tag import GuestTag, guest_tag_association
|
||||
from src.guest_management.models.guest_segment import GuestSegment, guest_segment_association
|
||||
# Import any other models that might be related
|
||||
except ImportError:
|
||||
pass # Some models might not exist, that's okay
|
||||
from datetime import datetime, timedelta
|
||||
import random
|
||||
import secrets
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
return db
|
||||
finally:
|
||||
pass
|
||||
|
||||
def generate_booking_number() -> str:
|
||||
"""Generate a unique booking number"""
|
||||
prefix = 'BK'
|
||||
ts = int(datetime.utcnow().timestamp() * 1000)
|
||||
rand = secrets.randbelow(9000) + 1000
|
||||
return f'{prefix}-{ts}-{rand}'
|
||||
|
||||
def seed_bookings(db: Session):
|
||||
print('=' * 80)
|
||||
print('SEEDING SAMPLE BOOKINGS FOR TESTING')
|
||||
print('=' * 80)
|
||||
|
||||
# Get roles
|
||||
customer_role = db.query(Role).filter(Role.name == 'customer').first()
|
||||
staff_role = db.query(Role).filter(Role.name == 'staff').first()
|
||||
admin_role = db.query(Role).filter(Role.name == 'admin').first()
|
||||
|
||||
if not customer_role:
|
||||
print(' ❌ Customer role not found! Please seed roles first.')
|
||||
return
|
||||
|
||||
# Get customers
|
||||
customers = db.query(User).filter(User.role_id == customer_role.id).all()
|
||||
if not customers:
|
||||
print(' ❌ No customer users found! Please seed users first.')
|
||||
return
|
||||
|
||||
# Get available rooms
|
||||
rooms = db.query(Room).all()
|
||||
if not rooms:
|
||||
print(' ❌ No rooms found! Please seed rooms first.')
|
||||
return
|
||||
|
||||
print(f'\n✓ Found {len(customers)} customer(s) and {len(rooms)} room(s)')
|
||||
|
||||
# Delete existing bookings (optional - comment out if you want to keep existing bookings)
|
||||
existing_bookings = db.query(Booking).all()
|
||||
if existing_bookings:
|
||||
print(f'\n🗑️ Deleting {len(existing_bookings)} existing booking(s)...')
|
||||
booking_ids = [b.id for b in existing_bookings]
|
||||
|
||||
# Delete related records first to avoid foreign key constraints
|
||||
try:
|
||||
from src.guest_management.models.guest_complaint import GuestComplaint, ComplaintUpdate
|
||||
complaints = db.query(GuestComplaint).filter(GuestComplaint.booking_id.in_(booking_ids)).all()
|
||||
if complaints:
|
||||
complaint_ids = [c.id for c in complaints]
|
||||
# Delete complaint updates first
|
||||
updates = db.query(ComplaintUpdate).filter(ComplaintUpdate.complaint_id.in_(complaint_ids)).all()
|
||||
if updates:
|
||||
for update in updates:
|
||||
db.delete(update)
|
||||
print(f' ✓ Deleted {len(updates)} complaint update(s)')
|
||||
# Then delete complaints
|
||||
for complaint in complaints:
|
||||
db.delete(complaint)
|
||||
print(f' ✓ Deleted {len(complaints)} guest complaint(s)')
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
for booking in existing_bookings:
|
||||
db.delete(booking)
|
||||
db.commit()
|
||||
print(f'✓ Deleted {len(existing_bookings)} booking(s)')
|
||||
|
||||
# Create sample bookings with different statuses
|
||||
now = datetime.utcnow()
|
||||
bookings_data = []
|
||||
|
||||
# 1. Past bookings (checked out) - These should trigger cleaning notifications
|
||||
print('\n📅 Creating past bookings (checked out)...')
|
||||
for i in range(3):
|
||||
room = random.choice(rooms)
|
||||
customer = random.choice(customers)
|
||||
|
||||
# Check-out was 1-3 days ago
|
||||
days_ago = random.randint(1, 3)
|
||||
check_out_date = now - timedelta(days=days_ago)
|
||||
check_in_date = check_out_date - timedelta(days=random.randint(1, 5))
|
||||
|
||||
# Calculate price
|
||||
base_price = float(room.price) if room.price else 100.0
|
||||
num_nights = (check_out_date - check_in_date).days
|
||||
total_price = base_price * num_nights
|
||||
|
||||
booking = Booking(
|
||||
booking_number=generate_booking_number(),
|
||||
user_id=customer.id,
|
||||
room_id=room.id,
|
||||
check_in_date=check_in_date,
|
||||
check_out_date=check_out_date,
|
||||
num_guests=random.randint(1, min(room.capacity, 4)),
|
||||
total_price=total_price,
|
||||
status=BookingStatus.checked_out,
|
||||
deposit_paid=True,
|
||||
requires_deposit=False,
|
||||
special_requests=f'Sample booking for testing - Checked out {days_ago} day(s) ago'
|
||||
)
|
||||
db.add(booking)
|
||||
db.flush() # Flush to get booking ID
|
||||
|
||||
# Set room status to cleaning for checked out bookings
|
||||
# Check if there's active maintenance first
|
||||
try:
|
||||
from src.rooms.models.room_maintenance import RoomMaintenance, MaintenanceStatus
|
||||
active_maintenance = db.query(RoomMaintenance).filter(
|
||||
and_(
|
||||
RoomMaintenance.room_id == room.id,
|
||||
RoomMaintenance.blocks_room == True,
|
||||
RoomMaintenance.status.in_([MaintenanceStatus.scheduled, MaintenanceStatus.in_progress])
|
||||
)
|
||||
).first()
|
||||
if not active_maintenance:
|
||||
room.status = RoomStatus.cleaning
|
||||
|
||||
# Create housekeeping task for checkout cleaning
|
||||
try:
|
||||
from src.hotel_services.models.housekeeping_task import HousekeepingTask, HousekeepingStatus, HousekeepingType
|
||||
checkout_checklist = [
|
||||
{'item': 'Bathroom cleaned', 'completed': False, 'notes': ''},
|
||||
{'item': 'Beds made with fresh linens', 'completed': False, 'notes': ''},
|
||||
{'item': 'Trash emptied', 'completed': False, 'notes': ''},
|
||||
{'item': 'Towels replaced', 'completed': False, 'notes': ''},
|
||||
{'item': 'Amenities restocked', 'completed': False, 'notes': ''},
|
||||
{'item': 'Floor vacuumed and mopped', 'completed': False, 'notes': ''},
|
||||
{'item': 'Surfaces dusted', 'completed': False, 'notes': ''},
|
||||
{'item': 'Windows and mirrors cleaned', 'completed': False, 'notes': ''},
|
||||
]
|
||||
|
||||
housekeeping_task = HousekeepingTask(
|
||||
room_id=room.id,
|
||||
booking_id=booking.id,
|
||||
task_type=HousekeepingType.checkout,
|
||||
status=HousekeepingStatus.pending,
|
||||
scheduled_time=datetime.utcnow(),
|
||||
created_by=admin_role.id if admin_role else (staff_role.id if staff_role else None),
|
||||
checklist_items=checkout_checklist,
|
||||
notes=f'Auto-created on checkout for booking {booking.booking_number}',
|
||||
estimated_duration_minutes=45
|
||||
)
|
||||
db.add(housekeeping_task)
|
||||
except ImportError:
|
||||
pass # If housekeeping models not available, skip task creation
|
||||
except ImportError:
|
||||
# If maintenance model not available, just set to cleaning
|
||||
room.status = RoomStatus.cleaning
|
||||
bookings_data.append({
|
||||
'number': booking.booking_number,
|
||||
'room': room.room_number,
|
||||
'status': 'checked_out',
|
||||
'check_out': check_out_date.strftime('%Y-%m-%d')
|
||||
})
|
||||
print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Checked out {days_ago} day(s) ago')
|
||||
|
||||
# 2. Current bookings (checked in) - Guests currently staying
|
||||
print('\n📅 Creating current bookings (checked in)...')
|
||||
for i in range(2):
|
||||
room = random.choice(rooms)
|
||||
customer = random.choice(customers)
|
||||
|
||||
# Checked in 1-3 days ago, checking out in 1-3 days
|
||||
days_ago = random.randint(1, 3)
|
||||
check_in_date = now - timedelta(days=days_ago)
|
||||
check_out_date = now + timedelta(days=random.randint(1, 3))
|
||||
|
||||
base_price = float(room.price) if room.price else 100.0
|
||||
num_nights = (check_out_date - check_in_date).days
|
||||
total_price = base_price * num_nights
|
||||
|
||||
booking = Booking(
|
||||
booking_number=generate_booking_number(),
|
||||
user_id=customer.id,
|
||||
room_id=room.id,
|
||||
check_in_date=check_in_date,
|
||||
check_out_date=check_out_date,
|
||||
num_guests=random.randint(1, min(room.capacity, 4)),
|
||||
total_price=total_price,
|
||||
status=BookingStatus.checked_in,
|
||||
deposit_paid=True,
|
||||
requires_deposit=False,
|
||||
special_requests=f'Sample booking for testing - Currently checked in'
|
||||
)
|
||||
db.add(booking)
|
||||
db.flush() # Flush to get booking ID
|
||||
|
||||
# Set room status to occupied for checked in bookings
|
||||
room.status = RoomStatus.occupied
|
||||
bookings_data.append({
|
||||
'number': booking.booking_number,
|
||||
'room': room.room_number,
|
||||
'status': 'checked_in',
|
||||
'check_out': check_out_date.strftime('%Y-%m-%d')
|
||||
})
|
||||
print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Checked in {days_ago} day(s) ago')
|
||||
|
||||
# 3. Future bookings (confirmed) - Upcoming reservations
|
||||
print('\n📅 Creating future bookings (confirmed)...')
|
||||
for i in range(3):
|
||||
room = random.choice(rooms)
|
||||
customer = random.choice(customers)
|
||||
|
||||
# Check-in in 1-7 days, staying for 2-5 days
|
||||
days_ahead = random.randint(1, 7)
|
||||
check_in_date = now + timedelta(days=days_ahead)
|
||||
check_out_date = check_in_date + timedelta(days=random.randint(2, 5))
|
||||
|
||||
base_price = float(room.price) if room.price else 100.0
|
||||
num_nights = (check_out_date - check_in_date).days
|
||||
total_price = base_price * num_nights
|
||||
|
||||
booking = Booking(
|
||||
booking_number=generate_booking_number(),
|
||||
user_id=customer.id,
|
||||
room_id=room.id,
|
||||
check_in_date=check_in_date,
|
||||
check_out_date=check_out_date,
|
||||
num_guests=random.randint(1, min(room.capacity, 4)),
|
||||
total_price=total_price,
|
||||
status=BookingStatus.confirmed,
|
||||
deposit_paid=random.choice([True, False]),
|
||||
requires_deposit=random.choice([True, False]),
|
||||
special_requests=f'Sample booking for testing - Future reservation'
|
||||
)
|
||||
db.add(booking)
|
||||
bookings_data.append({
|
||||
'number': booking.booking_number,
|
||||
'room': room.room_number,
|
||||
'status': 'confirmed',
|
||||
'check_in': check_in_date.strftime('%Y-%m-%d')
|
||||
})
|
||||
print(f' ✓ Created booking {booking.booking_number} - Room {room.room_number}, Check-in in {days_ahead} day(s)')
|
||||
|
||||
db.commit()
|
||||
|
||||
print(f'\n✅ Successfully created {len(bookings_data)} sample bookings!')
|
||||
print(f'\n📊 Summary:')
|
||||
checked_out = sum(1 for b in bookings_data if b['status'] == 'checked_out')
|
||||
checked_in = sum(1 for b in bookings_data if b['status'] == 'checked_in')
|
||||
confirmed = sum(1 for b in bookings_data if b['status'] == 'confirmed')
|
||||
print(f' - Checked out: {checked_out} (rooms should be in cleaning status)')
|
||||
print(f' - Checked in: {checked_in} (guests currently staying)')
|
||||
print(f' - Confirmed: {confirmed} (upcoming reservations)')
|
||||
print('\n💡 To test notifications:')
|
||||
print(' 1. Log in as staff user (staff@gnxsoft.com / staff123)')
|
||||
print(' 2. Go to Bookings and mark a checked_in booking as checked_out')
|
||||
print(' 3. Log in as housekeeping user (housekeeping@gnxsoft.com / P4eli240453.)')
|
||||
print(' 4. You should receive a notification about the room needing cleaning')
|
||||
print('=' * 80)
|
||||
|
||||
def main():
|
||||
db = get_db()
|
||||
try:
|
||||
seed_bookings(db)
|
||||
except Exception as e:
|
||||
print(f'\n❌ Error: {e}')
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
db.rollback()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user