feat: advanced catches at payment processing to prevent the payment loss
This commit is contained in:
@@ -6,7 +6,11 @@ from fastapi.routing import APIRouter
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.deps import get_db
|
||||
from db.models.transactions import BalanceTransaction, BalanceTxType
|
||||
from external.pally import BillStatus
|
||||
from repositories.invoices import InvoiceRepository
|
||||
from repositories.users import UserRepository
|
||||
from schemas.invoices import InvoiceStatus
|
||||
from services.payments import process_subscription_purchase, validate_pally_signature
|
||||
|
||||
router = APIRouter(prefix="/payments/pally")
|
||||
@@ -82,11 +86,69 @@ async def pally_callback(
|
||||
|
||||
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,
|
||||
)
|
||||
try:
|
||||
await process_subscription_purchase(
|
||||
session,
|
||||
invoice_id=int(invoice_id_str),
|
||||
trs_id=TrsId,
|
||||
amount=amount,
|
||||
)
|
||||
except Exception:
|
||||
# The payment is confirmed, so never leave the user without the money
|
||||
# if order/subscription provisioning fails.
|
||||
logger.exception(
|
||||
"Subscription provisioning failed for bill %s (TrsId: %s); "
|
||||
"crediting the user's bonus balance",
|
||||
invoice_id_str,
|
||||
TrsId,
|
||||
)
|
||||
await session.rollback()
|
||||
|
||||
invoice_repo = InvoiceRepository(session)
|
||||
invoice = await invoice_repo.get_by_id(int(invoice_id_str))
|
||||
if invoice is None:
|
||||
logger.critical(
|
||||
"Cannot credit fallback balance: bill %s was not found (TrsId: %s)",
|
||||
invoice_id_str,
|
||||
TrsId,
|
||||
)
|
||||
raise
|
||||
|
||||
if invoice.status == InvoiceStatus.PAID:
|
||||
return "OK"
|
||||
|
||||
user = await UserRepository(session).get_user_by_id(invoice.creator_id)
|
||||
if user is None:
|
||||
logger.critical(
|
||||
"Cannot credit fallback balance: user %s was not found " "for bill %s (TrsId: %s)",
|
||||
invoice.creator_id,
|
||||
invoice_id_str,
|
||||
TrsId,
|
||||
)
|
||||
raise
|
||||
|
||||
balance_before = user.balance
|
||||
user.balance += amount
|
||||
invoice.status = InvoiceStatus.PAID
|
||||
session.add(
|
||||
BalanceTransaction(
|
||||
user_id=user.id,
|
||||
amount=amount,
|
||||
tx_type=BalanceTxType.DEPOSIT,
|
||||
balance_before=balance_before,
|
||||
balance_after=user.balance,
|
||||
description=(
|
||||
f"fallback payment credit for invoice {invoice.id} " f"(TrsId: {TrsId})"
|
||||
),
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
logger.info(
|
||||
"Fallback payment credit processed: user_id=%s, amount=%s, " "invoice_id=%s, TrsId=%s",
|
||||
user.id,
|
||||
amount,
|
||||
invoice.id,
|
||||
TrsId,
|
||||
)
|
||||
|
||||
return "OK"
|
||||
|
||||
Reference in New Issue
Block a user