Files
vpn-control-panel/app/api/v1/payments.py
smolkik-code 7c7c88621d Initial commit: VPN Control Panel
- FastAPI REST API with JWT auth
- aiogram 3 Telegram bot with admin middleware
- APScheduler daily tasks (expiry, reminders, revoke, sync)
- SQLAlchemy 2 async ORM with Alembic migrations
- Jinja2 admin panel (Dashboard, Users, Payments, Servers, Tariffs)
- VPN provider abstraction with MockProvider
- Stats service with revenue/subscription analytics
- Docker Compose (PostgreSQL + Redis + app)
- Healthcheck endpoint
2026-07-05 17:50:11 +07:00

108 lines
3.3 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from app.api.deps import (
get_payment_service,
get_billing_service,
get_notification_service,
)
from app.schemas.payment import PaymentRead, PaymentCreate, PaymentConfirm
from app.services import PaymentService, BillingService, NotificationService
router = APIRouter(prefix="/payments", tags=["Payments"])
@router.post("", response_model=PaymentRead, status_code=status.HTTP_201_CREATED)
async def create_payment(
body: PaymentCreate,
payment_svc: PaymentService = Depends(get_payment_service),
):
try:
return await payment_svc.create(
user_id=body.user_id,
tariff_id=body.tariff_id,
provider=body.provider,
amount=body.amount,
currency=body.currency,
external_id=body.external_id,
)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/{payment_id}", response_model=PaymentRead)
async def get_payment(
payment_id: int,
payment_svc: PaymentService = Depends(get_payment_service),
):
payment = await payment_svc.get_by_id(payment_id)
if payment is None:
raise HTTPException(status_code=404, detail="Payment not found")
return payment
@router.get("/by-external/{external_id}", response_model=PaymentRead)
async def get_payment_by_external(
external_id: str,
payment_svc: PaymentService = Depends(get_payment_service),
):
payment = await payment_svc.get_by_external_id(external_id)
if payment is None:
raise HTTPException(status_code=404, detail="Payment not found")
return payment
@router.post("/{payment_id}/confirm", response_model=PaymentRead)
async def confirm_payment(
payment_id: int,
body: PaymentConfirm = PaymentConfirm(),
payment_svc: PaymentService = Depends(get_payment_service),
billing_svc: BillingService = Depends(get_billing_service),
notification_svc: NotificationService = Depends(get_notification_service),
):
try:
payment = await payment_svc.confirm(payment_id, body.external_id)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
await billing_svc.activate_subscription(
payment.user_id, payment.tariff_id, payment.id
)
await notification_svc.send_success(
payment.user_id,
"Payment confirmed",
f"Payment {payment.id} confirmed. Subscription activated.",
)
return payment
@router.post("/{payment_id}/fail", response_model=PaymentRead)
async def fail_payment(
payment_id: int,
payment_svc: PaymentService = Depends(get_payment_service),
):
try:
return await payment_svc.fail(payment_id)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.post("/{payment_id}/refund", response_model=PaymentRead)
async def refund_payment(
payment_id: int,
payment_svc: PaymentService = Depends(get_payment_service),
):
try:
return await payment_svc.refund(payment_id)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/user/{user_id}", response_model=list[PaymentRead])
async def get_user_payments(
user_id: int,
payment_svc: PaymentService = Depends(get_payment_service),
):
return await payment_svc.get_user_payments(user_id)