Enhance bulk promo code creation with CSV export functionality

- Added the ability to generate and send a CSV file containing created promo codes, improving data accessibility for admins.
- Updated success messages to inform users about the CSV file and the number of created promo codes.
- Refactored the promo code creation logic to include detailed validity information and links for activation in the CSV output.
- Improved localization for bulk promo creation messages to enhance user experience.
This commit is contained in:
machka-pasla
2025-08-06 17:58:44 +03:00
parent a126c05365
commit 859263dc2d
4 changed files with 58 additions and 14 deletions
+55 -9
View File
@@ -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🎟 <b>Созданные коды:</b>")
# 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>{code}</code>")
success_lines.append(f"\n🎟 <b>Создано {len(created_codes)} промокодов</b>")
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❌ <b>Ошибки ({len(failed_codes)}):</b>")
@@ -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:
+1 -1
View File
@@ -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
-2
View File
@@ -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")
+2 -2
View File
@@ -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": "📊 Создано: <b>{created}</b> из <b>{total}</b>",
"admin_bulk_promo_settings": "🎁 Бонусные дни: <b>{bonus_days}</b>\n📊 Макс. активаций: <b>{max_activations}</b>\n⏰ Срок действия: <b>{validity}</b>",
"admin_promo_list_page_info": "Страница {current}/{total} ({count} промокодов)",
"admin_queue_status_button": "📊 Статус очередей",
"admin_queue_status_title": "📊 Статус очередей сообщений",