fix(pally): use InvId as primary bill identifier instead of custom field

This commit is contained in:
2026-05-31 15:17:48 +07:00
parent 936d1ad260
commit 18f994aed9
2 changed files with 21 additions and 14 deletions

View File

@@ -45,7 +45,10 @@ async def pally_callback(
bot: Bot = Depends(get_bot), bot: Bot = Depends(get_bot),
deps: APIDependenciesDTO = Depends(get_deps), deps: APIDependenciesDTO = Depends(get_deps),
): ):
oid = custom or "" # FIXED: Use InvId (which contains the order_id from bill creation) instead of custom field
# The InvId field contains the db_bill.id that was passed as order_id during bill creation
bill_id_str = InvId
logger.info( logger.info(
"Pally webhook received - InvId: %s, OutSum: %s, Commission: %s, TrsId: %s, Status: %s, " "Pally webhook received - InvId: %s, OutSum: %s, Commission: %s, TrsId: %s, Status: %s, "
"CurrencyIn: %s, custom: %s, SignatureValue: %s", "CurrencyIn: %s, custom: %s, SignatureValue: %s",
@@ -80,16 +83,19 @@ async def pally_callback(
logger.info("Processing successfully paid bill %s", TrsId) logger.info("Processing successfully paid bill %s", TrsId)
# Validate custom field (order ID) # Validate bill ID (from InvId field, which contains the order_id from bill creation)
if not oid or not oid.isdigit(): if not bill_id_str or not bill_id_str.isdigit():
logger.critical("Invalid or missing custom field for TrsId %s: '%s'", TrsId, custom) logger.critical(
"Invalid or non-numeric bill ID in InvId field for TrsId %s: '%s'",
TrsId, bill_id_str
)
return "OK" return "OK"
# Find bill in database # Find bill in database
bill = await deps.bills_repository.get_bill_by_id(session, int(oid)) bill = await deps.bills_repository.get_bill_by_id(session, int(bill_id_str))
if not bill: if not bill:
logger.critical("Bill %s not found in database for TrsId %s", oid, TrsId) logger.critical("Bill %s not found in database for TrsId %s", bill_id_str, TrsId)
return "OK" return "OK"
# Check if already processed # Check if already processed

View File

@@ -46,27 +46,28 @@ def main():
pally_token = os.environ["PALLY_TOKEN"] pally_token = os.environ["PALLY_TOKEN"]
# Корректные поля согласно документации pally.info # ИСПРАВЛЕНО: InvId должен содержать ID счета из БД (это order_id при создании счета)
inv_id = f"payment-{args.bill_id}" # InvId - идентификатор платежа # Именно InvId используется в webhook handler для поиска счета в БД
trs_id = f"LXZv3R{args.bill_id}" # TrsId - уникальный идентификатор счета inv_id = str(args.bill_id) # InvId = bill ID из нашей БД (order_id при создании)
trs_id = f"LXZv3R{args.bill_id}" # TrsId - уникальный идентификатор счета в Pally
currency = "RUB" currency = "RUB"
custom = str(args.bill_id) # custom field содержит ID счета в нашей БД custom = None # custom field не используется в production (остается None)
commission = "0.00" # Комиссия commission = "0.00" # Комиссия
# ИСПРАВЛЕНО: используем inv_id вместо payment_id для сигнатуры # Сигнатура рассчитывается с использованием InvId (который содержит bill ID)
signature = calculate_signature( signature = calculate_signature(
str(args.amount), inv_id, pally_token str(args.amount), inv_id, pally_token
) )
# ИСПРАВЛЕНО: используем правильные имена полей согласно документации # Используем правильные имена полей согласно документации pally.info
payload = { payload = {
"InvId": inv_id, "InvId": inv_id, # Содержит ID счета из БД
"OutSum": str(args.amount), "OutSum": str(args.amount),
"Commission": commission, "Commission": commission,
"TrsId": trs_id, "TrsId": trs_id,
"Status": args.status, "Status": args.status,
"CurrencyIn": currency, "CurrencyIn": currency,
"custom": custom, "custom": custom, # None в production
"SignatureValue": signature, "SignatureValue": signature,
} }