fix: bind HWID top-ups to subscription periods
This commit is contained in:
@@ -113,6 +113,11 @@ class WebAppPaymentContext:
|
||||
description: str
|
||||
sale_mode: str
|
||||
traffic_gb: Optional[float] = None
|
||||
hwid_valid_from: Optional[Any] = None
|
||||
hwid_valid_until: Optional[Any] = None
|
||||
hwid_pricing_period_months: Optional[int] = None
|
||||
hwid_proration_ratio: Optional[float] = None
|
||||
hwid_full_price: Optional[float] = None
|
||||
|
||||
|
||||
EnabledPredicate = Callable[[Any], bool]
|
||||
|
||||
@@ -38,9 +38,12 @@ from .shared import (
|
||||
parse_payment_callback,
|
||||
payment_failed,
|
||||
payment_link_response,
|
||||
payment_record_amounts,
|
||||
payment_unavailable,
|
||||
quote_hwid_callback_parts,
|
||||
render_payment_link,
|
||||
sale_mode_base,
|
||||
sale_mode_is_traffic,
|
||||
sale_mode_tariff_key,
|
||||
)
|
||||
|
||||
@@ -155,13 +158,14 @@ class CryptoPayService:
|
||||
description: str,
|
||||
sale_mode: str = "subscription",
|
||||
url_kind: str = "bot",
|
||||
hwid_quote: Optional[dict] = None,
|
||||
) -> Optional[str]:
|
||||
if not self.configured or not self.client:
|
||||
logging.error("CryptoPayService not configured")
|
||||
return None
|
||||
|
||||
sale_base = sale_mode_base(sale_mode)
|
||||
is_traffic = sale_base in {"traffic", "traffic_package", "topup", "premium_topup"}
|
||||
amounts = payment_record_amounts(months=months, sale_mode=sale_mode)
|
||||
try:
|
||||
payment_record = await payment_dal.create_payment_record(
|
||||
session,
|
||||
@@ -177,7 +181,17 @@ class CryptoPayService:
|
||||
"provider": "cryptopay",
|
||||
"sale_mode": sale_mode,
|
||||
"tariff_key": sale_mode_tariff_key(sale_mode),
|
||||
"purchased_gb": float(months) if is_traffic else None,
|
||||
"purchased_gb": amounts.purchased_gb,
|
||||
"purchased_hwid_devices": amounts.purchased_hwid_devices,
|
||||
"hwid_valid_from": hwid_quote.get("valid_from") if hwid_quote else None,
|
||||
"hwid_valid_until": hwid_quote.get("valid_until") if hwid_quote else None,
|
||||
"hwid_pricing_period_months": hwid_quote.get("pricing_period_months")
|
||||
if hwid_quote
|
||||
else None,
|
||||
"hwid_proration_ratio": hwid_quote.get("proration_ratio")
|
||||
if hwid_quote
|
||||
else None,
|
||||
"hwid_full_price": hwid_quote.get("full_price") if hwid_quote else None,
|
||||
},
|
||||
)
|
||||
await session.commit()
|
||||
@@ -192,7 +206,7 @@ class CryptoPayService:
|
||||
"subscription_months": str(months),
|
||||
"payment_db_id": str(payment_record.payment_id),
|
||||
"sale_mode": sale_mode,
|
||||
"traffic_gb": str(months) if is_traffic else None,
|
||||
"traffic_gb": str(months) if sale_mode_is_traffic(sale_mode) else None,
|
||||
}
|
||||
)
|
||||
try:
|
||||
@@ -363,6 +377,16 @@ async def pay_crypto_callback_handler(
|
||||
return
|
||||
|
||||
parts = parse_payment_callback(callback.data or "")
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=cryptopay_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
@@ -375,6 +399,7 @@ async def pay_crypto_callback_handler(
|
||||
amount=parts.price,
|
||||
description=payment_description,
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
if invoice_url:
|
||||
@@ -424,6 +449,15 @@ async def create_webapp_payment(ctx: WebAppPaymentContext) -> web.Response:
|
||||
description=ctx.description,
|
||||
sale_mode=ctx.sale_mode,
|
||||
url_kind="web",
|
||||
hwid_quote={
|
||||
"valid_from": ctx.hwid_valid_from,
|
||||
"valid_until": ctx.hwid_valid_until,
|
||||
"pricing_period_months": ctx.hwid_pricing_period_months,
|
||||
"proration_ratio": ctx.hwid_proration_ratio,
|
||||
"full_price": ctx.hwid_full_price,
|
||||
}
|
||||
if ctx.hwid_valid_from and ctx.hwid_valid_until
|
||||
else None,
|
||||
)
|
||||
if not url:
|
||||
return payment_failed()
|
||||
|
||||
@@ -50,6 +50,7 @@ from .shared import (
|
||||
payment_failed,
|
||||
payment_unavailable,
|
||||
post_json_request,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
)
|
||||
|
||||
@@ -470,6 +471,16 @@ async def pay_fk_callback_handler(
|
||||
logging.error("Invalid pay_fk data in callback: %s", callback.data)
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=freekassa_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
|
||||
currency_code = (
|
||||
getattr(freekassa_service, "default_currency", None)
|
||||
@@ -486,6 +497,7 @@ async def pay_fk_callback_handler(
|
||||
months=parts.months,
|
||||
provider="freekassa",
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -49,6 +49,7 @@ from .shared import (
|
||||
parse_payment_callback,
|
||||
payment_failed,
|
||||
payment_unavailable,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
)
|
||||
|
||||
@@ -565,6 +566,16 @@ async def pay_heleket_callback_handler(
|
||||
logging.error("Invalid pay_heleket data in callback: %s", callback.data)
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=heleket_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
|
||||
currency_code = (heleket_service.currency or settings.DEFAULT_CURRENCY_SYMBOL or "RUB").upper()
|
||||
payment_description = describe_payment(translator, parts)
|
||||
@@ -577,6 +588,7 @@ async def pay_heleket_callback_handler(
|
||||
months=parts.months,
|
||||
provider="heleket",
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -46,6 +46,7 @@ from .shared import (
|
||||
payment_record_amounts,
|
||||
payment_unavailable,
|
||||
post_json_request,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
safe_callback_answer,
|
||||
)
|
||||
@@ -475,6 +476,16 @@ async def pay_platega_callback_handler(
|
||||
logging.error("Invalid pay_platega data in callback: %s", callback.data)
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=platega_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
|
||||
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
payment_description = describe_payment(translator, parts)
|
||||
@@ -487,6 +498,7 @@ async def pay_platega_callback_handler(
|
||||
months=parts.months,
|
||||
provider="platega",
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -47,6 +47,7 @@ from .shared import (
|
||||
payment_failed,
|
||||
payment_unavailable,
|
||||
post_json_request,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
)
|
||||
|
||||
@@ -414,6 +415,16 @@ async def pay_severpay_callback_handler(
|
||||
logging.error("Invalid pay_severpay data in callback: %s", callback.data)
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=severpay_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
|
||||
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
payment_description = describe_payment(translator, parts)
|
||||
@@ -426,6 +437,7 @@ async def pay_severpay_callback_handler(
|
||||
months=parts.months,
|
||||
provider="severpay",
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -15,6 +15,7 @@ from .callbacks import (
|
||||
notify_service_unavailable,
|
||||
parse_payment_callback,
|
||||
payment_link_message_text,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
render_payment_link,
|
||||
safe_callback_answer,
|
||||
@@ -55,6 +56,7 @@ from .success import (
|
||||
PaymentSuccessOutcome,
|
||||
PaymentSuccessRequest,
|
||||
SuccessMessage,
|
||||
append_hwid_renewal_note,
|
||||
build_success_message,
|
||||
finalize_successful_payment,
|
||||
is_traffic_sale_base,
|
||||
@@ -82,6 +84,7 @@ __all__ = [
|
||||
"build_payment_description",
|
||||
"build_payment_record_payload",
|
||||
"build_success_message",
|
||||
"append_hwid_renewal_note",
|
||||
"coerce_payment_db_id",
|
||||
"create_base_payment_record",
|
||||
"create_webapp_payment_record",
|
||||
@@ -113,6 +116,7 @@ __all__ = [
|
||||
"payment_record_amounts",
|
||||
"payment_unavailable",
|
||||
"post_json_request",
|
||||
"quote_hwid_callback_parts",
|
||||
"render_link_or_fail",
|
||||
"render_payment_link",
|
||||
"resolve_inviter_name",
|
||||
|
||||
@@ -21,6 +21,8 @@ from .common import (
|
||||
format_human_units,
|
||||
mark_payment_failed_creation,
|
||||
sale_mode_base,
|
||||
sale_mode_is_hwid_devices,
|
||||
sale_mode_tariff_key,
|
||||
)
|
||||
|
||||
|
||||
@@ -112,6 +114,34 @@ def describe_payment(translator: Translator, parts: PaymentCallbackParts) -> str
|
||||
)
|
||||
|
||||
|
||||
async def quote_hwid_callback_parts(
|
||||
*,
|
||||
session: AsyncSession,
|
||||
user_id: int,
|
||||
parts: PaymentCallbackParts,
|
||||
subscription_service,
|
||||
currency: str = "rub",
|
||||
) -> tuple[Optional[PaymentCallbackParts], Optional[dict]]:
|
||||
if not sale_mode_is_hwid_devices(parts.sale_mode):
|
||||
return parts, None
|
||||
quote = await subscription_service.quote_hwid_device_topup(
|
||||
session,
|
||||
user_id=user_id,
|
||||
device_count=int(parts.months),
|
||||
tariff_key=sale_mode_tariff_key(parts.sale_mode),
|
||||
renewal=sale_mode_base(parts.sale_mode) == "hwid_devices_renewal",
|
||||
currency=currency,
|
||||
)
|
||||
if not quote:
|
||||
return None, None
|
||||
quoted_parts = PaymentCallbackParts(
|
||||
months=parts.months,
|
||||
price=float(quote.get("price") or 0),
|
||||
sale_mode=parts.sale_mode,
|
||||
)
|
||||
return quoted_parts, quote
|
||||
|
||||
|
||||
def payment_link_message_text(
|
||||
translator: Translator,
|
||||
parts: PaymentCallbackParts,
|
||||
|
||||
@@ -60,7 +60,7 @@ def build_payment_description(
|
||||
"payment_description_traffic",
|
||||
traffic_gb=human_value if human_value is not None else format_human_units(months),
|
||||
)
|
||||
if base in {"hwid_device", "hwid_devices"}:
|
||||
if base in {"hwid_device", "hwid_devices", "hwid_devices_renewal"}:
|
||||
return translator("payment_description_hwid_devices", count=int(float(months)))
|
||||
return translator("payment_description_subscription", months=int(float(months)))
|
||||
|
||||
@@ -75,6 +75,7 @@ def build_payment_record_payload(
|
||||
months: Any,
|
||||
provider: str,
|
||||
sale_mode: str,
|
||||
hwid_quote: Optional[dict] = None,
|
||||
) -> dict:
|
||||
"""Assemble the payment-record dict that every callback handler used to inline.
|
||||
|
||||
@@ -85,7 +86,7 @@ def build_payment_record_payload(
|
||||
base = sale_mode_base(sale_mode)
|
||||
is_traffic = sale_mode_is_traffic(sale_mode)
|
||||
is_hwid = sale_mode_is_hwid_devices(sale_mode)
|
||||
return {
|
||||
payload = {
|
||||
"user_id": user_id,
|
||||
"amount": amount,
|
||||
"currency": currency,
|
||||
@@ -98,6 +99,17 @@ def build_payment_record_payload(
|
||||
"purchased_gb": float(months) if is_traffic else None,
|
||||
"purchased_hwid_devices": int(float(months)) if is_hwid else None,
|
||||
}
|
||||
if hwid_quote and is_hwid:
|
||||
payload.update(
|
||||
{
|
||||
"hwid_valid_from": hwid_quote.get("valid_from"),
|
||||
"hwid_valid_until": hwid_quote.get("valid_until"),
|
||||
"hwid_pricing_period_months": hwid_quote.get("pricing_period_months"),
|
||||
"hwid_proration_ratio": hwid_quote.get("proration_ratio"),
|
||||
"hwid_full_price": hwid_quote.get("full_price"),
|
||||
}
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -119,7 +131,7 @@ def sale_mode_is_traffic(sale_mode: str) -> bool:
|
||||
|
||||
|
||||
def sale_mode_is_hwid_devices(sale_mode: str) -> bool:
|
||||
return sale_mode_base(sale_mode) in {"hwid_device", "hwid_devices"}
|
||||
return sale_mode_base(sale_mode) in {"hwid_device", "hwid_devices", "hwid_devices_renewal"}
|
||||
|
||||
|
||||
def sale_mode_tariff_key(sale_mode: str) -> Optional[str]:
|
||||
@@ -194,6 +206,11 @@ async def create_base_payment_record(
|
||||
tariff_key: Optional[str] = None,
|
||||
purchased_gb: Optional[float] = None,
|
||||
purchased_hwid_devices: Optional[int] = None,
|
||||
hwid_valid_from: Optional[Any] = None,
|
||||
hwid_valid_until: Optional[Any] = None,
|
||||
hwid_pricing_period_months: Optional[int] = None,
|
||||
hwid_proration_ratio: Optional[float] = None,
|
||||
hwid_full_price: Optional[float] = None,
|
||||
) -> Payment:
|
||||
payment = await payment_dal.create_payment_record(
|
||||
session,
|
||||
@@ -209,6 +226,11 @@ async def create_base_payment_record(
|
||||
"tariff_key": tariff_key,
|
||||
"purchased_gb": purchased_gb,
|
||||
"purchased_hwid_devices": purchased_hwid_devices,
|
||||
"hwid_valid_from": hwid_valid_from,
|
||||
"hwid_valid_until": hwid_valid_until,
|
||||
"hwid_pricing_period_months": hwid_pricing_period_months,
|
||||
"hwid_proration_ratio": hwid_proration_ratio,
|
||||
"hwid_full_price": hwid_full_price,
|
||||
},
|
||||
)
|
||||
await session.commit()
|
||||
@@ -241,6 +263,11 @@ async def create_webapp_payment_record(
|
||||
tariff_key=amounts.tariff_key,
|
||||
purchased_gb=amounts.purchased_gb,
|
||||
purchased_hwid_devices=amounts.purchased_hwid_devices,
|
||||
hwid_valid_from=ctx.hwid_valid_from,
|
||||
hwid_valid_until=ctx.hwid_valid_until,
|
||||
hwid_pricing_period_months=ctx.hwid_pricing_period_months,
|
||||
hwid_proration_ratio=ctx.hwid_proration_ratio,
|
||||
hwid_full_price=ctx.hwid_full_price,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ from db.models import Payment, User
|
||||
from .common import Translator, format_human_units, make_translator, sale_mode_base
|
||||
|
||||
_TRAFFIC_MODES = {"traffic", "traffic_package", "topup", "premium_topup"}
|
||||
_HWID_DEVICE_MODES = {"hwid_device", "hwid_devices"}
|
||||
_HWID_DEVICE_MODES = {"hwid_device", "hwid_devices", "hwid_devices_renewal"}
|
||||
|
||||
|
||||
def is_traffic_sale_base(sale_base: str) -> bool:
|
||||
@@ -128,6 +128,28 @@ def build_success_message(payload: SuccessMessage) -> str:
|
||||
)
|
||||
|
||||
|
||||
def append_hwid_renewal_note(
|
||||
text: str,
|
||||
translator: Translator,
|
||||
*,
|
||||
count: Any,
|
||||
valid_until: Optional[datetime],
|
||||
) -> str:
|
||||
try:
|
||||
count_int = int(count or 0)
|
||||
except (TypeError, ValueError):
|
||||
count_int = 0
|
||||
if count_int <= 0:
|
||||
return text
|
||||
date_text = valid_until.strftime("%Y-%m-%d") if valid_until else ""
|
||||
note = translator(
|
||||
"payment_successful_hwid_devices_renewal_note",
|
||||
count=format_human_units(count_int),
|
||||
date=date_text,
|
||||
)
|
||||
return f"{text}\n\n{note}"
|
||||
|
||||
|
||||
async def send_success_message_to_user(
|
||||
*,
|
||||
bot: Bot,
|
||||
@@ -333,6 +355,13 @@ async def finalize_successful_payment(
|
||||
inviter_name=inviter_name,
|
||||
)
|
||||
)
|
||||
if is_subscription and activation:
|
||||
success_text = append_hwid_renewal_note(
|
||||
success_text,
|
||||
translator,
|
||||
count=activation.get("hwid_devices_renewal_recommended_count"),
|
||||
valid_until=activation.get("hwid_devices_valid_until"),
|
||||
)
|
||||
if req.text_prefix:
|
||||
success_text = f"{req.text_prefix}\n{success_text}"
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ from .shared import (
|
||||
payment_failed,
|
||||
payment_record_amounts,
|
||||
payment_unavailable,
|
||||
quote_hwid_callback_parts,
|
||||
safe_callback_answer,
|
||||
sale_mode_base,
|
||||
sale_mode_tariff_key,
|
||||
@@ -80,9 +81,10 @@ class StarsService:
|
||||
stars_price: int,
|
||||
description: str,
|
||||
sale_mode: str = "subscription",
|
||||
hwid_quote: Optional[dict] = None,
|
||||
) -> Optional[int]:
|
||||
amounts = payment_record_amounts(months=months, sale_mode=sale_mode)
|
||||
sale_base = sale_mode_base(sale_mode)
|
||||
is_traffic = sale_base in {"traffic", "traffic_package", "topup", "premium_topup"}
|
||||
payment_record_data = {
|
||||
"user_id": user_id,
|
||||
"amount": float(stars_price),
|
||||
@@ -93,7 +95,15 @@ class StarsService:
|
||||
"provider": "telegram_stars",
|
||||
"sale_mode": sale_mode,
|
||||
"tariff_key": sale_mode_tariff_key(sale_mode),
|
||||
"purchased_gb": float(months) if is_traffic else None,
|
||||
"purchased_gb": amounts.purchased_gb,
|
||||
"purchased_hwid_devices": amounts.purchased_hwid_devices,
|
||||
"hwid_valid_from": hwid_quote.get("valid_from") if hwid_quote else None,
|
||||
"hwid_valid_until": hwid_quote.get("valid_until") if hwid_quote else None,
|
||||
"hwid_pricing_period_months": hwid_quote.get("pricing_period_months")
|
||||
if hwid_quote
|
||||
else None,
|
||||
"hwid_proration_ratio": hwid_quote.get("proration_ratio") if hwid_quote else None,
|
||||
"hwid_full_price": hwid_quote.get("full_price") if hwid_quote else None,
|
||||
}
|
||||
try:
|
||||
db_payment_record = await payment_dal.create_payment_record(
|
||||
@@ -206,6 +216,16 @@ async def pay_stars_callback_handler(
|
||||
return
|
||||
|
||||
parts = parse_payment_callback(callback.data or "")
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=stars_service.subscription_service,
|
||||
currency="stars",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
@@ -221,6 +241,7 @@ async def pay_stars_callback_handler(
|
||||
stars_price=stars_price,
|
||||
description=payment_description,
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
if payment_db_id:
|
||||
|
||||
@@ -53,6 +53,7 @@ from .shared import (
|
||||
payment_record_amounts,
|
||||
payment_unavailable,
|
||||
post_json_request,
|
||||
quote_hwid_callback_parts,
|
||||
render_link_or_fail,
|
||||
render_payment_link,
|
||||
safe_callback_answer,
|
||||
@@ -856,6 +857,16 @@ async def pay_wata_callback_handler(
|
||||
logging.error("Invalid pay_wata data in callback: %s", callback.data)
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=parts,
|
||||
subscription_service=wata_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not parts:
|
||||
await notify_callback_parse_error(callback, translator)
|
||||
return
|
||||
|
||||
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
payment_description = describe_payment(translator, parts)
|
||||
@@ -901,6 +912,7 @@ async def pay_wata_callback_handler(
|
||||
months=parts.months,
|
||||
provider="wata",
|
||||
sale_mode=parts.sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -52,7 +52,9 @@ from .base import (
|
||||
provider_runtime_enabled,
|
||||
)
|
||||
from .shared import (
|
||||
PaymentCallbackParts,
|
||||
SuccessMessage,
|
||||
append_hwid_renewal_note,
|
||||
build_success_message,
|
||||
create_webapp_payment_record,
|
||||
format_human_units,
|
||||
@@ -65,6 +67,7 @@ from .shared import (
|
||||
payment_link_response,
|
||||
payment_record_amounts,
|
||||
payment_unavailable,
|
||||
quote_hwid_callback_parts,
|
||||
resolve_inviter_name,
|
||||
send_success_message_to_user,
|
||||
)
|
||||
@@ -419,7 +422,7 @@ YOOKASSA_WEBHOOK_ALLOWED_IPS = [
|
||||
"77.75.154.128/25",
|
||||
"2a02:5180::/32",
|
||||
]
|
||||
HWID_DEVICE_SALE_BASES = {"hwid_device", "hwid_devices"}
|
||||
HWID_DEVICE_SALE_BASES = {"hwid_device", "hwid_devices", "hwid_devices_renewal"}
|
||||
|
||||
|
||||
def _is_hwid_device_sale_base(sale_mode_base: str) -> bool:
|
||||
@@ -832,6 +835,14 @@ async def process_successful_payment(
|
||||
)
|
||||
include_keyboard = True
|
||||
|
||||
if sale_mode_base == "subscription" and activation_details:
|
||||
details_message = append_hwid_renewal_note(
|
||||
details_message,
|
||||
translator,
|
||||
count=activation_details.get("hwid_devices_renewal_recommended_count"),
|
||||
valid_until=activation_details.get("hwid_devices_valid_until"),
|
||||
)
|
||||
|
||||
install_share_url = None
|
||||
if include_keyboard:
|
||||
install_links = await ensure_user_install_guide_links(session, settings, user_id)
|
||||
@@ -1288,6 +1299,7 @@ async def _initiate_yk_payment(
|
||||
payment_method_id: Optional[str] = None,
|
||||
selected_method_internal_id: Optional[int] = None,
|
||||
sale_mode: str = "subscription",
|
||||
hwid_quote: Optional[dict] = None,
|
||||
) -> bool:
|
||||
"""Create payment record and initiate YooKassa payment (new card or saved card)."""
|
||||
if not callback.message:
|
||||
@@ -1299,7 +1311,7 @@ async def _initiate_yk_payment(
|
||||
if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"}
|
||||
else (
|
||||
get_text("payment_description_hwid_devices", count=int(months))
|
||||
if sale_base in {"hwid_device", "hwid_devices"}
|
||||
if sale_base in HWID_DEVICE_SALE_BASES
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
)
|
||||
@@ -1316,8 +1328,15 @@ async def _initiate_yk_payment(
|
||||
if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"}
|
||||
else None,
|
||||
"purchased_hwid_devices": int(months)
|
||||
if sale_base in {"hwid_device", "hwid_devices"}
|
||||
if sale_base in HWID_DEVICE_SALE_BASES
|
||||
else None,
|
||||
"hwid_valid_from": hwid_quote.get("valid_from") if hwid_quote else None,
|
||||
"hwid_valid_until": hwid_quote.get("valid_until") if hwid_quote else None,
|
||||
"hwid_pricing_period_months": hwid_quote.get("pricing_period_months")
|
||||
if hwid_quote
|
||||
else None,
|
||||
"hwid_proration_ratio": hwid_quote.get("proration_ratio") if hwid_quote else None,
|
||||
"hwid_full_price": hwid_quote.get("full_price") if hwid_quote else None,
|
||||
}
|
||||
|
||||
db_payment_record = None
|
||||
@@ -1634,6 +1653,23 @@ async def pay_yk_callback_handler(
|
||||
return
|
||||
|
||||
months, price_rub, sale_mode = parsed
|
||||
hwid_quote = None
|
||||
if _sale_mode_base(sale_mode) in HWID_DEVICE_SALE_BASES:
|
||||
quoted_parts, hwid_quote = await quote_hwid_callback_parts(
|
||||
session=session,
|
||||
user_id=callback.from_user.id,
|
||||
parts=PaymentCallbackParts(months=months, price=price_rub, sale_mode=sale_mode),
|
||||
subscription_service=yookassa_service.subscription_service,
|
||||
currency="rub",
|
||||
)
|
||||
if not quoted_parts:
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
months = quoted_parts.months
|
||||
price_rub = quoted_parts.price
|
||||
user_id = callback.from_user.id
|
||||
currency_code_for_yk = "RUB"
|
||||
autopay_enabled = bool(
|
||||
@@ -1710,6 +1746,7 @@ async def pay_yk_callback_handler(
|
||||
save_payment_method=autopay_enabled and autopay_require_binding,
|
||||
back_callback=payment_methods_back_callback(_format_value(months), sale_mode, price_rub),
|
||||
sale_mode=sale_mode,
|
||||
hwid_quote=hwid_quote,
|
||||
)
|
||||
try:
|
||||
await callback.answer()
|
||||
|
||||
Reference in New Issue
Block a user