This commit is contained in:
Iliyan Angelov
2025-12-05 22:12:32 +02:00
parent 13c91f95f4
commit 7667eb5eda
53 changed files with 3065 additions and 9257 deletions

View File

@@ -12,6 +12,7 @@ from ..models.guest_request import GuestRequest, RequestType, RequestStatus, Req
from ...bookings.models.booking import Booking, BookingStatus
from ...rooms.models.room import Room
from pydantic import BaseModel
from ...shared.utils.sanitization import sanitize_text
logger = get_logger(__name__)
router = APIRouter(prefix='/guest-requests', tags=['guest-requests'])
@@ -163,18 +164,135 @@ async def create_guest_request(
if booking.room_id != request_data.room_id:
raise HTTPException(status_code=400, detail='Room ID does not match booking')
# Sanitize user input to prevent XSS
sanitized_title = sanitize_text(request_data.title)
sanitized_description = sanitize_text(request_data.description) if request_data.description else None
sanitized_guest_notes = sanitize_text(request_data.guest_notes) if request_data.guest_notes else None
guest_request = GuestRequest(
booking_id=request_data.booking_id,
room_id=request_data.room_id,
user_id=current_user.id,
request_type=RequestType(request_data.request_type),
priority=RequestPriority(request_data.priority),
title=request_data.title,
description=request_data.description,
guest_notes=request_data.guest_notes,
title=sanitized_title,
description=sanitized_description,
guest_notes=sanitized_guest_notes,
)
db.add(guest_request)
db.flush() # Flush to get the ID for task creation
# Auto-create housekeeping task for request types that require housekeeping
request_type = RequestType(request_data.request_type)
task_types_requiring_housekeeping = {
RequestType.extra_towels,
RequestType.extra_pillows,
RequestType.room_cleaning,
RequestType.turndown_service,
RequestType.amenities,
}
if request_type in task_types_requiring_housekeeping:
try:
from ...hotel_services.models.housekeeping_task import HousekeepingTask, HousekeepingStatus, HousekeepingType
from ...rooms.models.room import Room
# Determine housekeeping task type based on request type
task_type_map = {
RequestType.room_cleaning: HousekeepingType.stayover,
RequestType.turndown_service: HousekeepingType.turndown,
RequestType.extra_towels: HousekeepingType.stayover,
RequestType.extra_pillows: HousekeepingType.stayover,
RequestType.amenities: HousekeepingType.stayover,
}
housekeeping_task_type = task_type_map.get(request_type, HousekeepingType.stayover)
# Create default checklist based on request type
checklist_items = []
if request_type == RequestType.room_cleaning:
checklist_items = [
{'item': 'Room cleaned', 'completed': False, 'notes': ''},
{'item': 'Bathroom cleaned', 'completed': False, 'notes': ''},
{'item': 'Trash emptied', 'completed': False, 'notes': ''},
{'item': 'Beds made', 'completed': False, 'notes': ''},
]
elif request_type == RequestType.turndown_service:
checklist_items = [
{'item': 'Beds turned down', 'completed': False, 'notes': ''},
{'item': 'Curtains closed', 'completed': False, 'notes': ''},
{'item': 'Lights dimmed', 'completed': False, 'notes': ''},
{'item': 'Amenities refreshed', 'completed': False, 'notes': ''},
]
elif request_type in [RequestType.extra_towels, RequestType.extra_pillows, RequestType.amenities]:
item_name = 'Extra towels' if request_type == RequestType.extra_towels else \
'Extra pillows' if request_type == RequestType.extra_pillows else 'Amenities'
checklist_items = [
{'item': f'{item_name} delivered', 'completed': False, 'notes': request_data.description or ''},
]
# Check if a similar task already exists for this room
existing_task = db.query(HousekeepingTask).filter(
and_(
HousekeepingTask.room_id == request_data.room_id,
HousekeepingTask.task_type == housekeeping_task_type,
HousekeepingTask.status.in_([HousekeepingStatus.pending, HousekeepingStatus.in_progress]),
HousekeepingTask.booking_id == request_data.booking_id
)
).first()
if not existing_task:
# Create housekeeping task
housekeeping_task = HousekeepingTask(
room_id=request_data.room_id,
booking_id=request_data.booking_id,
task_type=housekeeping_task_type,
status=HousekeepingStatus.pending,
scheduled_time=datetime.utcnow(), # Schedule immediately for guest requests
created_by=None, # Created by system/guest request
checklist_items=checklist_items,
notes=f'Auto-created from guest request: {request_data.title}. Guest notes: {request_data.guest_notes or "None"}',
estimated_duration_minutes=15 if request_type in [RequestType.extra_towels, RequestType.extra_pillows, RequestType.amenities] else 30
)
db.add(housekeeping_task)
db.flush()
# Link guest request to housekeeping task via notes
guest_request.staff_notes = f'Auto-created housekeeping task #{housekeeping_task.id}'
# Send notification to housekeeping users
try:
from ...notifications.routes.notification_routes import notification_manager
room = db.query(Room).filter(Room.id == request_data.room_id).first()
task_data_notification = {
'id': housekeeping_task.id,
'room_id': housekeeping_task.room_id,
'room_number': room.room_number if room else None,
'task_type': housekeeping_task.task_type.value,
'status': housekeeping_task.status.value,
'scheduled_time': housekeeping_task.scheduled_time.isoformat() if housekeeping_task.scheduled_time else None,
'guest_request_id': guest_request.id,
'guest_request_title': request_data.title,
'created_at': housekeeping_task.created_at.isoformat() if housekeeping_task.created_at else None
}
notification_data = {
'type': 'housekeeping_task_available',
'data': task_data_notification
}
# Send notification to all housekeeping users
await notification_manager.send_to_role('housekeeping', notification_data)
except Exception as e:
logger.error(f'Error sending housekeeping notification for guest request: {str(e)}', exc_info=True)
logger.info(f'Auto-created housekeeping task {housekeeping_task.id} for guest request {guest_request.id} (type: {request_type.value})')
except Exception as e:
# Don't fail guest request creation if task creation fails
logger.error(f'Error auto-creating housekeeping task for guest request: {str(e)}', exc_info=True)
db.commit()
db.refresh(guest_request)
@@ -378,7 +496,8 @@ async def fulfill_request(
request.fulfilled_at = datetime.utcnow()
if staff_notes:
request.staff_notes = (request.staff_notes or '') + f'\n{staff_notes}' if request.staff_notes else staff_notes
sanitized_notes = sanitize_text(staff_notes)
request.staff_notes = (request.staff_notes or '') + f'\n{sanitized_notes}' if request.staff_notes else sanitized_notes
if request.started_at:
delta = datetime.utcnow() - request.started_at