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": "📊 Статус очередей сообщений",