# ruff: noqa: N803 import logging from fastapi import Depends, Form, HTTPException from fastapi.routing import APIRouter from sqlalchemy.ext.asyncio import AsyncSession from core.deps import get_db from external.pally import BillStatus from services.payments import process_subscription_purchase, validate_pally_signature router = APIRouter(prefix="/payments/pally") logger = logging.getLogger(__name__) @router.post("/result") async def pally_callback( *, InvId: str = Form(...), OutSum: str = Form(...), Commission: str = Form(...), TrsId: str = Form(...), Status: str = Form(...), CurrencyIn: str = Form(...), custom: str | None = Form(None), SignatureValue: str = Form(...), AccountType: str | None = Form(None), AccountNumber: str | None = Form(None), BalanceAmount: str | None = Form(None), BalanceCurrency: str | None = Form(None), PayerPhone: str | None = Form(None), PayerEmail: str | None = Form(None), PayerName: str | None = Form(None), PayerComment: str | None = Form(None), ErrorCode: int | None = Form(None), ErrorMessage: str | None = Form(None), session: AsyncSession = Depends(get_db), ): logger.info( "Pally webhook received - InvId: %s, OutSum: %s, Commission: %s, TrsId: %s, Status: %s, " "CurrencyIn: %s, custom: %s, BalanceAmount: %s, SignatureValue: %s", InvId, OutSum, Commission, TrsId, Status, CurrencyIn, custom, BalanceAmount, SignatureValue, ) if Status != BillStatus.SUCCESS: logger.warning( "Non-success payment received - Status: %s, ErrorCode: %s, ErrorMessage: %s, TrsId: %s", Status, ErrorCode, ErrorMessage, TrsId, ) if not validate_pally_signature(OutSum, InvId, SignatureValue): logger.critical( "SECURITY ALERT: Invalid signature for TrsId %s", TrsId, ) raise HTTPException(403, detail="Invalid signature.") if Status != BillStatus.SUCCESS: logger.info("Bill %s skipped: status=%s", TrsId, Status) return "OK" invoice_id_str = InvId if not invoice_id_str or not invoice_id_str.isdigit(): logger.critical( "Invalid or non-numeric bill ID in InvId field for TrsId %s: '%s'", TrsId, invoice_id_str, ) return "OK" amount = int(float(BalanceAmount)) if BalanceAmount is not None else int(float(OutSum)) await process_subscription_purchase( session, invoice_id=int(invoice_id_str), trs_id=TrsId, amount=amount, ) return "OK"