Spaces:
Sleeping
Sleeping
| """ | |
| Wallet API endpoints. | |
| All routes extract partner_id from JWT token for security. | |
| """ | |
| from typing import Dict, Any | |
| from fastapi import APIRouter, Depends, HTTPException, status, Query | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from app.sql import get_db | |
| from app.wallet.services.service import WalletService | |
| from app.wallet.schemas.schema import ( | |
| WalletResponse, | |
| WalletCreateRequest, | |
| WalletTransactionRequest, | |
| WalletTransactionResponse, | |
| WalletBalanceResponse, | |
| WalletTransactionListRequest, | |
| WalletTransactionListResponse, | |
| ) | |
| from app.core.schemas import StandardResponse | |
| from app.dependencies.auth import get_current_user, get_partner_id, TokenUser | |
| router = APIRouter(prefix="/wallet", tags=["Wallet Management"]) | |
| async def create_wallet( | |
| request: WalletCreateRequest, | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Create a new wallet for the authenticated service professional. | |
| Partner ID is extracted from JWT token. | |
| - **initial_balance**: Starting balance (default: 0.00) | |
| - **currency**: Currency code (default: INR) | |
| The wallet balance is encrypted using AES encryption for security. | |
| """ | |
| try: | |
| partner_id = get_partner_id(current_user) | |
| wallet = await WalletService.create_wallet(db, partner_id, request) | |
| return StandardResponse( | |
| success=True, | |
| message="Wallet created successfully", | |
| data=wallet | |
| ) | |
| except ValueError as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=str(e) | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to create wallet: {str(e)}" | |
| ) | |
| async def get_my_wallet( | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Get wallet details for the authenticated service professional. | |
| Partner ID is extracted from JWT token. | |
| Returns decrypted balance and wallet information. | |
| """ | |
| try: | |
| partner_id = get_partner_id(current_user) | |
| wallet = await WalletService.get_wallet(db, partner_id) | |
| if not wallet: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Wallet not found. Please create a wallet first." | |
| ) | |
| return StandardResponse( | |
| success=True, | |
| message="Wallet retrieved successfully", | |
| data=wallet | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to retrieve wallet: {str(e)}" | |
| ) | |
| async def get_my_balance( | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Get current wallet balance for the authenticated service professional. | |
| Partner ID is extracted from JWT token. | |
| Returns decrypted balance information. | |
| """ | |
| try: | |
| partner_id = get_partner_id(current_user) | |
| balance = await WalletService.get_balance(db, partner_id) | |
| if not balance: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail="Wallet not found. Please create a wallet first." | |
| ) | |
| return StandardResponse( | |
| success=True, | |
| message="Balance retrieved successfully", | |
| data=balance | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to retrieve balance: {str(e)}" | |
| ) | |
| async def create_transaction( | |
| request: WalletTransactionRequest, | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Create a wallet transaction for the authenticated service professional. | |
| Partner ID is extracted from JWT token. | |
| - **transaction_type**: credit or debit | |
| - **amount**: Transaction amount (must be positive) | |
| - **reference_type**: order | refund | topup | commission | withdrawal | |
| - **reference_id**: Related transaction/order reference | |
| - **description**: Transaction description | |
| - **meta_data**: Additional transaction metadata | |
| For debit transactions, validates sufficient balance. | |
| Updates encrypted balance securely. | |
| """ | |
| try: | |
| partner_id = get_partner_id(current_user) | |
| transaction = await WalletService.create_transaction(db, partner_id, request) | |
| return StandardResponse( | |
| success=True, | |
| message="Transaction completed successfully", | |
| data=transaction | |
| ) | |
| except ValueError as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=str(e) | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to create transaction: {str(e)}" | |
| ) | |
| async def list_my_transactions( | |
| request: WalletTransactionListRequest, | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| List wallet transactions for the authenticated service professional. | |
| Partner ID is extracted from JWT token. | |
| - **transaction_type**: Filter by credit or debit | |
| - **reference_type**: Filter by reference type | |
| - **start_date**: Filter transactions from this date | |
| - **end_date**: Filter transactions until this date | |
| - **limit**: Maximum records per page (1-100) | |
| - **offset**: Pagination offset | |
| - **projection_list**: Optional list of fields to include in response | |
| Returns paginated transaction history, or raw list if projection_list is provided. | |
| """ | |
| try: | |
| partner_id = get_partner_id(current_user) | |
| result = await WalletService.list_transactions(db, partner_id, request) | |
| # Return raw list if projection used | |
| if request.projection_list: | |
| return result | |
| return StandardResponse( | |
| success=True, | |
| message="Transactions retrieved successfully", | |
| data=result | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to retrieve transactions: {str(e)}" | |
| ) | |
| # Admin endpoints (optional - for admin/support to manage wallets) | |
| async def admin_get_wallet( | |
| partner_id: str, | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Admin endpoint to get wallet details for any service professional. | |
| TODO: Add admin role verification | |
| - **partner_id**: Service professional identifier | |
| Returns decrypted balance and wallet information. | |
| """ | |
| try: | |
| # TODO: Verify admin role from current_user | |
| wallet = await WalletService.get_wallet(db, partner_id) | |
| if not wallet: | |
| raise HTTPException( | |
| status_code=status.HTTP_404_NOT_FOUND, | |
| detail=f"Wallet not found for partner_id: {partner_id}" | |
| ) | |
| return StandardResponse( | |
| success=True, | |
| message="Wallet retrieved successfully", | |
| data=wallet | |
| ) | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to retrieve wallet: {str(e)}" | |
| ) | |
| async def admin_update_wallet_status( | |
| partner_id: str, | |
| status_value: str = Query(..., alias="status", description="New status: active | suspended | closed"), | |
| db: AsyncSession = Depends(get_db), | |
| current_user: TokenUser = Depends(get_current_user) | |
| ): | |
| """ | |
| Admin endpoint to update wallet status. | |
| TODO: Add admin role verification | |
| - **partner_id**: Service professional identifier | |
| - **status**: New status (active | suspended | closed) | |
| Suspended wallets cannot perform transactions. | |
| Closed wallets are permanently disabled. | |
| """ | |
| try: | |
| # TODO: Verify admin role from token_data | |
| wallet = await WalletService.update_wallet_status(db, partner_id, status_value) | |
| return StandardResponse( | |
| success=True, | |
| message=f"Wallet status updated to {status_value}", | |
| data=wallet | |
| ) | |
| except ValueError as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_400_BAD_REQUEST, | |
| detail=str(e) | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Failed to update wallet status: {str(e)}" | |
| ) | |