add_refferal_stats

This commit is contained in:
Vladless
2025-03-23 19:44:11 +03:00
parent d3e502ce43
commit 388fbb5afc
8 changed files with 119 additions and 87 deletions
+26
View File
@@ -12,6 +12,7 @@ from aiogram.fsm.state import State, StatesGroup
from aiogram.types import CallbackQuery, Message
from aiogram.utils.keyboard import InlineKeyboardBuilder
from config import TOTAL_GB
from utils.csv_export import export_referrals_csv
from database import (
delete_key,
@@ -760,3 +761,28 @@ async def restore_trials(callback_query: types.CallbackQuery, session: Any):
text="✅ Пробники успешно восстановлены для пользователей, у которых нет активных подписок.",
reply_markup=builder.as_markup()
)
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_export_referrals"), IsAdminFilter())
async def handle_users_export_referrals(
callback_query: types.CallbackQuery,
callback_data: AdminUserEditorCallback,
session: Any
):
"""
Обработчик: получает tg_id реферера из callback_data,
вызывает export_referrals_csv и отправляет файл или отвечает,
что рефералов нет.
"""
referrer_tg_id = callback_data.tg_id
csv_file = await export_referrals_csv(referrer_tg_id, session)
if csv_file is None:
await callback_query.message.answer("У пользователя нет рефералов.")
return
await callback_query.message.answer_document(
document=csv_file,
caption=f"Список рефералов для пользователя {referrer_tg_id}."
)
-2
View File
@@ -55,8 +55,6 @@ async def handle_pay(callback_query: CallbackQuery):
callback_data="pay_robokassa",
)
)
builder.row(InlineKeyboardButton(text="🎟️ Активировать купон", callback_data="activate_coupon"))
if DONATIONS_ENABLE:
builder.row(InlineKeyboardButton(text="💰 Поддержать проект", callback_data="donate"))
builder.row(InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile"))
+45 -84
View File
@@ -2771,7 +2771,6 @@ static const char __pyx_k_request[] = "request";
static const char __pyx_k_session[] = "session";
static const char __pyx_k_user_id[] = "user_id";
static const char __pyx_k_warning[] = "warning";
static const char __pyx_k_web_app[] = "web_app";
static const char __pyx_k_Response[] = "Response";
static const char __pyx_k_amount_2[] = ", amount: ";
static const char __pyx_k_currency[] = "currency";
@@ -2800,7 +2799,6 @@ static const char __pyx_k_CUSTOM_SUM[] = "CUSTOM_SUM";
static const char __pyx_k_FSMContext[] = "FSMContext";
static const char __pyx_k_Secret_Key[] = "Secret Key: ";
static const char __pyx_k_ValueError[] = "ValueError";
static const char __pyx_k_WebAppInfo[] = "WebAppInfo";
static const char __pyx_k_account_id[] = "account_id";
static const char __pyx_k_amount_str[] = "amount_str";
static const char __pyx_k_payment_id[] = "payment_id";
@@ -3001,7 +2999,6 @@ typedef struct {
PyObject *__pyx_n_s_State;
PyObject *__pyx_n_s_StatesGroup;
PyObject *__pyx_n_s_ValueError;
PyObject *__pyx_n_s_WebAppInfo;
PyObject *__pyx_kp_u_Webhook_event_received;
PyObject *__pyx_n_s_YOOKASSA_ENABLE;
PyObject *__pyx_n_s_YOOKASSA_HASH;
@@ -3212,7 +3209,6 @@ typedef struct {
PyObject *__pyx_n_u_waiting_for_renewal_payment;
PyObject *__pyx_n_s_warning;
PyObject *__pyx_n_s_web;
PyObject *__pyx_n_s_web_app;
PyObject *__pyx_n_u_yookassa;
PyObject *__pyx_n_s_yookassa_2;
PyObject *__pyx_n_u_yookassa_2;
@@ -3340,7 +3336,6 @@ static int __pyx_m_clear(PyObject *m) {
Py_CLEAR(clear_module_state->__pyx_n_s_State);
Py_CLEAR(clear_module_state->__pyx_n_s_StatesGroup);
Py_CLEAR(clear_module_state->__pyx_n_s_ValueError);
Py_CLEAR(clear_module_state->__pyx_n_s_WebAppInfo);
Py_CLEAR(clear_module_state->__pyx_kp_u_Webhook_event_received);
Py_CLEAR(clear_module_state->__pyx_n_s_YOOKASSA_ENABLE);
Py_CLEAR(clear_module_state->__pyx_n_s_YOOKASSA_HASH);
@@ -3551,7 +3546,6 @@ static int __pyx_m_clear(PyObject *m) {
Py_CLEAR(clear_module_state->__pyx_n_u_waiting_for_renewal_payment);
Py_CLEAR(clear_module_state->__pyx_n_s_warning);
Py_CLEAR(clear_module_state->__pyx_n_s_web);
Py_CLEAR(clear_module_state->__pyx_n_s_web_app);
Py_CLEAR(clear_module_state->__pyx_n_u_yookassa);
Py_CLEAR(clear_module_state->__pyx_n_s_yookassa_2);
Py_CLEAR(clear_module_state->__pyx_n_u_yookassa_2);
@@ -3657,7 +3651,6 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(traverse_module_state->__pyx_n_s_State);
Py_VISIT(traverse_module_state->__pyx_n_s_StatesGroup);
Py_VISIT(traverse_module_state->__pyx_n_s_ValueError);
Py_VISIT(traverse_module_state->__pyx_n_s_WebAppInfo);
Py_VISIT(traverse_module_state->__pyx_kp_u_Webhook_event_received);
Py_VISIT(traverse_module_state->__pyx_n_s_YOOKASSA_ENABLE);
Py_VISIT(traverse_module_state->__pyx_n_s_YOOKASSA_HASH);
@@ -3868,7 +3861,6 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(traverse_module_state->__pyx_n_u_waiting_for_renewal_payment);
Py_VISIT(traverse_module_state->__pyx_n_s_warning);
Py_VISIT(traverse_module_state->__pyx_n_s_web);
Py_VISIT(traverse_module_state->__pyx_n_s_web_app);
Py_VISIT(traverse_module_state->__pyx_n_u_yookassa);
Py_VISIT(traverse_module_state->__pyx_n_s_yookassa_2);
Py_VISIT(traverse_module_state->__pyx_n_u_yookassa_2);
@@ -3984,7 +3976,6 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
#define __pyx_n_s_State __pyx_mstate_global->__pyx_n_s_State
#define __pyx_n_s_StatesGroup __pyx_mstate_global->__pyx_n_s_StatesGroup
#define __pyx_n_s_ValueError __pyx_mstate_global->__pyx_n_s_ValueError
#define __pyx_n_s_WebAppInfo __pyx_mstate_global->__pyx_n_s_WebAppInfo
#define __pyx_kp_u_Webhook_event_received __pyx_mstate_global->__pyx_kp_u_Webhook_event_received
#define __pyx_n_s_YOOKASSA_ENABLE __pyx_mstate_global->__pyx_n_s_YOOKASSA_ENABLE
#define __pyx_n_s_YOOKASSA_HASH __pyx_mstate_global->__pyx_n_s_YOOKASSA_HASH
@@ -4195,7 +4186,6 @@ static int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) {
#define __pyx_n_u_waiting_for_renewal_payment __pyx_mstate_global->__pyx_n_u_waiting_for_renewal_payment
#define __pyx_n_s_warning __pyx_mstate_global->__pyx_n_s_warning
#define __pyx_n_s_web __pyx_mstate_global->__pyx_n_s_web
#define __pyx_n_s_web_app __pyx_mstate_global->__pyx_n_s_web_app
#define __pyx_n_u_yookassa __pyx_mstate_global->__pyx_n_u_yookassa
#define __pyx_n_s_yookassa_2 __pyx_mstate_global->__pyx_n_s_yookassa_2
#define __pyx_n_u_yookassa_2 __pyx_mstate_global->__pyx_n_u_yookassa_2
@@ -5840,38 +5830,28 @@ static PyObject *__pyx_gb_8handlers_8payments_12yookassa_pay_5generator1(__pyx_C
if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_text, __pyx_t_9) < 0) __PYX_ERR(0, 174, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_n_s_WebAppInfo); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 175, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_9);
__pyx_t_16 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 175, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_16);
if (PyDict_SetItem(__pyx_t_16, __pyx_n_s_url, __pyx_cur_scope->__pyx_v_payment_url) < 0) __PYX_ERR(0, 175, __pyx_L1_error)
__pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_empty_tuple, __pyx_t_16); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 175, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_web_app, __pyx_t_13) < 0) __PYX_ERR(0, 174, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_url, __pyx_cur_scope->__pyx_v_payment_url) < 0) __PYX_ERR(0, 174, __pyx_L1_error)
__pyx_t_13 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_empty_tuple, __pyx_t_2); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 173, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_10, __pyx_empty_tuple, __pyx_t_2); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 173, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_9);
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 172, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_GIVEREF(__pyx_t_13);
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_t_13)) __PYX_ERR(0, 172, __pyx_L1_error);
__pyx_t_13 = 0;
__Pyx_GIVEREF(__pyx_t_9);
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_t_9)) __PYX_ERR(0, 172, __pyx_L1_error);
__pyx_t_9 = 0;
__Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_n_s_InlineKeyboardButton); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 179, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_13);
__Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_n_s_InlineKeyboardButton); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 179, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_9);
__pyx_t_10 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 179, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_10);
if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_text, __pyx_n_u__8) < 0) __PYX_ERR(0, 179, __pyx_L1_error)
if (PyDict_SetItem(__pyx_t_10, __pyx_n_s_callback_data, __pyx_n_u_pay) < 0) __PYX_ERR(0, 179, __pyx_L1_error)
__pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_13, __pyx_empty_tuple, __pyx_t_10); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 179, __pyx_L1_error)
__pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_9, __pyx_empty_tuple, __pyx_t_10); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 179, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0;
__Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
__Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
__pyx_t_10 = PyList_New(1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 178, __pyx_L1_error)
@@ -9019,29 +8999,19 @@ static PyObject *__pyx_gb_8handlers_8payments_12yookassa_pay_17generator5(__pyx_
__Pyx_GOTREF(__pyx_t_4);
if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_text, __pyx_t_4) < 0) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_WebAppInfo); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 347, __pyx_L21_error)
if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_url, __pyx_cur_scope->__pyx_v_payment_url) < 0) __PYX_ERR(0, 347, __pyx_L21_error)
__pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_empty_tuple, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_12 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_12);
if (PyDict_SetItem(__pyx_t_12, __pyx_n_s_url, __pyx_cur_scope->__pyx_v_payment_url) < 0) __PYX_ERR(0, 347, __pyx_L21_error)
__pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_empty_tuple, __pyx_t_12); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
if (PyDict_SetItem(__pyx_t_3, __pyx_n_s_web_app, __pyx_t_16) < 0) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__pyx_t_16 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_empty_tuple, __pyx_t_3); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 347, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_GIVEREF(__pyx_t_16);
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_t_16)) __PYX_ERR(0, 347, __pyx_L21_error);
__pyx_t_16 = 0;
__Pyx_GIVEREF(__pyx_t_4);
if (__Pyx_PyList_SET_ITEM(__pyx_t_3, 0, __pyx_t_4)) __PYX_ERR(0, 347, __pyx_L21_error);
__pyx_t_4 = 0;
__Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_n_s_InlineKeyboardButton); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_16);
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_InlineKeyboardButton); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_n_s_PROFILE); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 348, __pyx_L21_error)
@@ -9049,9 +9019,9 @@ static PyObject *__pyx_gb_8handlers_8payments_12yookassa_pay_17generator5(__pyx_
if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_text, __pyx_t_12) < 0) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_callback_data, __pyx_n_u_profile) < 0) __PYX_ERR(0, 348, __pyx_L21_error)
__pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_16, __pyx_empty_tuple, __pyx_t_2); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 348, __pyx_L21_error)
__pyx_t_12 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_empty_tuple, __pyx_t_2); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_12);
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = PyList_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 348, __pyx_L21_error)
__Pyx_GOTREF(__pyx_t_2);
@@ -9227,62 +9197,62 @@ static PyObject *__pyx_gb_8handlers_8payments_12yookassa_pay_17generator5(__pyx_
__Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_logger); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_error); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_16);
__pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_error); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_4);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_cur_scope->__pyx_v_e, __pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_3);
__pyx_t_4 = __Pyx_PyUnicode_Concat(__pyx_kp_u__23, __pyx_t_3); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_16 = __Pyx_PyUnicode_Concat(__pyx_kp_u__23, __pyx_t_3); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_16);
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = NULL;
__pyx_t_5 = 0;
#if CYTHON_UNPACK_METHODS
if (unlikely(PyMethod_Check(__pyx_t_16))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_16);
if (unlikely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_3)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_16);
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
__Pyx_INCREF(__pyx_t_3);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_16, function);
__Pyx_DECREF_SET(__pyx_t_4, function);
__pyx_t_5 = 1;
}
}
#endif
{
PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_4};
__pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_16, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5);
PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_16};
__pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_5, 1+__pyx_t_5);
__Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 360, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_12);
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
__Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_n_s_send_message); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 361, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_16);
__pyx_t_4 = NULL;
__Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_send_message); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 361, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_4);
__pyx_t_16 = NULL;
__pyx_t_5 = 0;
#if CYTHON_UNPACK_METHODS
if (unlikely(PyMethod_Check(__pyx_t_16))) {
__pyx_t_4 = PyMethod_GET_SELF(__pyx_t_16);
if (likely(__pyx_t_4)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_16);
__Pyx_INCREF(__pyx_t_4);
if (unlikely(PyMethod_Check(__pyx_t_4))) {
__pyx_t_16 = PyMethod_GET_SELF(__pyx_t_4);
if (likely(__pyx_t_16)) {
PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
__Pyx_INCREF(__pyx_t_16);
__Pyx_INCREF(function);
__Pyx_DECREF_SET(__pyx_t_16, function);
__Pyx_DECREF_SET(__pyx_t_4, function);
__pyx_t_5 = 1;
}
}
#endif
{
PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_cur_scope->__pyx_v_callback_query, __pyx_kp_u__24};
__pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_16, __pyx_callargs+1-__pyx_t_5, 2+__pyx_t_5);
__Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
PyObject *__pyx_callargs[3] = {__pyx_t_16, __pyx_cur_scope->__pyx_v_callback_query, __pyx_kp_u__24};
__pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+1-__pyx_t_5, 2+__pyx_t_5);
__Pyx_XDECREF(__pyx_t_16); __pyx_t_16 = 0;
if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 361, __pyx_L35_error)
__Pyx_GOTREF(__pyx_t_12);
__Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
__Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
}
__pyx_r = __Pyx_Coroutine_Yield_From(__pyx_generator, __pyx_t_12);
__Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0;
@@ -11450,7 +11420,6 @@ static int __Pyx_CreateStringTabAndInitStrings(void) {
{&__pyx_n_s_State, __pyx_k_State, sizeof(__pyx_k_State), 0, 0, 1, 1},
{&__pyx_n_s_StatesGroup, __pyx_k_StatesGroup, sizeof(__pyx_k_StatesGroup), 0, 0, 1, 1},
{&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1},
{&__pyx_n_s_WebAppInfo, __pyx_k_WebAppInfo, sizeof(__pyx_k_WebAppInfo), 0, 0, 1, 1},
{&__pyx_kp_u_Webhook_event_received, __pyx_k_Webhook_event_received, sizeof(__pyx_k_Webhook_event_received), 0, 1, 0, 0},
{&__pyx_n_s_YOOKASSA_ENABLE, __pyx_k_YOOKASSA_ENABLE, sizeof(__pyx_k_YOOKASSA_ENABLE), 0, 0, 1, 1},
{&__pyx_n_s_YOOKASSA_HASH, __pyx_k_YOOKASSA_HASH, sizeof(__pyx_k_YOOKASSA_HASH), 0, 0, 1, 1},
@@ -11661,7 +11630,6 @@ static int __Pyx_CreateStringTabAndInitStrings(void) {
{&__pyx_n_u_waiting_for_renewal_payment, __pyx_k_waiting_for_renewal_payment, sizeof(__pyx_k_waiting_for_renewal_payment), 0, 1, 0, 1},
{&__pyx_n_s_warning, __pyx_k_warning, sizeof(__pyx_k_warning), 0, 0, 1, 1},
{&__pyx_n_s_web, __pyx_k_web, sizeof(__pyx_k_web), 0, 0, 1, 1},
{&__pyx_n_s_web_app, __pyx_k_web_app, sizeof(__pyx_k_web_app), 0, 0, 1, 1},
{&__pyx_n_u_yookassa, __pyx_k_yookassa, sizeof(__pyx_k_yookassa), 0, 1, 0, 1},
{&__pyx_n_s_yookassa_2, __pyx_k_yookassa_2, sizeof(__pyx_k_yookassa_2), 0, 0, 1, 1},
{&__pyx_n_u_yookassa_2, __pyx_k_yookassa_2, sizeof(__pyx_k_yookassa_2), 0, 1, 0, 1},
@@ -12336,7 +12304,7 @@ if (!__Pyx_RefNanny) {
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = PyList_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)
__pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_INCREF(__pyx_n_s_InlineKeyboardButton);
__Pyx_GIVEREF(__pyx_n_s_InlineKeyboardButton);
@@ -12344,9 +12312,6 @@ if (!__Pyx_RefNanny) {
__Pyx_INCREF(__pyx_n_s_InlineKeyboardMarkup);
__Pyx_GIVEREF(__pyx_n_s_InlineKeyboardMarkup);
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_n_s_InlineKeyboardMarkup)) __PYX_ERR(0, 8, __pyx_L1_error);
__Pyx_INCREF(__pyx_n_s_WebAppInfo);
__Pyx_GIVEREF(__pyx_n_s_WebAppInfo);
if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_n_s_WebAppInfo)) __PYX_ERR(0, 8, __pyx_L1_error);
__pyx_t_3 = __Pyx_Import(__pyx_n_s_aiogram_types, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
@@ -12358,10 +12323,6 @@ if (!__Pyx_RefNanny) {
__Pyx_GOTREF(__pyx_t_2);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_InlineKeyboardMarkup, __pyx_t_2) < 0) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_n_s_WebAppInfo); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
if (PyDict_SetItem(__pyx_d, __pyx_n_s_WebAppInfo, __pyx_t_2) < 0) __PYX_ERR(0, 8, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error)
+1
View File
@@ -127,6 +127,7 @@ async def balance_handler(callback_query: CallbackQuery, session: Any):
builder = InlineKeyboardBuilder()
builder.row(InlineKeyboardButton(text=PAYMENT, callback_data="pay"))
builder.row(InlineKeyboardButton(text=BALANCE_HISTORY, callback_data="balance_history"))
builder.row(InlineKeyboardButton(text="🎟️ Активировать купон", callback_data="activate_coupon"))
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
text = f"<b>Управление вашим балансом 💰</b>\n\nВаш баланс: {balance}"
+4
View File
@@ -43,6 +43,10 @@ def build_user_edit_kb(tg_id: int, key_records: list) -> InlineKeyboardMarkup:
text="💸 Изменить баланс",
callback_data=AdminUserEditorCallback(action="users_balance_edit", tg_id=tg_id).pack(),
)
builder.button(
text="🤝 Выгрузить рефералов",
callback_data=AdminUserEditorCallback(action="users_export_referrals", tg_id=tg_id).pack(),
)
builder.button(
text="♻️ Восстановить триал",
callback_data=AdminUserEditorCallback(action="users_trial_restore", tg_id=tg_id).pack(),
+1 -1
View File
File diff suppressed because one or more lines are too long
+42
View File
@@ -1,5 +1,6 @@
from io import StringIO
from typing import Any
import csv
from aiogram.types import BufferedInputFile
@@ -95,3 +96,44 @@ def _export_payments_csv(payments: list, filename: str) -> BufferedInputFile:
buffer.seek(0)
return BufferedInputFile(file=buffer.getvalue().encode("utf-8-sig"), filename=filename)
async def export_referrals_csv(referrer_tg_id: int, session: Any) -> BufferedInputFile | None:
"""
Формирует CSV-файл со списком рефералов и возвращает его как BufferedInputFile.
Если у пользователя нет рефералов, возвращает None.
"""
rows = await session.fetch(
"""
SELECT
r.referred_tg_id,
COALESCE(u.first_name, '') AS first_name,
COALESCE(u.last_name, '') AS last_name,
COALESCE(u.username, '') AS username
FROM referrals r
JOIN users u ON u.tg_id = r.referred_tg_id
WHERE r.referrer_tg_id = $1
ORDER BY r.referred_tg_id
""",
referrer_tg_id
)
if not rows:
return None
output = StringIO()
writer = csv.writer(output, delimiter=';')
writer.writerow(["Приглашённый (tg_id)", "Имя"])
for row in rows:
invited_id = row["referred_tg_id"]
full_name = row["first_name"].strip() or row["username"] or str(invited_id)
if row["last_name"]:
full_name = f"{full_name} {row['last_name']}"
writer.writerow([invited_id, full_name.strip()])
output.seek(0)
csv_data = output.getvalue().encode("utf-8")
filename = f"referrals_{referrer_tg_id}.csv"
return BufferedInputFile(file=csv_data, filename=filename)