Files
malenia/api/routes/pally.py
hexdev 049f31118d 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`.
2026-04-24 17:41:42 +07:00

79 lines
2.6 KiB
Python

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"