update
This commit is contained in:
@@ -10,6 +10,8 @@ from ..models.user import User
|
||||
from ..models.booking import Booking, BookingStatus
|
||||
from ..models.payment import Payment, PaymentStatus
|
||||
from ..models.room import Room
|
||||
from ..models.service_usage import ServiceUsage
|
||||
from ..models.service import Service
|
||||
|
||||
router = APIRouter(prefix="/reports", tags=["reports"])
|
||||
|
||||
@@ -140,6 +142,33 @@ async def get_reports(
|
||||
for room_id, room_number, bookings, revenue in top_rooms_data
|
||||
]
|
||||
|
||||
# Service usage statistics
|
||||
service_usage_query = db.query(
|
||||
Service.id,
|
||||
Service.name,
|
||||
func.count(ServiceUsage.id).label('usage_count'),
|
||||
func.sum(ServiceUsage.total_price).label('total_revenue')
|
||||
).join(ServiceUsage, Service.id == ServiceUsage.service_id)
|
||||
|
||||
if start_date:
|
||||
service_usage_query = service_usage_query.filter(ServiceUsage.usage_date >= start_date)
|
||||
if end_date:
|
||||
service_usage_query = service_usage_query.filter(ServiceUsage.usage_date <= end_date)
|
||||
|
||||
service_usage_data = service_usage_query.group_by(Service.id, Service.name).order_by(
|
||||
func.sum(ServiceUsage.total_price).desc()
|
||||
).limit(10).all()
|
||||
|
||||
service_usage = [
|
||||
{
|
||||
"service_id": service_id,
|
||||
"service_name": service_name,
|
||||
"usage_count": int(usage_count or 0),
|
||||
"total_revenue": float(total_revenue or 0)
|
||||
}
|
||||
for service_id, service_name, usage_count, total_revenue in service_usage_data
|
||||
]
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"success": True,
|
||||
@@ -152,6 +181,7 @@ async def get_reports(
|
||||
"revenue_by_date": revenue_by_date if revenue_by_date else None,
|
||||
"bookings_by_status": bookings_by_status,
|
||||
"top_rooms": top_rooms if top_rooms else None,
|
||||
"service_usage": service_usage if service_usage else None,
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
@@ -221,6 +251,171 @@ async def get_dashboard_stats(
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/customer/dashboard")
|
||||
async def get_customer_dashboard_stats(
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get customer dashboard statistics"""
|
||||
try:
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Total bookings count for user
|
||||
total_bookings = db.query(Booking).filter(
|
||||
Booking.user_id == current_user.id
|
||||
).count()
|
||||
|
||||
# Total spending (sum of completed payments from user's bookings)
|
||||
user_bookings = db.query(Booking.id).filter(
|
||||
Booking.user_id == current_user.id
|
||||
).subquery()
|
||||
|
||||
total_spending = db.query(func.sum(Payment.amount)).filter(
|
||||
and_(
|
||||
Payment.booking_id.in_(db.query(user_bookings.c.id)),
|
||||
Payment.payment_status == PaymentStatus.completed
|
||||
)
|
||||
).scalar() or 0.0
|
||||
|
||||
# Currently staying (checked_in bookings)
|
||||
now = datetime.utcnow()
|
||||
currently_staying = db.query(Booking).filter(
|
||||
and_(
|
||||
Booking.user_id == current_user.id,
|
||||
Booking.status == BookingStatus.checked_in,
|
||||
Booking.check_in_date <= now,
|
||||
Booking.check_out_date >= now
|
||||
)
|
||||
).count()
|
||||
|
||||
# Upcoming bookings (confirmed/pending with check_in_date in future)
|
||||
upcoming_bookings_query = db.query(Booking).filter(
|
||||
and_(
|
||||
Booking.user_id == current_user.id,
|
||||
Booking.status.in_([BookingStatus.confirmed, BookingStatus.pending]),
|
||||
Booking.check_in_date > now
|
||||
)
|
||||
).order_by(Booking.check_in_date.asc()).limit(5).all()
|
||||
|
||||
upcoming_bookings = []
|
||||
for booking in upcoming_bookings_query:
|
||||
booking_dict = {
|
||||
"id": booking.id,
|
||||
"booking_number": booking.booking_number,
|
||||
"check_in_date": booking.check_in_date.isoformat() if booking.check_in_date else None,
|
||||
"check_out_date": booking.check_out_date.isoformat() if booking.check_out_date else None,
|
||||
"status": booking.status.value if isinstance(booking.status, BookingStatus) else booking.status,
|
||||
"total_price": float(booking.total_price) if booking.total_price else 0.0,
|
||||
}
|
||||
|
||||
if booking.room:
|
||||
booking_dict["room"] = {
|
||||
"id": booking.room.id,
|
||||
"room_number": booking.room.room_number,
|
||||
"room_type": {
|
||||
"name": booking.room.room_type.name if booking.room.room_type else None
|
||||
}
|
||||
}
|
||||
|
||||
upcoming_bookings.append(booking_dict)
|
||||
|
||||
# Recent activity (last 5 bookings ordered by created_at)
|
||||
recent_bookings_query = db.query(Booking).filter(
|
||||
Booking.user_id == current_user.id
|
||||
).order_by(Booking.created_at.desc()).limit(5).all()
|
||||
|
||||
recent_activity = []
|
||||
for booking in recent_bookings_query:
|
||||
activity_type = None
|
||||
if booking.status == BookingStatus.checked_out:
|
||||
activity_type = "Check-out"
|
||||
elif booking.status == BookingStatus.checked_in:
|
||||
activity_type = "Check-in"
|
||||
elif booking.status == BookingStatus.confirmed:
|
||||
activity_type = "Booking Confirmed"
|
||||
elif booking.status == BookingStatus.pending:
|
||||
activity_type = "Booking"
|
||||
else:
|
||||
activity_type = "Booking"
|
||||
|
||||
activity_dict = {
|
||||
"action": activity_type,
|
||||
"booking_id": booking.id,
|
||||
"booking_number": booking.booking_number,
|
||||
"created_at": booking.created_at.isoformat() if booking.created_at else None,
|
||||
}
|
||||
|
||||
if booking.room:
|
||||
activity_dict["room"] = {
|
||||
"room_number": booking.room.room_number,
|
||||
}
|
||||
|
||||
recent_activity.append(activity_dict)
|
||||
|
||||
# Calculate percentage change (placeholder - can be enhanced)
|
||||
# For now, compare last month vs this month
|
||||
last_month_start = (now - timedelta(days=30)).replace(day=1, hour=0, minute=0, second=0)
|
||||
last_month_end = now.replace(day=1, hour=0, minute=0, second=0) - timedelta(seconds=1)
|
||||
|
||||
last_month_bookings = db.query(Booking).filter(
|
||||
and_(
|
||||
Booking.user_id == current_user.id,
|
||||
Booking.created_at >= last_month_start,
|
||||
Booking.created_at <= last_month_end
|
||||
)
|
||||
).count()
|
||||
|
||||
this_month_bookings = db.query(Booking).filter(
|
||||
and_(
|
||||
Booking.user_id == current_user.id,
|
||||
Booking.created_at >= now.replace(day=1, hour=0, minute=0, second=0),
|
||||
Booking.created_at <= now
|
||||
)
|
||||
).count()
|
||||
|
||||
booking_change_percentage = 0
|
||||
if last_month_bookings > 0:
|
||||
booking_change_percentage = ((this_month_bookings - last_month_bookings) / last_month_bookings) * 100
|
||||
|
||||
last_month_spending = db.query(func.sum(Payment.amount)).filter(
|
||||
and_(
|
||||
Payment.booking_id.in_(db.query(user_bookings.c.id)),
|
||||
Payment.payment_status == PaymentStatus.completed,
|
||||
Payment.payment_date >= last_month_start,
|
||||
Payment.payment_date <= last_month_end
|
||||
)
|
||||
).scalar() or 0.0
|
||||
|
||||
this_month_spending = db.query(func.sum(Payment.amount)).filter(
|
||||
and_(
|
||||
Payment.booking_id.in_(db.query(user_bookings.c.id)),
|
||||
Payment.payment_status == PaymentStatus.completed,
|
||||
Payment.payment_date >= now.replace(day=1, hour=0, minute=0, second=0),
|
||||
Payment.payment_date <= now
|
||||
)
|
||||
).scalar() or 0.0
|
||||
|
||||
spending_change_percentage = 0
|
||||
if last_month_spending > 0:
|
||||
spending_change_percentage = ((this_month_spending - last_month_spending) / last_month_spending) * 100
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"success": True,
|
||||
"data": {
|
||||
"total_bookings": total_bookings,
|
||||
"total_spending": float(total_spending),
|
||||
"currently_staying": currently_staying,
|
||||
"upcoming_bookings": upcoming_bookings,
|
||||
"recent_activity": recent_activity,
|
||||
"booking_change_percentage": round(booking_change_percentage, 1),
|
||||
"spending_change_percentage": round(spending_change_percentage, 1),
|
||||
}
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/revenue")
|
||||
async def get_revenue_report(
|
||||
start_date: Optional[str] = Query(None),
|
||||
|
||||
Reference in New Issue
Block a user