This commit is contained in:
Iliyan Angelov
2025-12-03 01:31:34 +02:00
parent e32527ae8c
commit 5fb50983a9
37 changed files with 5844 additions and 201 deletions

View 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()