107 lines
4.3 KiB
Python
107 lines
4.3 KiB
Python
"""
|
||
Симулятор вебхука Pally для локального тестирования.
|
||
|
||
Использование:
|
||
python tests/send_test_webhook.py --user-id 123456789 --amount 300 --bill-id 1
|
||
|
||
Предварительно:
|
||
- API должен быть запущен: uvicorn api.main:app --port 8000
|
||
- Пользователь с --user-id должен существовать в БД
|
||
- Счёт с --bill-id должен существовать в БД и принадлежать этому пользователю
|
||
"""
|
||
|
||
import argparse
|
||
import hashlib
|
||
import os
|
||
|
||
import httpx
|
||
from dotenv import load_dotenv
|
||
|
||
load_dotenv()
|
||
|
||
ENDPOINT = "/pally/result"
|
||
|
||
|
||
def calculate_signature(
|
||
out_sum: str,
|
||
inv_id: str,
|
||
pally_token: str,
|
||
) -> str:
|
||
raw = f"{out_sum}:{inv_id}:{pally_token}"
|
||
return hashlib.md5(raw.encode()).hexdigest().upper()
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser()
|
||
parser.add_argument("--user-id", type=int, required=True)
|
||
parser.add_argument("--amount", type=int, required=True)
|
||
parser.add_argument("--bill-id", type=int, required=True)
|
||
parser.add_argument("--host", default="http://127.0.0.1:8000")
|
||
parser.add_argument(
|
||
"--status",
|
||
default="SUCCESS",
|
||
choices=["SUCCESS", "FAIL", "UNDERPAID", "OVERPAID"],
|
||
help="Статус платежа (по умолчанию SUCCESS)",
|
||
)
|
||
parser.add_argument(
|
||
"--customer-pays-fees",
|
||
action="store_true",
|
||
help="Симулировать сценарий 'клиент платит комиссию'",
|
||
)
|
||
args = parser.parse_args()
|
||
|
||
pally_token = os.environ["PALLY_TOKEN"]
|
||
|
||
# ИСПРАВЛЕНО: InvId должен содержать ID счета из БД (это order_id при создании счета)
|
||
# Именно InvId используется в webhook handler для поиска счета в БД
|
||
inv_id = str(args.bill_id) # InvId = bill ID из нашей БД (order_id при создании)
|
||
trs_id = f"LXZv3R{args.bill_id}" # TrsId - уникальный идентификатор счета в Pally
|
||
currency = "RUB"
|
||
custom = None # custom field не используется в production (остается None)
|
||
|
||
# Симуляция комиссии
|
||
if args.customer_pays_fees:
|
||
# Симулируем комиссию ~10% (как в вашем продакшене: 50 -> 55.4)
|
||
commission_rate = 0.108 # ~10.8%
|
||
gross_amount = args.amount * (1 + commission_rate)
|
||
commission = gross_amount - args.amount
|
||
|
||
print(f"customer pays fee:")
|
||
print(f" Сумма заказа: {args.amount} RUB")
|
||
print(f" Комиссия: {commission:.2f} RUB")
|
||
print(f" Итого к оплате: {gross_amount:.2f} RUB")
|
||
print(f" К зачислению: {args.amount} RUB")
|
||
else:
|
||
gross_amount = args.amount
|
||
commission = 0.00
|
||
|
||
# Сигнатура рассчитывается с использованием InvId (который содержит bill ID)
|
||
signature = calculate_signature(f"{gross_amount:.2f}", inv_id, pally_token)
|
||
|
||
# Используем правильные имена полей согласно документации pally.info
|
||
payload = {
|
||
"InvId": inv_id, # Содержит ID счета из БД
|
||
"OutSum": f"{gross_amount:.2f}", # Сумма, которую заплатил клиент (с комиссией)
|
||
"Commission": f"{commission:.2f}",
|
||
"TrsId": trs_id,
|
||
"Status": args.status,
|
||
"CurrencyIn": currency,
|
||
"custom": custom, # None в production
|
||
"SignatureValue": signature,
|
||
}
|
||
|
||
# Добавляем BalanceAmount только если клиент платит комиссию
|
||
if args.customer_pays_fees:
|
||
payload["BalanceAmount"] = str(args.amount) # Сумма к зачислению (без комиссии)
|
||
payload["BalanceCurrency"] = currency
|
||
|
||
print(f"{args.host}{ENDPOINT}")
|
||
print(f"Отправляю вебхук: {payload}\n")
|
||
response = httpx.post(f"{args.host}{ENDPOINT}", data=payload)
|
||
print(f"Статус ответа: {response.status_code}")
|
||
print(f"Тело ответа: {response.text}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|