feat: update payment method defaults to use PaymentMethod enum; refactor related validation checks

This commit is contained in:
bohd4nx
2026-05-29 22:31:30 +03:00
parent 5124af17ef
commit 6aa7037380
13 changed files with 49 additions and 38 deletions
+4 -4
View File
@@ -136,7 +136,7 @@ class FragmentClient:
username: str,
months: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumResult:
"""Gift Telegram Premium to a user.
@@ -156,7 +156,7 @@ class FragmentClient:
username: str,
amount: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsResult:
"""Send Telegram Stars to a user.
@@ -212,7 +212,7 @@ class FragmentClient:
channel: str,
winners: int,
amount: int,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsGiveawayResult:
"""Run a Telegram Stars giveaway for a channel.
@@ -233,7 +233,7 @@ class FragmentClient:
channel: str,
winners: int,
months: int = 3,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumGiveawayResult:
"""Run a Telegram Premium giveaway for a channel.
+1 -1
View File
@@ -19,7 +19,7 @@ def get_cookies_from_browser(browser: str = "chrome") -> CookieResult:
global rookiepy
key = browser.lower()
if key not in SupportedBrowser._value2member_map_:
if not any(key == m for m in SupportedBrowser):
supported = ", ".join(sorted(b.value for b in SupportedBrowser))
raise CookieError(CookieError.UNSUPPORTED_BROWSER.format(browser=browser, supported=supported))
+2 -2
View File
@@ -4,7 +4,7 @@ import json
import logging
from typing import TYPE_CHECKING
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO
from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction
from pyfragment.exceptions import ConfigurationError, FragmentAPIError, FragmentError, UnexpectedError, VerificationError
@@ -34,7 +34,7 @@ async def recharge_ads(client: FragmentClient, account: str, amount: int) -> Ads
"getAdsRechargeLink",
{
"account": json.dumps(account_info),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
},
+2 -2
View File
@@ -4,7 +4,7 @@ import json
import logging
from typing import TYPE_CHECKING
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE
from pyfragment.core.constants import ADS_TOPUP_PAGE, DEVICE_INFO
from pyfragment.domains.payments import parse_required_payment_amount
from pyfragment.domains.tonapi.account import get_account_info
from pyfragment.domains.tonapi.transaction import process_transaction
@@ -48,7 +48,7 @@ async def topup_ton(client: FragmentClient, username: str, amount: int, show_sen
"getAdsTopupLink",
{
"account": json.dumps(account),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
"show_sender": int(show_sender),
+8 -8
View File
@@ -6,7 +6,7 @@ import random
from typing import TYPE_CHECKING
from pyfragment.core.constants import (
DEVICE,
DEVICE_INFO,
PREMIUM_GIVEAWAY_PAGE,
PREMIUM_MONTHS_VALID,
PREMIUM_WINNERS_MAX,
@@ -43,13 +43,13 @@ async def giveaway_stars(
channel: str,
winners: int,
amount: int,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsGiveawayResult:
if not isinstance(winners, int) or not (STARS_WINNERS_MIN <= winners <= STARS_WINNERS_MAX):
raise ConfigurationError(ConfigurationError.INVALID_WINNERS_STARS)
if not isinstance(amount, int) or not (STARS_GIVEAWAY_MIN <= amount <= STARS_GIVEAWAY_MAX):
raise ConfigurationError(ConfigurationError.INVALID_STARS_PER_WINNER)
if payment_method not in PaymentMethod._value2member_map_:
if not any(payment_method == m for m in PaymentMethod):
raise ConfigurationError(
ConfigurationError.INVALID_PAYMENT_METHOD.format(
method=payment_method,
@@ -89,7 +89,7 @@ async def giveaway_stars(
"getGiveawayStarsLink",
{
"account": json.dumps(account),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
},
@@ -133,17 +133,17 @@ async def giveaway_premium(
channel: str,
winners: int,
months: int = 3,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumGiveawayResult:
if not isinstance(winners, int) or not (PREMIUM_WINNERS_MIN <= winners <= PREMIUM_WINNERS_MAX):
raise ConfigurationError(ConfigurationError.INVALID_WINNERS_PREMIUM)
if months not in PREMIUM_MONTHS_VALID:
raise ConfigurationError(ConfigurationError.INVALID_MONTHS)
if payment_method not in PaymentMethod._value2member_map_:
if not any(payment_method == m for m in PaymentMethod):
raise ConfigurationError(
ConfigurationError.INVALID_PAYMENT_METHOD.format(
method=payment_method,
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
supported=", ".join(sorted(m.value for m in PaymentMethod)),
)
)
@@ -188,7 +188,7 @@ async def giveaway_premium(
"getGiveawayPremiumLink",
{
"account": json.dumps(account),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
},
+2 -2
View File
@@ -17,7 +17,7 @@ class GiveawaysService(BaseService):
channel: str,
winners: int,
amount: int,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsGiveawayResult:
return await giveaway_stars(self._client, channel, winners, amount, payment_method=payment_method)
@@ -26,6 +26,6 @@ class GiveawaysService(BaseService):
channel: str,
winners: int,
months: int = 3,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumGiveawayResult:
return await giveaway_premium(self._client, channel, winners, months, payment_method=payment_method)
+9 -9
View File
@@ -6,7 +6,7 @@ import time
from typing import TYPE_CHECKING
from pyfragment.core.constants import (
DEVICE,
DEVICE_INFO,
PREMIUM_MONTHS_VALID,
PREMIUM_PAGE,
STARS_PAGE,
@@ -39,15 +39,15 @@ async def purchase_stars(
username: str,
amount: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsResult:
if not isinstance(amount, int) or not (STARS_PURCHASE_MIN <= amount <= STARS_PURCHASE_MAX):
raise ConfigurationError(ConfigurationError.INVALID_STARS_AMOUNT)
if payment_method not in PaymentMethod._value2member_map_:
if not any(payment_method == m for m in PaymentMethod):
raise ConfigurationError(
ConfigurationError.INVALID_PAYMENT_METHOD.format(
method=payment_method,
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
supported=", ".join(sorted(m.value for m in PaymentMethod)),
)
)
@@ -77,7 +77,7 @@ async def purchase_stars(
"getBuyStarsLink",
{
"account": json.dumps(account),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
"show_sender": int(show_sender),
@@ -120,15 +120,15 @@ async def purchase_premium(
username: str,
months: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumResult:
if months not in PREMIUM_MONTHS_VALID:
raise ConfigurationError(ConfigurationError.INVALID_MONTHS)
if payment_method not in PaymentMethod._value2member_map_:
if not any(payment_method == m for m in PaymentMethod):
raise ConfigurationError(
ConfigurationError.INVALID_PAYMENT_METHOD.format(
method=payment_method,
supported=", ".join(sorted(PaymentMethod._value2member_map_)),
supported=", ".join(sorted(m.value for m in PaymentMethod)),
)
)
@@ -158,7 +158,7 @@ async def purchase_premium(
"getGiftPremiumLink",
{
"account": json.dumps(account),
"device": DEVICE,
"device": json.dumps(DEVICE_INFO),
"transaction": 1,
"id": req_id,
"show_sender": int(show_sender),
+2 -2
View File
@@ -17,7 +17,7 @@ class PurchasesService(BaseService):
username: str,
amount: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> StarsResult:
return await purchase_stars(self._client, username, amount, show_sender=show_sender, payment_method=payment_method)
@@ -26,6 +26,6 @@ class PurchasesService(BaseService):
username: str,
months: int,
show_sender: bool = True,
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
) -> PremiumResult:
return await purchase_premium(self._client, username, months, show_sender=show_sender, payment_method=payment_method)
+1 -1
View File
@@ -124,7 +124,7 @@ async def _broadcast_with_retry(wallet: Any, message: dict[str, Any], payload: s
async def process_transaction(
client: FragmentClient,
transaction_data: dict[str, Any],
payment_method: PaymentMethod = "ton",
payment_method: PaymentMethod = PaymentMethod.TON,
required_payment_amount: float | None = None,
) -> str:
"""Sign and broadcast a Fragment transaction with the seeded TON wallet.
+9 -1
View File
@@ -1,10 +1,18 @@
from __future__ import annotations
from enum import StrEnum
import sys
from enum import Enum
from typing import Any
from tonutils.contracts.wallet import WalletV4R2, WalletV5R1
if sys.version_info >= (3, 11):
from enum import StrEnum
else:
class StrEnum(str, Enum): # noqa: F811
pass
class PaymentMethod(StrEnum):
TON = "ton"
+3 -2
View File
@@ -9,6 +9,7 @@ from tonutils.exceptions import ProviderResponseError
from pyfragment import TransactionError, WalletError
from pyfragment.domains.tonapi.transaction import process_transaction
from pyfragment.models.enums import PaymentMethod
from tests.shared import VALID_SEED
@@ -145,7 +146,7 @@ async def test_usdt_payment_requires_min_ton_gas_reserve() -> None:
wallet = _make_wallet(balance_nanotons=10_000_000) # 0.01 TON below MIN_TON_BALANCE
with _patch_wallet(wallet), patch("pyfragment.domains.tonapi.account.get_usdt_balance", AsyncMock(return_value=100.0)):
with pytest.raises(WalletError, match="Insufficient TON balance"):
await process_transaction(_make_client(), TRANSACTION_DATA, payment_method="usdt_ton")
await process_transaction(_make_client(), TRANSACTION_DATA, payment_method=PaymentMethod.USDT_TON)
@pytest.mark.asyncio
@@ -173,6 +174,6 @@ async def test_usdt_payment_checks_usdt_balance() -> None:
await process_transaction(
_make_client(),
transaction,
payment_method="usdt_ton",
payment_method=PaymentMethod.USDT_TON,
required_payment_amount=12.5,
)
+3 -2
View File
@@ -7,6 +7,7 @@ import pytest
import pyfragment.domains.giveaways.giveaway as _giveaway_stars_mod
import pyfragment.domains.purchases.purchase as _purchase_stars_mod
from pyfragment import ConfigurationError, FragmentClient, StarsGiveawayResult, StarsResult, UserNotFoundError
from pyfragment.models.enums import PaymentMethod
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
# Stars purchase validation tests
@@ -78,7 +79,7 @@ async def test_purchase_stars_passes_payment_method(client: FragmentClient) -> N
patch.object(_purchase_stars_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
patch.object(_purchase_stars_mod, "process_transaction", proc_mock),
):
await client.purchase_stars("@user", amount=500, payment_method="usdt_ton")
await client.purchase_stars("@user", amount=500, payment_method=PaymentMethod.USDT_TON)
init_call = call_mock.await_args_list[2]
assert init_call.args[0] == "initBuyStarsRequest"
@@ -198,7 +199,7 @@ async def test_giveaway_stars_passes_payment_method(client: FragmentClient) -> N
patch.object(_giveaway_stars_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
patch.object(_giveaway_stars_mod, "process_transaction", proc_mock),
):
await client.giveaway_stars("@channel", winners=3, amount=1000, payment_method="usdt_ton")
await client.giveaway_stars("@channel", winners=3, amount=1000, payment_method=PaymentMethod.USDT_TON)
init_call = call_mock.await_args_list[2]
assert init_call.args[0] == "initGiveawayStarsRequest"
+3 -2
View File
@@ -7,6 +7,7 @@ import pytest
import pyfragment.domains.giveaways.giveaway as _giveaway_premium_mod
import pyfragment.domains.purchases.purchase as _purchase_premium_mod
from pyfragment import ConfigurationError, FragmentClient, PremiumGiveawayResult, PremiumResult, UserNotFoundError
from pyfragment.models.enums import PaymentMethod
from tests.shared import FAKE_ACCOUNT, FAKE_RECIPIENT, FAKE_REQ_ID, FAKE_TRANSACTION, FAKE_TX_HASH
# Premium purchase validation tests
@@ -75,7 +76,7 @@ async def test_purchase_premium_passes_payment_method(client: FragmentClient) ->
patch.object(_purchase_premium_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
patch.object(_purchase_premium_mod, "process_transaction", proc_mock),
):
await client.purchase_premium("@user", months=6, payment_method="usdt_ton")
await client.purchase_premium("@user", months=6, payment_method=PaymentMethod.USDT_TON)
init_call = call_mock.await_args_list[2]
assert init_call.args[0] == "initGiftPremiumRequest"
@@ -183,7 +184,7 @@ async def test_giveaway_premium_passes_payment_method(client: FragmentClient) ->
patch.object(_giveaway_premium_mod, "get_account_info", AsyncMock(return_value=FAKE_ACCOUNT)),
patch.object(_giveaway_premium_mod, "process_transaction", proc_mock),
):
await client.giveaway_premium("@channel", winners=10, months=6, payment_method="usdt_ton")
await client.giveaway_premium("@channel", winners=10, months=6, payment_method=PaymentMethod.USDT_TON)
init_call = call_mock.await_args_list[2]
assert init_call.args[0] == "initGiveawayPremiumRequest"