from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from sqlalchemy import func as sql_func from datetime import datetime from typing import List from ..database import get_db from ..models import User, ReferralReward, SystemSettings from ..schemas import ( ReferralRewardResponse, ReferralStats, ReferralSettingsResponse, ReferralSettingsUpdate, ) from .auth import get_current_user from .notification import notify_referral_reward router = APIRouter(prefix="/referral", tags=["referral"]) def get_referral_settings(db: Session) -> SystemSettings: """Get or create system settings""" settings = db.query(SystemSettings).first() if not settings: settings = SystemSettings() db.add(settings) db.commit() db.refresh(settings) return settings def create_referral_reward( referrer_id: int, referred_user_id: int, payment_amount: float, db: Session ): """Create a referral reward when a referred user makes a payment""" settings = get_referral_settings(db) # Check if referral rewards are enabled if not settings.referral_reward_enabled: return None # Check if this is a one_time reward and already exists if settings.referral_reward_type == "one_time": existing = db.query(ReferralReward).filter( ReferralReward.referrer_id == referrer_id, ReferralReward.referred_user_id == referred_user_id ).first() if existing: return None # Already gave reward for this referral # Calculate reward amount reward_amount = payment_amount * (settings.referral_reward_percent / 100) # Create reward record reward = ReferralReward( referrer_id=referrer_id, referred_user_id=referred_user_id, payment_amount=payment_amount, reward_amount=reward_amount, status="credited", # Auto-credit for simplicity credited_at=datetime.utcnow() ) db.add(reward) db.commit() db.refresh(reward) # Send notification to referrer referred_user = db.query(User).filter(User.id == referred_user_id).first() referred_name = referred_user.name or referred_user.email if referred_user else "회원" notify_referral_reward(db, referrer_id, reward_amount, referred_name) return reward @router.get("/my-link") def get_my_referral_link(current_user: User = Depends(get_current_user)): """Get current user's referral link/code""" return { "referral_code": current_user.referral_code, "referral_link": f"/register?ref={current_user.referral_code}" } @router.get("/my-rewards", response_model=List[ReferralRewardResponse]) def get_my_rewards( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """Get current user's referral rewards""" rewards = db.query(ReferralReward).filter( ReferralReward.referrer_id == current_user.id ).order_by(ReferralReward.created_at.desc()).all() return rewards @router.get("/stats", response_model=ReferralStats) def get_referral_stats( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """Get referral statistics for current user""" # Get all rewards where user is the referrer rewards = db.query(ReferralReward).filter( ReferralReward.referrer_id == current_user.id ).all() # Count unique referred users referred_users = db.query(sql_func.count(sql_func.distinct(ReferralReward.referred_user_id))).filter( ReferralReward.referrer_id == current_user.id ).scalar() or 0 total_rewards_earned = sum(r.reward_amount for r in rewards) total_rewards_credited = sum(r.reward_amount for r in rewards if r.status == "credited") total_rewards_pending = sum(r.reward_amount for r in rewards if r.status == "pending") total_withdrawn = sum(r.reward_amount for r in rewards if r.status == "withdrawn") return ReferralStats( total_referrals=referred_users, total_rewards_earned=total_rewards_earned, total_rewards_credited=total_rewards_credited, total_rewards_pending=total_rewards_pending, available_for_withdrawal=total_rewards_credited - total_withdrawn ) @router.get("/settings", response_model=ReferralSettingsResponse) def get_settings( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """Get referral settings (public endpoint)""" settings = get_referral_settings(db) return ReferralSettingsResponse( referral_reward_enabled=settings.referral_reward_enabled, referral_reward_percent=settings.referral_reward_percent, referral_reward_type=settings.referral_reward_type ) # Admin endpoints @router.put("/admin/settings", response_model=ReferralSettingsResponse) def update_settings( update_data: ReferralSettingsUpdate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """[Admin] Update referral settings""" if not current_user.is_admin: raise HTTPException(status_code=403, detail="Admin access required") settings = get_referral_settings(db) if update_data.referral_reward_enabled is not None: settings.referral_reward_enabled = update_data.referral_reward_enabled if update_data.referral_reward_percent is not None: if update_data.referral_reward_percent < 0 or update_data.referral_reward_percent > 100: raise HTTPException(status_code=400, detail="Reward percent must be between 0 and 100") settings.referral_reward_percent = update_data.referral_reward_percent if update_data.referral_reward_type is not None: if update_data.referral_reward_type not in ["one_time", "recurring"]: raise HTTPException(status_code=400, detail="Reward type must be 'one_time' or 'recurring'") settings.referral_reward_type = update_data.referral_reward_type db.commit() db.refresh(settings) return ReferralSettingsResponse( referral_reward_enabled=settings.referral_reward_enabled, referral_reward_percent=settings.referral_reward_percent, referral_reward_type=settings.referral_reward_type ) @router.get("/admin/all-rewards", response_model=List[ReferralRewardResponse]) def admin_get_all_rewards( current_user: User = Depends(get_current_user), db: Session = Depends(get_db) ): """[Admin] Get all referral rewards""" if not current_user.is_admin: raise HTTPException(status_code=403, detail="Admin access required") rewards = db.query(ReferralReward).order_by( ReferralReward.created_at.desc() ).limit(100).all() return rewards