diff --git a/bot/handlers/admin/promo/bulk.py b/bot/handlers/admin/promo/bulk.py
index 8a2f7c7..181ee17 100644
--- a/bot/handlers/admin/promo/bulk.py
+++ b/bot/handlers/admin/promo/bulk.py
@@ -1,6 +1,8 @@
import logging
import random
import string
+import csv
+import io
from aiogram import Router, F, types
from aiogram.filters import StateFilter
from aiogram.fsm.context import FSMContext
@@ -421,15 +423,52 @@ async def create_bulk_promo_codes_final(callback_or_message,
)
)
+ # Create CSV file with promo codes if any were created
+ csv_file = None
if created_codes:
- success_lines.append("\n🎟 Созданные коды:")
- # Show first 20 codes, then indicate if there are more
- codes_to_show = created_codes[:20]
- for code in codes_to_show:
- success_lines.append(f"{code}")
+ success_lines.append(f"\n🎟 Создано {len(created_codes)} промокодов")
+ success_lines.append("📄 CSV файл с промокодами отправлен отдельным сообщением")
- if len(created_codes) > 20:
- success_lines.append(f"... и еще {len(created_codes) - 20} кодов")
+ # Create CSV file
+ output = io.StringIO()
+ writer = csv.writer(output)
+
+ # CSV headers
+ writer.writerow([
+ "Промокод", "Бонусные дни", "Макс. активации", "Действителен до",
+ "Команда для старта", "Ссылка для активации"
+ ])
+
+ # Add bot username from settings
+ bot_username = getattr(settings, 'BOT_USERNAME', 'your_bot')
+
+ for code in created_codes:
+ # Determine validity info
+ if data.get("validity_days"):
+ valid_until = (datetime.now(timezone.utc) + timedelta(days=data["validity_days"])).strftime("%Y-%m-%d %H:%M:%S")
+ else:
+ valid_until = "Без ограничений"
+
+ start_command = f"/start promo_{code}"
+ telegram_link = f"https://t.me/{bot_username}?start=promo_{code}"
+
+ writer.writerow([
+ code,
+ data["bonus_days"],
+ data["max_activations"],
+ valid_until,
+ start_command,
+ telegram_link
+ ])
+
+ output.seek(0)
+
+ # Create file for sending
+ filename = f"bulk_promo_codes_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
+ csv_file = types.BufferedInputFile(
+ output.getvalue().encode('utf-8-sig'), # BOM for correct Excel display
+ filename=filename
+ )
if failed_codes:
success_lines.append(f"\n❌ Ошибки ({len(failed_codes)}):")
@@ -447,19 +486,26 @@ async def create_bulk_promo_codes_final(callback_or_message,
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
parse_mode="HTML"
)
+ message_obj = callback_or_message.message
except Exception:
- await callback_or_message.message.answer(
+ message_obj = await callback_or_message.message.answer(
success_text,
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
parse_mode="HTML"
)
+ await callback_or_message.answer()
else: # Message
- await callback_or_message.answer(
+ message_obj = await callback_or_message.answer(
success_text,
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n),
parse_mode="HTML"
)
+ # Send CSV file if created
+ if csv_file:
+ csv_caption = f"📄 Промокоды для массового создания\n💫 Всего: {len(created_codes)} промокодов\n🎁 Бонус: {data['bonus_days']} дней каждый"
+ await message_obj.answer_document(csv_file, caption=csv_caption)
+
await state.clear()
except Exception as e:
diff --git a/bot/handlers/user/start.py b/bot/handlers/user/start.py
index 994d6c4..9bf10f9 100644
--- a/bot/handlers/user/start.py
+++ b/bot/handlers/user/start.py
@@ -224,7 +224,7 @@ async def start_command_handler(message: types.Message,
if promo_code_to_apply:
try:
from bot.services.promo_code_service import PromoCodeService
- promo_code_service = PromoCodeService()
+ promo_code_service = PromoCodeService(settings, subscription_service, bot, i18n)
success, result = await promo_code_service.apply_promo_code(
session, user_id, promo_code_to_apply, current_lang
diff --git a/bot/services/promo_code_service.py b/bot/services/promo_code_service.py
index 6aaaca8..77ec565 100644
--- a/bot/services/promo_code_service.py
+++ b/bot/services/promo_code_service.py
@@ -55,7 +55,6 @@ class PromoCodeService:
reason=f"promo code {code_input_upper}")
if new_end_date:
-
activation_recorded = await promo_code_dal.record_promo_activation(
session, promo_data.promo_code_id, user_id, payment_id=None)
promo_incremented = await promo_code_dal.increment_promo_code_usage(
@@ -83,5 +82,4 @@ class PromoCodeService:
)
return False, _("error_applying_promo_bonus")
else:
-
return False, _("error_applying_promo_bonus")
diff --git a/locales/ru.json b/locales/ru.json
index 7f3cd30..fd7177d 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -154,8 +154,8 @@
"admin_back_to_panel": "⬅️ В панель",
"admin_promo_unlimited": "♾️ Неограниченно",
"admin_bulk_promo_created_title": "📦 Массовое создание завершено",
- "admin_bulk_promo_created_stats": "✅ Создано промокодов: {created_count}\n📅 Бонусные дни: {bonus_days}\n🔢 Максимальные активации: {max_activations}\n⏰ Действительны: {validity_info}",
- "admin_bulk_promo_settings": "📝 Настройки промокодов",
+ "admin_bulk_promo_created_stats": "📊 Создано: {created} из {total}",
+ "admin_bulk_promo_settings": "🎁 Бонусные дни: {bonus_days}\n📊 Макс. активаций: {max_activations}\n⏰ Срок действия: {validity}",
"admin_promo_list_page_info": "Страница {current}/{total} ({count} промокодов)",
"admin_queue_status_button": "📊 Статус очередей",
"admin_queue_status_title": "📊 Статус очередей сообщений",