From b29bf9a3544bed248d8e8d48450d24dc7ec8d053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=9D=D0=B0=D0=B4=D0=B5?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Thu, 6 Nov 2025 14:00:08 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=20=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B0=20=D0=BC=D0=B0=D1=81=D1=81?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20(=D0=BE=D0=B4=D0=B8=D0=BD=20XML=20=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=BC=D0=BD=D0=BE=D0=B6=D0=B5=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bot.py | 207 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 166 insertions(+), 41 deletions(-) diff --git a/bot.py b/bot.py index 282539b..b33fe4f 100644 --- a/bot.py +++ b/bot.py @@ -56,8 +56,9 @@ logger = logging.getLogger(__name__) SELECT_FORMAT, SELECT_TEMPLATE, DOWNLOAD_DOCUMENT, - BATCH_INPUT -) = range(11) + BATCH_INPUT, + BATCH_FORMAT_CHOICE +) = range(12) # Менеджер пользователей user_manager = UserManager() @@ -1307,8 +1308,7 @@ async def batch_generation_prompt( "Примеры:\n" " 4926,4927,4928\n" " 00001,00002,00003\n\n" - "⚠️ Все отгрузки будут объединены в один XML файл " - "(EnterpriseData 1.20).", + "Максимум 50 отгрузок за раз.", parse_mode='HTML', reply_markup=ReplyKeyboardMarkup( [["⬅️ Назад"]], @@ -1319,11 +1319,11 @@ async def batch_generation_prompt( return BATCH_INPUT -async def batch_generation_process( +async def batch_format_choice( update: Update, context: ContextTypes.DEFAULT_TYPE ): - """Обработка массовой генерации""" + """Выбор формата генерации: один файл или множество""" user_id = update.effective_user.id text = update.message.text.strip() @@ -1354,9 +1354,72 @@ async def batch_generation_process( ) return BATCH_INPUT + # Сохраняем номера в контекст + context.user_data['batch_order_numbers'] = order_numbers + + # Предлагаем выбор формата + keyboard = [ + ["📄 Один файл (все документы)"], + ["📑 Отдельные файлы (каждый документ)"], + ["⬅️ Назад"] + ] + + await update.message.reply_text( + f"✅ Будет обработано отгрузок: {len(order_numbers)}\n\n" + "Выберите формат генерации:", + parse_mode='HTML', + reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True) + ) + + return BATCH_FORMAT_CHOICE + + +async def batch_generation_process( + update: Update, + context: ContextTypes.DEFAULT_TYPE +): + """Обработка массовой генерации""" + user_id = update.effective_user.id + text = update.message.text.strip() + + # Проверка на отмену + if text == "⬅️ Назад": + await update.message.reply_text( + "Массовая генерация отменена.", + reply_markup=get_main_keyboard() + ) + return MAIN_MENU + + # Определяем режим генерации + if text == "📄 Один файл (все документы)": + batch_mode = True + elif text == "📑 Отдельные файлы (каждый документ)": + batch_mode = False + else: + await update.message.reply_text( + "❌ Неверный выбор. Попробуйте ещё раз:", + parse_mode='HTML' + ) + return BATCH_FORMAT_CHOICE + + # Получаем сохранённые номера + order_numbers = context.user_data.get('batch_order_numbers', []) + if not order_numbers: + await update.message.reply_text( + "❌ Ошибка: номера отгрузок не найдены. " + "Начните заново.", + reply_markup=get_main_keyboard() + ) + return MAIN_MENU + # Уведомление о начале обработки + mode_text = ( + "один общий файл" if batch_mode + else f"{len(order_numbers)} отдельных файлов" + ) progress_msg = await update.message.reply_text( f"⏳ Обработка {len(order_numbers)} отгрузок...\n" + f"Режим: {mode_text}\n\n" f"Это может занять некоторое время." ) @@ -1372,7 +1435,8 @@ async def batch_generation_process( try: # Обновляем прогресс await progress_msg.edit_text( - f"⏳ Обработка отгрузки {idx}/{len(order_numbers)}: {order_num}" + f"⏳ Обработка отгрузки {idx}/{len(order_numbers)}: " + f"{order_num}" ) # Поиск отгрузки @@ -1399,7 +1463,9 @@ async def batch_generation_process( # Проверка результатов if not orders_data: - error_text = "❌ Не удалось обработать ни одной отгрузки\n\n" + error_text = ( + "❌ Не удалось обработать ни одной отгрузки\n\n" + ) if not_found: error_text += f"Не найдено: {', '.join(not_found)}\n" if errors: @@ -1428,39 +1494,89 @@ async def batch_generation_process( output_dir = Path("temp_documents") output_dir.mkdir(exist_ok=True) - # Генерируем пакетный XML - xml_filename = f"batch_{len(orders_data)}_orders.xml" - xml_path = str(output_dir / xml_filename) - xml_gen.generate_batch_realization(orders_data, xml_path) - - # Формируем отчёт - order_names = [ - od['order'].get('name', 'N/A') - for od in orders_data - ] - - caption = ( - f"✅ Пакетный XML создан!\n\n" - f"📦 Документов: {len(orders_data)}\n" - f"📋 Отгрузки: {', '.join(order_names)}\n\n" - ) - - if not_found: - caption += f"⚠️ Не найдено: {', '.join(not_found)}\n" - if errors: - caption += f"⚠️ Ошибок: {len(errors)}\n" - - caption += "\n📄 Формат: 1С EnterpriseData 1.20" - - # Отправляем файл - await update.message.reply_document( - document=open(xml_path, 'rb'), - caption=caption, - parse_mode='HTML' - ) - - # Удаляем временный файл - os.remove(xml_path) + if batch_mode: + # ОДИН ФАЙЛ - все документы в одном XML + xml_filename = f"batch_{len(orders_data)}_orders.xml" + xml_path = str(output_dir / xml_filename) + xml_gen.generate_batch_realization(orders_data, xml_path) + + # Формируем отчёт + order_names = [ + od['order'].get('name', 'N/A') + for od in orders_data + ] + + caption = ( + f"✅ Пакетный XML создан!\n\n" + f"📦 Документов: {len(orders_data)}\n" + f"📋 Отгрузки: {', '.join(order_names)}\n\n" + ) + + if not_found: + caption += f"⚠️ Не найдено: {', '.join(not_found)}\n" + if errors: + caption += f"⚠️ Ошибок: {len(errors)}\n" + + caption += "\n📄 Формат: 1С EnterpriseData 1.20" + + # Отправляем файл + await update.message.reply_document( + document=open(xml_path, 'rb'), + caption=caption, + parse_mode='HTML' + ) + + # Удаляем временный файл + os.remove(xml_path) + + else: + # МНОЖЕСТВО ФАЙЛОВ - каждый документ отдельно + generated_files = [] + + for idx, order_data in enumerate(orders_data, 1): + order_name = order_data['order'].get('name', f'order_{idx}') + xml_filename = f"order_{order_name}.xml" + xml_path = str(output_dir / xml_filename) + + # Генерируем отдельный XML + xml_gen.generate_realization(order_data, xml_path) + generated_files.append((xml_path, order_name)) + + # Отправляем все файлы + await progress_msg.edit_text( + f"✅ Сгенерировано {len(generated_files)} файлов\n" + f"⏳ Отправка..." + ) + + for xml_path, order_name in generated_files: + caption = ( + f"📄 Отгрузка {order_name}\n" + f"Формат: 1С EnterpriseData 1.20" + ) + + await update.message.reply_document( + document=open(xml_path, 'rb'), + caption=caption, + parse_mode='HTML' + ) + + # Удаляем временный файл + os.remove(xml_path) + + # Итоговая статистика + summary = ( + f"✅ Массовая генерация завершена!\n\n" + f"📦 Отправлено файлов: {len(generated_files)}\n" + ) + if not_found: + summary += f"⚠️ Не найдено: {', '.join(not_found)}\n" + if errors: + summary += f"⚠️ Ошибок: {len(errors)}\n" + + await update.message.reply_text( + summary, + parse_mode='HTML' + ) # Показываем главное меню await update.message.reply_text( @@ -1470,6 +1586,9 @@ async def batch_generation_process( await progress_msg.delete() + # Очищаем контекст + context.user_data.pop('batch_order_numbers', None) + return MAIN_MENU except Exception as e: @@ -1580,6 +1699,12 @@ def main(): MessageHandler(filters.TEXT & ~filters.COMMAND, handle_text), ], BATCH_INPUT: [ + MessageHandler( + filters.TEXT & ~filters.COMMAND, + batch_format_choice + ), + ], + BATCH_FORMAT_CHOICE: [ MessageHandler( filters.TEXT & ~filters.COMMAND, batch_generation_process