added gb packets selling
This commit is contained in:
@@ -40,11 +40,15 @@ async def display_subscription_options(event: Union[types.Message, types.Callbac
|
||||
return
|
||||
|
||||
currency_symbol_val = settings.DEFAULT_CURRENCY_SYMBOL
|
||||
text_content = get_text("select_subscription_period") if settings.subscription_options else get_text("no_subscription_options_available")
|
||||
traffic_mode = bool(getattr(settings, "traffic_sale_mode", False))
|
||||
options = settings.traffic_packages if traffic_mode else settings.subscription_options
|
||||
text_content = (
|
||||
get_text("select_traffic_package") if traffic_mode else get_text("select_subscription_period")
|
||||
) if options else get_text("no_subscription_options_available")
|
||||
|
||||
reply_markup = (
|
||||
get_subscription_options_keyboard(settings.subscription_options, currency_symbol_val, current_lang, i18n)
|
||||
if settings.subscription_options
|
||||
get_subscription_options_keyboard(options, currency_symbol_val, current_lang, i18n, traffic_mode=traffic_mode)
|
||||
if options
|
||||
else get_back_to_main_menu_markup(current_lang, i18n)
|
||||
)
|
||||
|
||||
@@ -125,17 +129,50 @@ async def my_subscription_command_handler(
|
||||
|
||||
end_date = active.get("end_date")
|
||||
days_left = (end_date.date() - datetime.now().date()).days if end_date else 0
|
||||
text = get_text(
|
||||
"my_subscription_details",
|
||||
end_date=end_date.strftime("%Y-%m-%d") if end_date else "N/A",
|
||||
days_left=max(0, days_left),
|
||||
status=active.get("status_from_panel", get_text("status_active")).capitalize(),
|
||||
config_link=active.get("config_link") or get_text("config_link_not_available"),
|
||||
traffic_limit=(f"{active['traffic_limit_bytes'] / 2**30:.2f} GB" if active.get("traffic_limit_bytes") else get_text("traffic_unlimited")),
|
||||
traffic_used=(
|
||||
f"{active['traffic_used_bytes'] / 2**30:.2f} GB" if active.get("traffic_used_bytes") is not None else get_text("traffic_na")
|
||||
),
|
||||
)
|
||||
traffic_mode = bool(getattr(settings, "traffic_sale_mode", False))
|
||||
def _fmt_gb(val: Optional[float]) -> str:
|
||||
if val is None:
|
||||
return get_text("traffic_na")
|
||||
try:
|
||||
if isinstance(val, (int, float)):
|
||||
val_gb = float(val) / (2**30)
|
||||
return f"{val_gb:.2f} GB"
|
||||
except Exception:
|
||||
pass
|
||||
return str(val)
|
||||
|
||||
if traffic_mode:
|
||||
limit_display = _fmt_gb(active.get("traffic_limit_bytes"))
|
||||
used_display = _fmt_gb(active.get("traffic_used_bytes"))
|
||||
remaining_display = get_text("traffic_na")
|
||||
try:
|
||||
limit_val = active.get("traffic_limit_bytes") or 0
|
||||
used_val = active.get("traffic_used_bytes") or 0
|
||||
remaining_val = max(0, float(limit_val) - float(used_val))
|
||||
remaining_display = _fmt_gb(remaining_val)
|
||||
except Exception:
|
||||
pass
|
||||
text = get_text(
|
||||
"my_traffic_details",
|
||||
status=active.get("status_from_panel", get_text("status_active")).capitalize(),
|
||||
end_date=end_date.strftime("%Y-%m-%d") if end_date else get_text("traffic_no_expiry"),
|
||||
traffic_limit=limit_display,
|
||||
traffic_used=used_display,
|
||||
traffic_left=remaining_display,
|
||||
config_link=active.get("config_link") or get_text("config_link_not_available"),
|
||||
)
|
||||
else:
|
||||
text = get_text(
|
||||
"my_subscription_details",
|
||||
end_date=end_date.strftime("%Y-%m-%d") if end_date else "N/A",
|
||||
days_left=max(0, days_left),
|
||||
status=active.get("status_from_panel", get_text("status_active")).capitalize(),
|
||||
config_link=active.get("config_link") or get_text("config_link_not_available"),
|
||||
traffic_limit=(f"{active['traffic_limit_bytes'] / 2**30:.2f} GB" if active.get("traffic_limit_bytes") else get_text("traffic_unlimited")),
|
||||
traffic_used=(
|
||||
f"{active['traffic_used_bytes'] / 2**30:.2f} GB" if active.get("traffic_used_bytes") is not None else get_text("traffic_na")
|
||||
),
|
||||
)
|
||||
|
||||
base_markup = get_back_to_main_menu_markup(current_lang, i18n)
|
||||
kb = base_markup.inline_keyboard
|
||||
@@ -214,7 +251,7 @@ async def my_subscription_command_handler(
|
||||
])
|
||||
|
||||
# 2) Auto-renew toggle (YooKassa only)
|
||||
if local_sub and local_sub.provider == "yookassa" and settings.yookassa_autopayments_active:
|
||||
if not traffic_mode and local_sub and local_sub.provider == "yookassa" and settings.yookassa_autopayments_active:
|
||||
toggle_text = (
|
||||
get_text("autorenew_disable_button") if local_sub.auto_renew_enabled else get_text("autorenew_enable_button")
|
||||
)
|
||||
@@ -226,7 +263,7 @@ async def my_subscription_command_handler(
|
||||
])
|
||||
|
||||
# 3) Payment methods management (when autopayments enabled)
|
||||
if settings.yookassa_autopayments_active:
|
||||
if not traffic_mode and settings.yookassa_autopayments_active:
|
||||
prepend_rows.append([
|
||||
InlineKeyboardButton(text=get_text("payment_methods_manage_button"), callback_data="pm:manage")
|
||||
])
|
||||
|
||||
@@ -390,8 +390,15 @@ async def payment_method_history(callback: types.CallbackQuery, settings: Settin
|
||||
await callback.message.edit_text(_("payment_method_no_history"), reply_markup=back_markup)
|
||||
return
|
||||
|
||||
traffic_mode = getattr(settings, "traffic_sale_mode", False)
|
||||
|
||||
def _format_item(p: Payment) -> str:
|
||||
title = p.description or _("subscription_purchase_title", months=p.subscription_duration_months or 1)
|
||||
if traffic_mode:
|
||||
units_val = p.subscription_duration_months or 0
|
||||
units_display = str(int(units_val)) if float(units_val).is_integer() else f"{units_val:g}"
|
||||
title = p.description or _("traffic_purchase_title", traffic_gb=units_display)
|
||||
else:
|
||||
title = p.description or _("subscription_purchase_title", months=p.subscription_duration_months or 1)
|
||||
date_str = p.created_at.strftime('%Y-%m-%d') if p.created_at else "N/A"
|
||||
return f"{date_str} — {title} — {p.amount:.2f} {p.currency}"
|
||||
|
||||
@@ -455,4 +462,3 @@ async def payment_methods_list(callback: types.CallbackQuery, settings: Settings
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -39,9 +39,10 @@ async def pay_crypto_callback_handler(
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
months_str, price_str = data_payload.split(":")
|
||||
months = int(months_str)
|
||||
price_amount = float(price_str)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
price_amount = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
@@ -50,7 +51,12 @@ async def pay_crypto_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
|
||||
invoice_url = await cryptopay_service.create_invoice(
|
||||
session=session,
|
||||
@@ -58,17 +64,22 @@ async def pay_crypto_callback_handler(
|
||||
months=months,
|
||||
amount=price_amount,
|
||||
description=payment_description,
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
|
||||
if invoice_url:
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
invoice_url,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
@@ -76,12 +87,16 @@ async def pay_crypto_callback_handler(
|
||||
except Exception:
|
||||
try:
|
||||
await callback.message.answer(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
invoice_url,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
|
||||
@@ -47,9 +47,10 @@ async def pay_fk_callback_handler(
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
months_str, price_str = data_payload.split(":")
|
||||
months = int(months_str)
|
||||
price_rub = float(price_str)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
price_rub = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"Invalid pay_fk data in callback: {callback.data}")
|
||||
try:
|
||||
@@ -59,7 +60,12 @@ async def pay_fk_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
currency_code = getattr(freekassa_service, "default_currency", None) or settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
|
||||
payment_record_payload = {
|
||||
@@ -68,7 +74,7 @@ async def pay_fk_callback_handler(
|
||||
"currency": currency_code,
|
||||
"status": "pending_freekassa",
|
||||
"description": payment_description,
|
||||
"subscription_duration_months": months,
|
||||
"subscription_duration_months": int(months),
|
||||
"provider": "freekassa",
|
||||
}
|
||||
|
||||
@@ -135,12 +141,16 @@ async def pay_fk_callback_handler(
|
||||
)
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
f"{order_info_text}\n\n" + get_text(key="payment_link_message", months=months),
|
||||
f"{order_info_text}\n\n" + get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
location,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
@@ -149,12 +159,16 @@ async def pay_fk_callback_handler(
|
||||
logging.warning(f"FreeKassa: failed to display payment link ({e_edit}), sending new message.")
|
||||
try:
|
||||
await callback.message.answer(
|
||||
f"{order_info_text}\n\n" + get_text(key="payment_link_message", months=months),
|
||||
f"{order_info_text}\n\n" + get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
location,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
|
||||
@@ -47,9 +47,10 @@ async def pay_platega_callback_handler(
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
months_str, price_str = data_payload.split(":")
|
||||
months = int(months_str)
|
||||
price_rub = float(price_str)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
price_rub = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"Invalid pay_platega data in callback: {callback.data}")
|
||||
try:
|
||||
@@ -59,7 +60,12 @@ async def pay_platega_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
|
||||
payment_record_payload = {
|
||||
@@ -68,7 +74,7 @@ async def pay_platega_callback_handler(
|
||||
"currency": currency_code,
|
||||
"status": "pending_platega",
|
||||
"description": payment_description,
|
||||
"subscription_duration_months": months,
|
||||
"subscription_duration_months": int(months),
|
||||
"provider": "platega",
|
||||
}
|
||||
|
||||
@@ -96,6 +102,7 @@ async def pay_platega_callback_handler(
|
||||
"payment_db_id": payment_record.payment_id,
|
||||
"user_id": user_id,
|
||||
"months": months,
|
||||
"sale_mode": sale_mode,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -136,12 +143,16 @@ async def pay_platega_callback_handler(
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
redirect_url,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
@@ -150,12 +161,16 @@ async def pay_platega_callback_handler(
|
||||
logging.warning(f"Platega: failed to display payment link ({e_edit}), sending new message.")
|
||||
try:
|
||||
await callback.message.answer(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
redirect_url,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
|
||||
@@ -46,9 +46,10 @@ async def pay_severpay_callback_handler(
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
months_str, price_str = data_payload.split(":")
|
||||
months = int(months_str)
|
||||
price_rub = float(price_str)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
price_rub = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"Invalid pay_severpay data in callback: {callback.data}")
|
||||
try:
|
||||
@@ -58,7 +59,12 @@ async def pay_severpay_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB"
|
||||
|
||||
payment_record_payload = {
|
||||
@@ -67,7 +73,7 @@ async def pay_severpay_callback_handler(
|
||||
"currency": currency_code,
|
||||
"status": "pending_severpay",
|
||||
"description": payment_description,
|
||||
"subscription_duration_months": months,
|
||||
"subscription_duration_months": int(months),
|
||||
"provider": "severpay",
|
||||
}
|
||||
|
||||
@@ -126,12 +132,16 @@ async def pay_severpay_callback_handler(
|
||||
if payment_link:
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
payment_link,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
@@ -140,12 +150,16 @@ async def pay_severpay_callback_handler(
|
||||
logging.warning(f"SeverPay: failed to display payment link ({e_edit}), sending new message.")
|
||||
try:
|
||||
await callback.message.answer(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
payment_link,
|
||||
current_lang,
|
||||
i18n,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{human_value}",
|
||||
back_text_key="back_to_payment_methods_button",
|
||||
),
|
||||
disable_web_page_preview=False,
|
||||
|
||||
@@ -40,9 +40,10 @@ async def pay_stars_callback_handler(
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
months_str, stars_price_str = data_payload.split(":")
|
||||
months = int(months_str)
|
||||
stars_price = int(stars_price_str)
|
||||
parts = data_payload.split(":")
|
||||
months = float(parts[0])
|
||||
stars_price = int(float(parts[1]))
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
@@ -51,7 +52,12 @@ async def pay_stars_callback_handler(
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
human_value = str(int(months)) if float(months).is_integer() else f"{months:g}"
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=human_value)
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
|
||||
payment_db_id = await stars_service.create_invoice(
|
||||
session=session,
|
||||
@@ -59,16 +65,21 @@ async def pay_stars_callback_handler(
|
||||
months=months,
|
||||
stars_price=stars_price,
|
||||
description=payment_description,
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
|
||||
if payment_db_id:
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
get_text("payment_invoice_sent_message", months=months),
|
||||
get_text(
|
||||
"payment_invoice_sent_message_traffic" if sale_mode == "traffic" else "payment_invoice_sent_message",
|
||||
months=int(months),
|
||||
traffic_gb=human_value,
|
||||
),
|
||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(
|
||||
text=get_text("back_to_payment_methods_button"),
|
||||
callback_data=f"subscribe_period:{months}",
|
||||
callback_data=f"subscribe_period:{human_value}",
|
||||
)]
|
||||
]),
|
||||
)
|
||||
@@ -106,9 +117,10 @@ async def handle_successful_stars_payment(
|
||||
payload = (message.successful_payment.invoice_payload
|
||||
if message and message.successful_payment else "")
|
||||
try:
|
||||
payment_db_id_str, months_str = (payload or "").split(":", 1)
|
||||
payment_db_id = int(payment_db_id_str)
|
||||
months = int(months_str)
|
||||
parts = (payload or "").split(":")
|
||||
payment_db_id = int(parts[0])
|
||||
months = float(parts[1]) if len(parts) > 1 else 0
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
except Exception:
|
||||
return
|
||||
|
||||
@@ -120,4 +132,5 @@ async def handle_successful_stars_payment(
|
||||
months=months,
|
||||
stars_amount=stars_amount,
|
||||
i18n_data=i18n_data,
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
|
||||
@@ -29,8 +29,9 @@ async def select_subscription_period_callback_handler(
|
||||
pass
|
||||
return
|
||||
|
||||
traffic_mode = bool(getattr(settings, "traffic_sale_mode", False))
|
||||
try:
|
||||
months = int(callback.data.split(":")[-1])
|
||||
months = float(callback.data.split(":")[-1])
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"Invalid subscription period in callback_data: {callback.data}")
|
||||
try:
|
||||
@@ -39,10 +40,13 @@ async def select_subscription_period_callback_handler(
|
||||
pass
|
||||
return
|
||||
|
||||
price_rub = settings.subscription_options.get(months)
|
||||
price_source = settings.traffic_packages if traffic_mode else settings.subscription_options
|
||||
stars_price_source = settings.stars_traffic_packages if traffic_mode else settings.stars_subscription_options
|
||||
|
||||
price_rub = price_source.get(months)
|
||||
if price_rub is None:
|
||||
logging.error(
|
||||
f"Price not found for {months} months subscription period in settings.subscription_options."
|
||||
f"Price not found for option {months} using {'traffic_packages' if traffic_mode else 'subscription_options'}."
|
||||
)
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
@@ -51,8 +55,8 @@ async def select_subscription_period_callback_handler(
|
||||
return
|
||||
|
||||
currency_symbol_val = settings.DEFAULT_CURRENCY_SYMBOL
|
||||
text_content = get_text("choose_payment_method")
|
||||
stars_price = settings.stars_subscription_options.get(months)
|
||||
text_content = get_text("choose_payment_method_traffic") if traffic_mode else get_text("choose_payment_method")
|
||||
stars_price = stars_price_source.get(months)
|
||||
reply_markup = get_payment_method_keyboard(
|
||||
months,
|
||||
price_rub,
|
||||
@@ -61,6 +65,7 @@ async def select_subscription_period_callback_handler(
|
||||
current_lang,
|
||||
i18n,
|
||||
settings,
|
||||
sale_mode="traffic" if traffic_mode else "subscription",
|
||||
)
|
||||
|
||||
try:
|
||||
|
||||
@@ -18,10 +18,17 @@ from db.dal import payment_dal, user_billing_dal
|
||||
router = Router(name="user_subscription_payments_yookassa_router")
|
||||
|
||||
|
||||
def _parse_months_and_price(payload: str) -> Optional[Tuple[int, float]]:
|
||||
def _format_value(val: float) -> str:
|
||||
return str(int(val)) if float(val).is_integer() else f"{val:g}"
|
||||
|
||||
|
||||
def _parse_offer_payload(payload: str) -> Optional[Tuple[float, float, str]]:
|
||||
try:
|
||||
months_str, price_str = payload.split(":")
|
||||
return int(months_str), float(price_str)
|
||||
parts = payload.split(":")
|
||||
value = float(parts[0])
|
||||
price = float(parts[1])
|
||||
sale_mode = parts[2] if len(parts) > 2 else "subscription"
|
||||
return value, price, sale_mode
|
||||
except (ValueError, IndexError):
|
||||
return None
|
||||
|
||||
@@ -64,19 +71,24 @@ async def _initiate_yk_payment(
|
||||
back_callback: str,
|
||||
payment_method_id: Optional[str] = None,
|
||||
selected_method_internal_id: Optional[int] = None,
|
||||
sale_mode: str = "subscription",
|
||||
) -> bool:
|
||||
"""Create payment record and initiate YooKassa payment (new card or saved card)."""
|
||||
if not callback.message:
|
||||
return False
|
||||
|
||||
payment_description = get_text("payment_description_subscription", months=months)
|
||||
payment_description = (
|
||||
get_text("payment_description_traffic", traffic_gb=_format_value(months))
|
||||
if sale_mode == "traffic"
|
||||
else get_text("payment_description_subscription", months=int(months))
|
||||
)
|
||||
payment_record_data = {
|
||||
"user_id": user_id,
|
||||
"amount": price_rub,
|
||||
"currency": currency_code_for_yk,
|
||||
"status": "pending_yookassa",
|
||||
"description": payment_description,
|
||||
"subscription_duration_months": months,
|
||||
"subscription_duration_months": int(months),
|
||||
}
|
||||
|
||||
db_payment_record = None
|
||||
@@ -109,7 +121,10 @@ async def _initiate_yk_payment(
|
||||
"user_id": str(user_id),
|
||||
"subscription_months": str(months),
|
||||
"payment_db_id": str(db_payment_record.payment_id),
|
||||
"sale_mode": sale_mode,
|
||||
}
|
||||
if sale_mode == "traffic":
|
||||
yookassa_metadata["traffic_gb"] = str(months)
|
||||
if payment_method_id:
|
||||
yookassa_metadata["used_saved_payment_method_id"] = payment_method_id
|
||||
|
||||
@@ -198,7 +213,11 @@ async def _initiate_yk_payment(
|
||||
|
||||
try:
|
||||
await callback.message.edit_text(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=_format_value(months),
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
payment_response_yk["confirmation_url"],
|
||||
current_lang,
|
||||
@@ -214,7 +233,11 @@ async def _initiate_yk_payment(
|
||||
)
|
||||
try:
|
||||
await callback.message.answer(
|
||||
get_text(key="payment_link_message", months=months),
|
||||
get_text(
|
||||
key="payment_link_message_traffic" if sale_mode == "traffic" else "payment_link_message",
|
||||
months=int(months),
|
||||
traffic_gb=_format_value(months),
|
||||
),
|
||||
reply_markup=get_payment_url_keyboard(
|
||||
payment_response_yk["confirmation_url"],
|
||||
current_lang,
|
||||
@@ -328,7 +351,7 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti
|
||||
pass
|
||||
return
|
||||
|
||||
parsed = _parse_months_and_price(data_payload)
|
||||
parsed = _parse_offer_payload(data_payload)
|
||||
if not parsed:
|
||||
logging.error(f"Invalid pay_yk payload structure: {callback.data}")
|
||||
try:
|
||||
@@ -337,10 +360,10 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti
|
||||
pass
|
||||
return
|
||||
|
||||
months, price_rub = parsed
|
||||
months, price_rub, sale_mode = parsed
|
||||
user_id = callback.from_user.id
|
||||
currency_code_for_yk = "RUB"
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active)
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active and sale_mode != "traffic" and not settings.traffic_sale_mode)
|
||||
autopay_require_binding = bool(
|
||||
getattr(settings, 'YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING', True)
|
||||
)
|
||||
@@ -364,6 +387,7 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti
|
||||
current_lang,
|
||||
i18n,
|
||||
has_saved_cards=True,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception as e_edit:
|
||||
@@ -377,6 +401,7 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti
|
||||
current_lang,
|
||||
i18n,
|
||||
has_saved_cards=True,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception:
|
||||
@@ -400,7 +425,8 @@ async def pay_yk_callback_handler(callback: types.CallbackQuery, settings: Setti
|
||||
price_rub=price_rub,
|
||||
currency_code_for_yk=currency_code_for_yk,
|
||||
save_payment_method=autopay_enabled and autopay_require_binding,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{_format_value(months)}",
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
try:
|
||||
await callback.answer()
|
||||
@@ -443,7 +469,7 @@ async def pay_yk_new_card_handler(callback: types.CallbackQuery, settings: Setti
|
||||
pass
|
||||
return
|
||||
|
||||
parsed = _parse_months_and_price(data_payload)
|
||||
parsed = _parse_offer_payload(data_payload)
|
||||
if not parsed:
|
||||
logging.error(f"Invalid pay_yk_new payload structure: {callback.data}")
|
||||
try:
|
||||
@@ -452,10 +478,10 @@ async def pay_yk_new_card_handler(callback: types.CallbackQuery, settings: Setti
|
||||
pass
|
||||
return
|
||||
|
||||
months, price_rub = parsed
|
||||
months, price_rub, sale_mode = parsed
|
||||
user_id = callback.from_user.id
|
||||
currency_code_for_yk = "RUB"
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active)
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active and sale_mode != "traffic" and not settings.traffic_sale_mode)
|
||||
autopay_require_binding = bool(
|
||||
getattr(settings, 'YOOKASSA_AUTOPAYMENTS_REQUIRE_CARD_BINDING', True)
|
||||
)
|
||||
@@ -473,7 +499,8 @@ async def pay_yk_new_card_handler(callback: types.CallbackQuery, settings: Setti
|
||||
price_rub=price_rub,
|
||||
currency_code_for_yk=currency_code_for_yk,
|
||||
save_payment_method=autopay_enabled and autopay_require_binding,
|
||||
back_callback=f"subscribe_period:{months}",
|
||||
back_callback=f"subscribe_period:{_format_value(months)}",
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
try:
|
||||
await callback.answer()
|
||||
@@ -494,14 +521,6 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
pass
|
||||
return
|
||||
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active)
|
||||
if not autopay_enabled:
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
try:
|
||||
_, data_payload = callback.data.split(":", 1)
|
||||
except ValueError:
|
||||
@@ -522,9 +541,10 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
return
|
||||
|
||||
try:
|
||||
months = int(parts[0])
|
||||
months = float(parts[0])
|
||||
price_rub = float(parts[1])
|
||||
page = int(parts[2]) if len(parts) > 2 else 0
|
||||
sale_mode = parts[3] if len(parts) > 3 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"pay_yk_saved_list payload parsing error: {callback.data}")
|
||||
try:
|
||||
@@ -533,6 +553,14 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
pass
|
||||
return
|
||||
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active and sale_mode != "traffic" and not settings.traffic_sale_mode)
|
||||
if not autopay_enabled:
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
user_id = callback.from_user.id
|
||||
try:
|
||||
saved_methods = await user_billing_dal.list_user_payment_methods(
|
||||
@@ -552,6 +580,7 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
current_lang,
|
||||
i18n,
|
||||
has_saved_cards=False,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception as e_edit:
|
||||
@@ -565,6 +594,7 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
current_lang,
|
||||
i18n,
|
||||
has_saved_cards=False,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception:
|
||||
@@ -596,6 +626,7 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
current_lang,
|
||||
i18n,
|
||||
page=page,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception as e_edit:
|
||||
@@ -610,6 +641,7 @@ async def pay_yk_saved_list_handler(callback: types.CallbackQuery, settings: Set
|
||||
current_lang,
|
||||
i18n,
|
||||
page=page,
|
||||
sale_mode=sale_mode,
|
||||
),
|
||||
)
|
||||
except Exception:
|
||||
@@ -633,14 +665,6 @@ async def pay_yk_use_saved_handler(callback: types.CallbackQuery, settings: Sett
|
||||
pass
|
||||
return
|
||||
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active)
|
||||
if not autopay_enabled:
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
if not yookassa_service or not yookassa_service.configured:
|
||||
logging.error("YooKassa service unavailable for pay_yk_use_saved.")
|
||||
try:
|
||||
@@ -673,8 +697,9 @@ async def pay_yk_use_saved_handler(callback: types.CallbackQuery, settings: Sett
|
||||
return
|
||||
|
||||
try:
|
||||
months = int(parts[0])
|
||||
months = float(parts[0])
|
||||
price_rub = float(parts[1])
|
||||
sale_mode = parts[3] if len(parts) > 3 else "subscription"
|
||||
except (ValueError, IndexError):
|
||||
logging.error(f"pay_yk_use_saved months/price parsing error: {callback.data}")
|
||||
try:
|
||||
@@ -683,6 +708,14 @@ async def pay_yk_use_saved_handler(callback: types.CallbackQuery, settings: Sett
|
||||
pass
|
||||
return
|
||||
|
||||
autopay_enabled = bool(settings.yookassa_autopayments_active and sale_mode != "traffic" and not settings.traffic_sale_mode)
|
||||
if not autopay_enabled:
|
||||
try:
|
||||
await callback.answer(get_text("error_try_again"), show_alert=True)
|
||||
except Exception:
|
||||
pass
|
||||
return
|
||||
|
||||
method_identifier = parts[2]
|
||||
user_id = callback.from_user.id
|
||||
|
||||
@@ -727,9 +760,10 @@ async def pay_yk_use_saved_handler(callback: types.CallbackQuery, settings: Sett
|
||||
price_rub=price_rub,
|
||||
currency_code_for_yk=currency_code_for_yk,
|
||||
save_payment_method=False,
|
||||
back_callback=f"pay_yk_saved_list:{months}:{price_rub}",
|
||||
back_callback=f"pay_yk_saved_list:{_format_value(months)}:{price_rub}:{sale_mode}",
|
||||
payment_method_id=selected_method.provider_payment_method_id,
|
||||
selected_method_internal_id=selected_method.method_id,
|
||||
sale_mode=sale_mode,
|
||||
)
|
||||
try:
|
||||
await callback.answer()
|
||||
|
||||
Reference in New Issue
Block a user