feat: Implement payment notification system and API structure
- Added notifications for successful payments in `api/core/notifications.py`. - Created main API entry point in `api/main.py` with FastAPI integration. - Established routing structure in `api/routes/__init__.py` and `api/routes/pally.py` for handling payment callbacks. - Developed billing handlers in `bot/handlers/billing.py` and `bot/handlers/buy.py` for subscription management. - Introduced state management for user interactions in `bot/states/`. - Created user interface elements in `bot/keyboards/` for navigation and payment processing. - Set up middleware for dependency injection in `bot/middlewares/di.py`. - Added support for user commands and interactions in `bot/handlers/common.py` and `bot/handlers/support.py`. - Implemented logging and error handling throughout the bot's functionality. - Created entry point script for API server in `entrypoints/api.sh`.
This commit is contained in:
78
api/routes/pally.py
Normal file
78
api/routes/pally.py
Normal file
@@ -0,0 +1,78 @@
|
||||
import hashlib
|
||||
import logging
|
||||
import math
|
||||
|
||||
from aiogram import Bot
|
||||
from fastapi import Depends, Form, HTTPException
|
||||
from fastapi.routing import APIRouter
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from api.core.deps import get_bot, get_db, get_deps
|
||||
from api.core.notifications import successful_payment_notification
|
||||
from config import settings
|
||||
from misc.pally import BillStatus
|
||||
from schemas.di import APIDependenciesDTO
|
||||
|
||||
router = APIRouter(prefix="/checkout/pally")
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.post("/callback")
|
||||
async def pally_callback(
|
||||
id: str = Form(...),
|
||||
bill_id: str = Form(...),
|
||||
status: str = Form(...),
|
||||
req_amount: str = Form(...),
|
||||
currency: str = Form(...),
|
||||
order_id: str | None = Form(None),
|
||||
signature: str = Form(...),
|
||||
session: AsyncSession = Depends(get_db),
|
||||
bot: Bot = Depends(get_bot),
|
||||
deps: APIDependenciesDTO = Depends(get_deps),
|
||||
):
|
||||
oid = order_id or ""
|
||||
raw_string = f"{id}{status}{req_amount}{currency}{oid}{settings.pally_token}"
|
||||
md5_hash = hashlib.md5(raw_string.encode("utf-8")).hexdigest()
|
||||
expected_signature = hashlib.sha1(md5_hash.encode("utf-8")).hexdigest()
|
||||
|
||||
if signature != expected_signature:
|
||||
logger.critical("Invalid signature for bill %s", bill_id)
|
||||
raise HTTPException(403, detail="Invalid signature.")
|
||||
|
||||
if status != BillStatus.SUCCESS or not req_amount.isdigit():
|
||||
logger.info("Bill %s skipped: status=%s, req_amount=%s", bill_id, status, req_amount)
|
||||
return "OK"
|
||||
|
||||
logger.info("Received successfully paid bill %s", bill_id)
|
||||
|
||||
if not oid.isdigit():
|
||||
logger.critical("Invalid order_id format for bill %s", bill_id)
|
||||
return "OK"
|
||||
|
||||
bill = await deps.bills_repository.get_bill_by_id(session, int(oid))
|
||||
|
||||
if not bill:
|
||||
logger.critical("Bill %s is not found in db", bill_id)
|
||||
return "OK"
|
||||
|
||||
try:
|
||||
amount = int(req_amount)
|
||||
|
||||
await deps.user_repository.increase_user_balance(session, bill.creator_id, amount=amount)
|
||||
await successful_payment_notification(bot, bill.creator_id, amount)
|
||||
|
||||
referal = bill.user.referal_id
|
||||
if referal is not None:
|
||||
referal_amount = math.floor(amount * (settings.referal_bonus / 100))
|
||||
await deps.user_repository.increase_user_balance(session, referal, referal_amount)
|
||||
await successful_payment_notification(bot, referal, referal_amount)
|
||||
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Exception caught while processing balances for bill %s (Creator: %s)",
|
||||
bill_id,
|
||||
bill.creator_id,
|
||||
)
|
||||
|
||||
return "OK"
|
||||
Reference in New Issue
Block a user