""" 프랜차이즈 관리 라우터 - 프랜차이즈 정보 조회 - 프랜차이즈 수정 - 프랜차이즈 전체 통계 """ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from sqlalchemy import func from datetime import datetime, date from database import get_db from models import Franchise, Store, User, WaitingList, DailyClosing, Member from schemas import Franchise as FranchiseSchema, FranchiseUpdate from auth import get_current_user, require_franchise_admin router = APIRouter() @router.get("/", response_model=FranchiseSchema) async def get_franchise( current_user: User = Depends(require_franchise_admin), db: Session = Depends(get_db) ): """프랜차이즈 정보 조회 Returns: Franchise: 프랜차이즈 정보 """ franchise = db.query(Franchise).filter( Franchise.id == current_user.franchise_id ).first() if not franchise: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="프랜차이즈를 찾을 수 없습니다" ) return franchise @router.put("/{franchise_id}", response_model=FranchiseSchema) async def update_franchise( franchise_id: int, franchise_update: FranchiseUpdate, current_user: User = Depends(require_franchise_admin), db: Session = Depends(get_db) ): """프랜차이즈 정보 수정 Args: franchise_id: 프랜차이즈 ID franchise_update: 수정할 프랜차이즈 정보 Returns: Franchise: 수정된 프랜차이즈 정보 """ # 권한 체크: 자신의 프랜차이즈만 수정 가능 if current_user.franchise_id != franchise_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="다른 프랜차이즈를 수정할 권한이 없습니다" ) franchise = db.query(Franchise).filter(Franchise.id == franchise_id).first() if not franchise: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="프랜차이즈를 찾을 수 없습니다" ) # 수정 update_data = franchise_update.dict(exclude_unset=True) for key, value in update_data.items(): setattr(franchise, key, value) franchise.updated_at = datetime.now() db.commit() db.refresh(franchise) return franchise @router.get("/stats") async def get_franchise_stats( current_user: User = Depends(require_franchise_admin), db: Session = Depends(get_db) ): """프랜차이즈 전체 통계 조회 Returns: dict: 프랜차이즈 전체 통계 정보 """ franchise_id = current_user.franchise_id # 매장 수 total_stores = db.query(func.count(Store.id)).filter( Store.franchise_id == franchise_id, Store.is_active == True ).scalar() # 활성 매장 수 active_stores = db.query(func.count(Store.id)).filter( Store.franchise_id == franchise_id, Store.is_active == True ).scalar() # 오늘 날짜 today = date.today() # 프랜차이즈 전체 매장의 오늘 통계 Query query = db.query(Store).filter( Store.franchise_id == franchise_id, Store.is_active == True ) # franchise_manager인 경우 관리 매장만 필터링 if current_user.role == 'franchise_manager': managed_ids = [s.id for s in current_user.managed_stores] if not managed_ids: # 관리 매장이 없는 경우 빈 결과 반환 return { 'franchise_id': franchise_id, 'total_stores': 0, 'active_stores': 0, 'total_users': 0, # Note: This might need adjustment if users are also scoped 'total_members': 0, 'today_stats': { 'total_waiting': 0, 'total_attended': 0, 'total_cancelled': 0 }, 'current_waiting': 0, 'stores': [] } query = query.filter(Store.id.in_(managed_ids)) stores = query.all() store_ids = [store.id for store in stores] # 오늘의 대기 통계 (모든 매장 합계) today_stats = db.query( func.coalesce(func.sum(DailyClosing.total_waiting), 0).label('total_waiting'), func.coalesce(func.sum(DailyClosing.total_attended), 0).label('total_attended'), func.coalesce(func.sum(DailyClosing.total_cancelled), 0).label('total_cancelled') ).filter( DailyClosing.store_id.in_(store_ids), DailyClosing.business_date == today ).first() # 현재 대기 중인 고객 수 (모든 매장 합계) current_waiting = db.query(func.count(WaitingList.id)).filter( WaitingList.store_id.in_(store_ids), WaitingList.status == 'waiting' ).scalar() # 총 사용자 수 total_users = db.query(func.count(User.id)).filter( User.franchise_id == franchise_id ).scalar() # 총 회원 수 (모든 매장 합계) total_members = db.query(func.count(Member.id)).filter( Member.store_id.in_(store_ids) ).scalar() if store_ids else 0 # 매장별 간단한 통계 store_stats = [] for store in stores: # 매장의 오늘 통계 store_today = db.query(DailyClosing).filter( DailyClosing.store_id == store.id, DailyClosing.business_date == today ).first() # 매장의 현재 대기 수 store_waiting = db.query(func.count(WaitingList.id)).filter( WaitingList.store_id == store.id, WaitingList.status == 'waiting' ).scalar() store_stats.append({ 'store_id': store.id, 'store_name': store.name, 'store_code': store.code, 'current_waiting': store_waiting, 'today_total': store_today.total_waiting if store_today else 0, 'today_attended': store_today.total_attended if store_today else 0, 'today_cancelled': store_today.total_cancelled if store_today else 0, 'is_open': store_today.is_closed == False if store_today else False }) return { 'franchise_id': franchise_id, 'total_stores': total_stores, 'active_stores': active_stores, 'total_users': total_users, 'total_members': total_members, 'today_stats': { 'total_waiting': today_stats.total_waiting if today_stats else 0, 'total_attended': today_stats.total_attended if today_stats else 0, 'total_cancelled': today_stats.total_cancelled if today_stats else 0 }, 'current_waiting': current_waiting, 'stores': store_stats }