import logging from typing import Optional from datetime import datetime, timedelta from fastapi import APIRouter, HTTPException, Query, Depends, status, Body from app.models.merchant import MerchantRegister, GetOtpRequest from app.services.merchant_services import generate_and_send_otp, get_otp_from_cache, verify_otp_and_save_merchant, validate_merchant # Initialize router and logger router = APIRouter(prefix="/merchant") logger = logging.getLogger(__name__) @router.post("/register") async def register_customer(user: MerchantRegister = Body(...)): """ API endpoint to register a new Merchant. Args: user (MerchantRegister): The details of the Merchant to register. Returns: dict: Confirmation message indicating email and SMS verification pending. """ try: logger.info("Registering a new Merchant with Merchant name : %s, email: %s and mobile: %s", user.merchant_name, user.email, user.mobile) # Validate email and mobile format validation_result = await validate_merchant(user) if validation_result["status"] == "error": logger.error("Validation failed: %s", validation_result["errors"]) raise HTTPException(status_code=400, detail=validation_result["errors"]) return user.dict() except HTTPException as e: logger.error("Failed to register merchant: %s", e.detail) raise e except Exception as e: logger.error("Unexpected error while registering merchant: %s", e) raise HTTPException(status_code=500, detail="Failed to register Merchant") from e @router.post("/otp/verify") async def customer_otp_verification(user: MerchantRegister = Body(...)): """ API endpoint to validate OTPs and save the complete Merchant object. Args: user (MerchantRegister): The complete Merchant object including email, mobile, and OTPs. Returns: dict: Confirmation message indicating success or failure. """ try: logger.info("Verifying OTPs and registering merchant with email: %s and mobile: %s", user.email, user.mobile) # Verify OTPs and save customer result = await verify_otp_and_save_merchant(user) if result["status"] == "error": raise HTTPException(status_code=400, detail=result["errors"]) return {"message": "Merchant successfully registered and verified."} except HTTPException as e: logger.error("Failed to verify and register merchant: %s", e.detail) raise e except Exception as e: logger.error("Unexpected error while verifying and registering merchant: %s", e) raise HTTPException(status_code=500, detail="Failed to verify and register merchant") from e @router.post("/otp/get") async def get_otps(payload: GetOtpRequest): """ API endpoint to retrieve the email or SMS OTP from Redis cache. Args: payload (GetOtpRequest): The request payload containing the identifier and type. Returns: dict: The OTP data if found, or an error message if not found. """ try: logger.info("Retrieving OTP for identifier: %s, type: %s", payload.identifier, payload.type) # Construct the Redis key based on the type redis_key = f"otp:{payload.type}:{payload.identifier}" # Retrieve OTP from Redis otp_data = await get_otp_from_cache(redis_key) if not otp_data: raise HTTPException(status_code=404, detail="OTP not found or expired") return {"identifier": payload.identifier, "type": payload.type, "otp_data": otp_data} except HTTPException as e: logger.error("Failed to retrieve OTP for identifier %s, type %s: %s", payload.identifier, payload.type, e.detail) raise e except Exception as e: logger.error("Unexpected error while retrieving OTP for identifier %s, type %s: %s", payload.identifier, payload.type, e) raise HTTPException(status_code=500, detail="Failed to retrieve OTP") from e @router.post("/otp/regenerate") async def regenerate_otp(user: MerchantRegister = Body(...)): """ API endpoint to regenerate an OTP for a given email, mobile number, or both. Args: user (MerchantRegister): The Merchant object containing email and mobile details. Returns: dict: Confirmation message indicating the OTP has been regenerated. """ try: logger.info("Regenerating OTP for Merchant with email: %s and mobile: %s", user.email, user.mobile) # Regenerate OTP for email & mobile if user.email and user.mobile: await generate_and_send_otp(user.email, user.mobile) return {"message": "OTP successfully regenerated for email and/or mobile.", "email": user.email, "mobile": user.mobile} except Exception as e: logger.error("Failed to regenerate OTP for Merchant with email: %s and mobile: %s. Error: %s", user.email, user.mobile, e) raise HTTPException(status_code=500, detail="Failed to regenerate OTP") from e