fix: remove PayKilla redirect fields

This commit is contained in:
3252a8
2026-06-04 15:14:13 +03:00
parent e108cc0baa
commit cd4b40af6b
5 changed files with 11 additions and 135 deletions
+4 -40
View File
@@ -182,9 +182,6 @@ class PaykillaConfig(ProviderEnvConfig):
INVOICE_TYPE: Optional[str] = None
PAYMENT_CURRENCIES: str = Field(default=PAYKILLA_DEFAULT_PAYMENT_CURRENCIES)
SUPPORTED_CURRENCIES: str = Field(default=PAYKILLA_DEFAULT_SUPPORTED_CURRENCIES)
RETURN_URL: Optional[str] = None
SUCCESS_URL: Optional[str] = None
CANCEL_URL: Optional[str] = None
LIFETIME_SECONDS: int = Field(default=3600)
RECV_WINDOW_MS: int = Field(default=5000)
USER_PAYS_SERVICE_FEE: bool = Field(default=True)
@@ -219,9 +216,6 @@ class PaykillaConfig(ProviderEnvConfig):
"API_KEY",
"SECRET_KEY",
"INVOICE_TYPE",
"RETURN_URL",
"SUCCESS_URL",
"CANCEL_URL",
"WEBHOOK_URL",
mode="before",
)
@@ -291,9 +285,10 @@ def _clean_paykilla_text(value: Any, *, fallback: str, max_length: int = 255) ->
return text[:max_length].strip() or fallback_text[:max_length].strip() or "Payment"
def _invoice_text(payment_db_id: int) -> str:
def _invoice_text(title: Any, payment_db_id: int) -> str:
project_title = _clean_paykilla_text(title, fallback="Minishop")
return _clean_paykilla_text(
f"Minishop payment {payment_db_id}",
f"{project_title} payment {payment_db_id}",
fallback=f"Payment {payment_db_id}",
)
@@ -403,18 +398,6 @@ class PaykillaService(HttpClientMixin):
def currency(self) -> str:
return (self.config.CURRENCY or "RUB").upper()
@property
def return_url(self) -> str:
return self.config.RETURN_URL or f"https://t.me/{self._default_return_url}"
@property
def success_url(self) -> str:
return self.config.SUCCESS_URL or self.return_url
@property
def cancel_url(self) -> Optional[str]:
return self.config.CANCEL_URL
@property
def verify_webhook_signature(self) -> bool:
return self.config.VERIFY_WEBHOOK_SIGNATURE
@@ -434,7 +417,7 @@ class PaykillaService(HttpClientMixin):
description: str,
) -> Dict[str, Any]:
currency_code = normalize_payment_currency_code(currency or self.currency)
invoice_text = _invoice_text(payment_db_id)
invoice_text = _invoice_text(getattr(self.settings, "WEBAPP_TITLE", None), payment_db_id)
body: Dict[str, Any] = {
"type": _invoice_type_for(self.config, currency_code),
"purpose": invoice_text,
@@ -451,16 +434,6 @@ class PaykillaService(HttpClientMixin):
seconds=int(self.config.LIFETIME_SECONDS)
)
body["expiredAt"] = expires_at.isoformat().replace("+00:00", "Z")
urls: List[Dict[str, Any]] = []
if self.config.SUCCESS_URL:
urls.append({"type": "SUCCESS", "url": self.config.SUCCESS_URL, "autoRedirect": True})
if self.config.RETURN_URL:
urls.append({"type": "RETURN", "url": self.config.RETURN_URL})
if self.config.CANCEL_URL:
urls.append({"type": "CANCEL", "url": self.config.CANCEL_URL})
if urls:
body["urls"] = urls
return body
async def create_payment_link(
@@ -1053,15 +1026,6 @@ _CONFIG_MANIFEST = (
("OPEN_AMOUNT", "OPEN_AMOUNT"),
),
),
ProviderManifestField(
"PAYKILLA_RETURN_URL", "url", "Return URL", subsection="PayKilla", attr="RETURN_URL"
),
ProviderManifestField(
"PAYKILLA_SUCCESS_URL", "url", "Success URL", subsection="PayKilla", attr="SUCCESS_URL"
),
ProviderManifestField(
"PAYKILLA_CANCEL_URL", "url", "Cancel URL", subsection="PayKilla", attr="CANCEL_URL"
),
ProviderManifestField(
"PAYKILLA_LIFETIME_SECONDS",
"int",
-3
View File
@@ -380,9 +380,6 @@ Webhook настраивается в PayKilla Dashboard: **Settings -> Webhooks
| `PAYKILLA_PAYMENT_CURRENCIES` | Crypto tickers для оплаты, например `USDTTRC,BTC,ETH`. |
| `PAYKILLA_SUPPORTED_CURRENCIES` | Валюты инвойса, разрешенные в этом магазине. |
| `PAYKILLA_INVOICE_TYPE` | Необязательный override: `FIAT_BASED`, `FIXED_AMOUNT` или `OPEN_AMOUNT`. |
| `PAYKILLA_RETURN_URL` | URL кнопки возврата на checkout-странице. |
| `PAYKILLA_SUCCESS_URL` | URL после успешной оплаты; используется с auto-redirect. |
| `PAYKILLA_CANCEL_URL` | URL после отмены оплаты. |
| `PAYKILLA_LIFETIME_SECONDS` | TTL инвойса, отправляется как `expiredAt`. |
| `PAYKILLA_RECV_WINDOW_MS` | `recvWindow` для подписанных API-запросов. |
| `PAYKILLA_USER_PAYS_SERVICE_FEE` | `true`, если пользователь оплачивает service fee. |
+2 -2
View File
@@ -158,7 +158,7 @@ Heleket используется для крипто-инвойсов с отд
PayKilla используется для крипто-инвойсов V2 через hosted checkout `https://gopay.paykilla.com/{invoice_id}`. API-запросы подписываются HMAC-SHA256, webhook проверяется по заголовку `X-API-SIGN` и raw body.
PayKilla строго валидирует текстовые поля invoice. Поэтому Minishop отправляет в `purpose` и `description` простой английский текст `Minishop payment <id>`, а локализованное описание платежа оставляет только внутри Minishop. Дополнительно эти поля проходят ASCII-safe sanitizer: допускаются ASCII-буквы, цифры, пробелы, `_`, `.`, `,`.
PayKilla строго валидирует текстовые поля invoice. Поэтому Minishop отправляет в `purpose` и `description` простой английский текст `<WEBAPP_TITLE> payment <id>`, а локализованное описание платежа оставляет только внутри Minishop. Дополнительно эти поля проходят ASCII-safe sanitizer: допускаются ASCII-буквы, цифры, пробелы, `_`, `.`, `,`.
Какие полномочия нужны API key:
@@ -182,7 +182,7 @@ PayKilla строго валидирует текстовые поля invoice.
1. Включите `PAYKILLA_ENABLED`.
2. Укажите `PAYKILLA_API_KEY` и `PAYKILLA_SECRET_KEY`.
3. Проверьте `PAYKILLA_CURRENCY` и `PAYKILLA_PAYMENT_CURRENCIES`, например `USDTTRC,BTC,ETH`.
4. При необходимости задайте `PAYKILLA_SUCCESS_URL`, `PAYKILLA_RETURN_URL` и `PAYKILLA_CANCEL_URL`; по умолчанию Minishop не отправляет redirect URLs в PayKilla и полагается на webhook для активации платежа.
4. Убедитесь, что webhook `/webhook/paykilla` настроен в PayKilla: Minishop не отправляет redirect URLs в PayKilla и полагается на webhook для активации платежа.
5. Добавьте `paykilla` в `PAYMENT_METHODS_ORDER`, если хотите задать явный порядок кнопок.
Справочник переменных: [PayKilla](../configuration/env-vars.md#paykilla).
@@ -4090,81 +4090,6 @@
"updated_at": null,
"webhook_base_url_configured": false
},
{
"key": "PAYKILLA_RETURN_URL",
"type": "url",
"section": "payments",
"section_order": 4,
"subsection": "PayKilla",
"label": "Return URL",
"description": "",
"i18n_label_key": "admin_settings_field_paykilla_return_url_label",
"i18n_description_key": null,
"i18n_subsection_key": "admin_settings_subsection_paykilla",
"i18n_placeholder_key": null,
"placeholder": "",
"optional": true,
"secret": false,
"provider_id": "paykilla",
"provider_label": "PayKilla",
"webhook_provider_id": "paykilla",
"webhook_path": "/webhook/paykilla",
"webhook_requires_base_url": false,
"value": "",
"overridden": false,
"updated_at": null,
"webhook_base_url_configured": false
},
{
"key": "PAYKILLA_SUCCESS_URL",
"type": "url",
"section": "payments",
"section_order": 4,
"subsection": "PayKilla",
"label": "Success URL",
"description": "",
"i18n_label_key": "admin_settings_field_paykilla_success_url_label",
"i18n_description_key": null,
"i18n_subsection_key": "admin_settings_subsection_paykilla",
"i18n_placeholder_key": null,
"placeholder": "",
"optional": true,
"secret": false,
"provider_id": "paykilla",
"provider_label": "PayKilla",
"webhook_provider_id": "paykilla",
"webhook_path": "/webhook/paykilla",
"webhook_requires_base_url": false,
"value": "",
"overridden": false,
"updated_at": null,
"webhook_base_url_configured": false
},
{
"key": "PAYKILLA_CANCEL_URL",
"type": "url",
"section": "payments",
"section_order": 4,
"subsection": "PayKilla",
"label": "Cancel URL",
"description": "",
"i18n_label_key": "admin_settings_field_paykilla_cancel_url_label",
"i18n_description_key": null,
"i18n_subsection_key": "admin_settings_subsection_paykilla",
"i18n_placeholder_key": null,
"placeholder": "",
"optional": true,
"secret": false,
"provider_id": "paykilla",
"provider_label": "PayKilla",
"webhook_provider_id": "paykilla",
"webhook_path": "/webhook/paykilla",
"webhook_requires_base_url": false,
"value": "",
"overridden": false,
"updated_at": null,
"webhook_base_url_configured": false
},
{
"key": "PAYKILLA_LIFETIME_SECONDS",
"type": "int",
+5 -15
View File
@@ -218,6 +218,7 @@ class PaykillaServiceTests(unittest.TestCase):
)
service.settings = SimpleNamespace(
WEBHOOK_BASE_URL="https://shop.example",
WEBAPP_TITLE="/minishop",
trusted_proxies=["127.0.0.1"],
)
service._default_return_url = "test_bot"
@@ -245,6 +246,7 @@ class PaykillaServiceTests(unittest.TestCase):
def test_invoice_body_uses_english_purpose_and_description(self):
service = self._make_service()
service.settings.WEBAPP_TITLE = "Tunnel Shop"
body = service._invoice_body(
payment_db_id=556,
@@ -253,15 +255,13 @@ class PaykillaServiceTests(unittest.TestCase):
description="Оплата подписки на 1 мес. - тариф «Базовый» ✅",
)
self.assertEqual(body["purpose"], "Minishop payment 556")
self.assertEqual(body["purpose"], "Tunnel Shop payment 556")
self.assertEqual(body["description"], body["purpose"])
self.assertRegex(body["purpose"], r"^[A-Za-z0-9_\s.,]+$")
self.assertNotIn("urls", body)
def test_invoice_body_includes_only_explicit_redirect_urls(self):
def test_invoice_body_omits_redirect_urls(self):
service = self._make_service()
service.config.SUCCESS_URL = "https://shop.example/pay/success"
service.config.RETURN_URL = "https://shop.example/pay/return"
body = service._invoice_body(
payment_db_id=556,
@@ -270,17 +270,7 @@ class PaykillaServiceTests(unittest.TestCase):
description="ignored",
)
self.assertEqual(
body["urls"],
[
{
"type": "SUCCESS",
"url": "https://shop.example/pay/success",
"autoRedirect": True,
},
{"type": "RETURN", "url": "https://shop.example/pay/return"},
],
)
self.assertNotIn("urls", body)
def test_verify_webhook_signature_accepts_raw_body_signature(self):
service = self._make_service()