diff --git a/src/mail_order_bot/task_processor/handlers/delivery_time/from_config.py b/src/mail_order_bot/task_processor/handlers/delivery_time/from_config.py index 228eb33..473f28a 100644 --- a/src/mail_order_bot/task_processor/handlers/delivery_time/from_config.py +++ b/src/mail_order_bot/task_processor/handlers/delivery_time/from_config.py @@ -6,6 +6,7 @@ import logging from ...abstract_task import AbstractTask, pass_if_error, handle_errors +from ...exceptions import TaskExceptionWithEmailNotify logger = logging.getLogger(__name__) @@ -13,12 +14,12 @@ class DeliveryPeriodFromConfig(AbstractTask): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - @pass_if_error + #@pass_if_error def do(self, attachment) -> None: try: delivery_period = self.config.get("delivery_period") attachment["delivery_period"] = delivery_period logger.warning(f"Срок доставки установлен из конфига - {delivery_period} (ч.)") except Exception as e: - raise Exception(f"Ошибка при установке срока доставки из конфига. Детали ошибки: {e}") + raise TaskExceptionWithEmailNotify(f"Ошибка при установке срока доставки из конфига. Детали ошибки: {e}") diff --git a/src/mail_order_bot/task_processor/handlers/delivery_time/from_subject.py b/src/mail_order_bot/task_processor/handlers/delivery_time/from_subject.py index bac2a60..27bf16a 100644 --- a/src/mail_order_bot/task_processor/handlers/delivery_time/from_subject.py +++ b/src/mail_order_bot/task_processor/handlers/delivery_time/from_subject.py @@ -3,6 +3,7 @@ """ from ...abstract_task import AbstractTask, pass_if_error, handle_errors +from ...exceptions import TaskExceptionWithEmailNotify import logging import re @@ -48,7 +49,7 @@ class DeliveryPeriodFromSubject(AbstractTask): logger.debug(f"Срок доставки для файла {attachment["name"]} установлен как {delivery_time}") except Exception as e: - logger.error(e) + raise TaskExceptionWithEmailNotify(f"Ошибка при установке срока доставки из темы письма. Детали ошибки: {e}") def _parse_delivery_period(self, subject: str) -> int: diff --git a/src/mail_order_bot/task_processor/handlers/delivery_time/local_store.py b/src/mail_order_bot/task_processor/handlers/delivery_time/local_store.py index 4cb8796..1d8bfcd 100644 --- a/src/mail_order_bot/task_processor/handlers/delivery_time/local_store.py +++ b/src/mail_order_bot/task_processor/handlers/delivery_time/local_store.py @@ -13,8 +13,6 @@ class DeliveryPeriodLocalStore(AbstractTask): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - def do(self) -> None: - attachments = self.context.data["attachments"] - for attachment in attachments: - attachment["delivery_period"] = 0 - logger.info(f"Срок доставки для файла {attachment["name"]} - только из наличия") + def do(self, attachment) -> None: + attachment["delivery_period"] = 0 + logger.info(f"Срок доставки для файла {attachment["name"]} - только из наличия") diff --git a/src/mail_order_bot/task_processor/handlers/email/email_reply_task.py b/src/mail_order_bot/task_processor/handlers/email/email_reply_task.py index 3408b6a..c08a3f8 100644 --- a/src/mail_order_bot/task_processor/handlers/email/email_reply_task.py +++ b/src/mail_order_bot/task_processor/handlers/email/email_reply_task.py @@ -8,6 +8,7 @@ from email import encoders from ...abstract_task import AbstractTask, pass_if_error, handle_errors +from ...exceptions import TaskExceptionWithEmailNotify logger = logging.getLogger(__name__) @@ -19,40 +20,41 @@ class EmailReplyTask(AbstractTask): """Формирует ответ на входящее письмо с запросом на заказ°""" EMAIl = "zosimovaa@yandex.ru" #"noreply@zapchastiya.ru" - @pass_if_error + #@pass_if_error #@handle_errors def do(self, attachment): + try: + email = self.context.data.get("email") - email = self.context.data.get("email") + if not email: + raise ValueError("В контексте нет входящего сообщения") - if not email: - raise ValueError("В контексте нет входящего сообщения") - - email_from = self.context.data.get("email_from") - if not email_from: - raise ValueError("В контексте не определен адрес отправителя") + email_from = self.context.data.get("email_from") + if not email_from: + raise ValueError("В контексте не определен адрес отправителя") - reply_message = MIMEMultipart() + reply_message = MIMEMultipart() - email_subj = self.context.data.get("email_subj") + email_subj = self.context.data.get("email_subj") - reply_message["From"] = os.environ.get("EMAIL_USER") - reply_message["To"] = email_from - #reply_message["Cc"] = self.config.get("reply_to", "") - reply_message["Subject"] = f"Re: {email_subj}" - reply_message["Date"] = formatdate(localtime=True) + reply_message["From"] = os.environ.get("EMAIL_USER") + reply_message["To"] = email_from + #reply_message["Cc"] = self.config.get("reply_to", "") + reply_message["Subject"] = f"Re: {email_subj}" + reply_message["Date"] = formatdate(localtime=True) - body = "Автоматический ответ на создание заказа" - reply_message.attach(MIMEText(body, "plain", "utf-8")) + body = "Автоматический ответ на создание заказа" + reply_message.attach(MIMEText(body, "plain", "utf-8")) - self._attach_file(reply_message, attachment) + self._attach_file(reply_message, attachment) - self.context.email_client.send_email(reply_message) - - logger.warning(f"Сформирован ответ на заказ на email") + self.context.email_client.send_email(reply_message) + logger.warning(f"Сформирован ответ на заказ на email") + except Exception as e: + raise TaskExceptionWithEmailNotify("Произошла ошибка при отправке уведомления клиенту об успешном заказе") def _attach_file(self, reply_message, attachment): """ diff --git a/src/mail_order_bot/task_processor/handlers/excel_parcers/excel_extractor.py b/src/mail_order_bot/task_processor/handlers/excel_parcers/excel_extractor.py index e9afd7b..5d41b47 100644 --- a/src/mail_order_bot/task_processor/handlers/excel_parcers/excel_extractor.py +++ b/src/mail_order_bot/task_processor/handlers/excel_parcers/excel_extractor.py @@ -2,6 +2,7 @@ import logging from io import BytesIO from mail_order_bot.task_processor.abstract_task import AbstractTask, pass_if_error, handle_errors from mail_order_bot.task_processor.handlers.excel_parcers.order_extractor import ExcelFileParcer +from ...exceptions import TaskExceptionWithEmailNotify logger = logging.getLogger(__name__) @@ -15,10 +16,13 @@ class ExcelExtractor(AbstractTask): super().__init__(*args, **kwargs) self.excel_config = self.config.get("excel", {}) - @pass_if_error + #@pass_if_error #@handle_errors def do(self, attachment) -> None: - file_bytes = BytesIO(attachment['bytes']) - excel_file = ExcelFileParcer(file_bytes, self.excel_config) - attachment["excel"] = excel_file - logger.warning(f"Произведен успешный парсинг файла {attachment.get('name', 'неизвестный файл')}") + try: + file_bytes = BytesIO(attachment['bytes']) + excel_file = ExcelFileParcer(file_bytes, self.excel_config) + attachment["excel"] = excel_file + logger.warning(f"Произведен успешный парсинг файла {attachment.get('name', 'неизвестный файл')}") + except Exception as e: + raise TaskExceptionWithEmailNotify("Произошла ошибка при парсинге эксель файла. Детали ошибки: {e}") diff --git a/src/mail_order_bot/task_processor/handlers/excel_parcers/order_extractor.py b/src/mail_order_bot/task_processor/handlers/excel_parcers/order_extractor.py index fbf6b2a..38f104a 100644 --- a/src/mail_order_bot/task_processor/handlers/excel_parcers/order_extractor.py +++ b/src/mail_order_bot/task_processor/handlers/excel_parcers/order_extractor.py @@ -3,6 +3,7 @@ import pandas as pd from io import BytesIO from mail_order_bot.parsers.order_parcer import OrderParser from ...abstract_task import AbstractTask, pass_if_error, handle_errors +from ...exceptions import TaskExceptionWithEmailNotify from mail_order_bot.parsers.excel_parcer import ExcelFileParcer @@ -19,23 +20,26 @@ class OrderExtractor(AbstractTask): self.excel_config = self.config.get("excel", {}) @pass_if_error - #@handle_errors + #@handle_errors("Произошла ошибка при парсинге заказа") def do(self, attachment) -> None: - # todo сделать проверку на наличие файла и его тип - delivery_period = attachment.get("delivery_period", 0) - mapping = self.excel_config.get("mapping") + try: + # todo сделать проверку на наличие файла и его тип + delivery_period = attachment.get("delivery_period", 0) + mapping = self.excel_config.get("mapping") - excel_file = attachment.get("excel") - client_id = self.config.get("client_id") + excel_file = attachment.get("excel") + client_id = self.config.get("client_id") - order_parcer = OrderParser(mapping, delivery_period, client_id) + order_parcer = OrderParser(mapping, delivery_period, client_id) - order_dataframe = excel_file.get_order_rows() - order = order_parcer.parse(order_dataframe) + order_dataframe = excel_file.get_order_rows() + order = order_parcer.parse(order_dataframe) - attachment["order"] = order + attachment["order"] = order - logger.warning(f"Файл заказа обработан успешно, извлечено {len(order.positions)} позиций") + logger.warning(f"Файл заказа обработан успешно, извлечено {len(order.positions)} позиций") + except Exception as e: + raise TaskExceptionWithEmailNotify(f"Ошибка при парсинге заказа. Детали ошибки: {e}") diff --git a/src/mail_order_bot/task_processor/handlers/excel_parcers/update_excel_file.py b/src/mail_order_bot/task_processor/handlers/excel_parcers/update_excel_file.py index 937e344..117db6c 100644 --- a/src/mail_order_bot/task_processor/handlers/excel_parcers/update_excel_file.py +++ b/src/mail_order_bot/task_processor/handlers/excel_parcers/update_excel_file.py @@ -1,6 +1,6 @@ import logging from ...abstract_task import AbstractTask, pass_if_error, handle_errors - +from ...exceptions import TaskExceptionWithEmailNotify logger = logging.getLogger(__name__) @@ -15,31 +15,34 @@ class UpdateExcelFile(AbstractTask): super().__init__(*args, **kwargs) self.excel_config = self.config.get("excel", {}) - @pass_if_error + #@pass_if_error #@handle_errors def do(self, attachment) -> None: - # todo сделать проверку на наличие файла и его тип - excel_file = attachment.get("excel") - order = attachment.get("order") - config = self.context.data.get("config", {}) - excel_config = config.get("excel", {}) - updatable_fields = excel_config.get("updatable_fields", {}) + try: + # todo сделать проверку на наличие файла и его тип + excel_file = attachment.get("excel") + order = attachment.get("order") + config = self.context.data.get("config", {}) + excel_config = config.get("excel", {}) + updatable_fields = excel_config.get("updatable_fields", {}) - for position in order.positions: + for position in order.positions: - sku = position.sku - manufacturer = position.manufacturer + sku = position.sku + manufacturer = position.manufacturer - for key, value in updatable_fields.items(): + for key, value in updatable_fields.items(): - if key == "ordered_quantity": - column = value - value = position.order_quantity - excel_file.set_value(sku, manufacturer, column, value) + if key == "ordered_quantity": + column = value + value = position.order_quantity + excel_file.set_value(sku, manufacturer, column, value) - if key == "ordered_price": - column = value - value = position.order_price - excel_file.set_value(sku, manufacturer, column, value) + if key == "ordered_price": + column = value + value = position.order_price + excel_file.set_value(sku, manufacturer, column, value) - logger.warning(f"Файла {attachment.get('name', 'неизвестный файл')} отредактирован") + logger.warning(f"Файла {attachment.get('name', 'неизвестный файл')} отредактирован") + except Exception as e: + raise TaskExceptionWithEmailNotify(f"Не удалось отредактировать исходный файл с заказом. Детали ошибки: {e}") diff --git a/src/mail_order_bot/task_processor/handlers/notifications/test_notifier.py b/src/mail_order_bot/task_processor/handlers/notifications/test_notifier.py index 93e7f71..4f0e16f 100644 --- a/src/mail_order_bot/task_processor/handlers/notifications/test_notifier.py +++ b/src/mail_order_bot/task_processor/handlers/notifications/test_notifier.py @@ -9,6 +9,7 @@ import logging from ...abstract_task import AbstractTask, pass_if_error, handle_errors from mail_order_bot.abcp_api.abcp_provider import AbcpProvider from mail_order_bot.credential_provider import CredentialProvider +from ...exceptions import TaskExceptionSilent from mail_order_bot.telegram.client import TelegramClient @@ -19,23 +20,26 @@ class TelegramNotifier(AbstractTask): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - @pass_if_error + #@pass_if_error # @handle_errors def do(self, attachment) -> None: - message = self.build_message(attachment) + try: + message = self.build_message(attachment) - client = TelegramClient() - result = client.send_message(message) + client = TelegramClient() + result = client.send_message(message) - # Отправка экселя в телеграм - excel = attachment["excel"] - file = excel.get_file_bytes() - client.send_document( - document=file, - filename=attachment.get("name", "document.xlsx") - ) + # Отправка экселя в телеграм + excel = attachment["excel"] + file = excel.get_file_bytes() + client.send_document( + document=file, + filename=attachment.get("name", "document.xlsx") + ) - logger.warning("Инфо по заказу отправлено в телеграм") + logger.warning("Инфо по заказу отправлено в телеграм") + except Exception as e: + raise TaskExceptionSilent(f"Ошибка при отправке в телеграм. Детали ошибки: {e}") def build_message(self, attachment): order = attachment["order"] diff --git a/src/mail_order_bot/task_processor/handlers/stock_selectors/stock_selector.py b/src/mail_order_bot/task_processor/handlers/stock_selectors/stock_selector.py index a0d5228..dd25c59 100644 --- a/src/mail_order_bot/task_processor/handlers/stock_selectors/stock_selector.py +++ b/src/mail_order_bot/task_processor/handlers/stock_selectors/stock_selector.py @@ -15,17 +15,15 @@ from mail_order_bot.abcp_api.abcp_provider import AbcpProvider from mail_order_bot.credential_provider import CredentialProvider from mail_order_bot.order.auto_part_order import OrderStatus -from ...exceptions import TaskException +from ...exceptions import TaskExceptionWithEmailNotify from typing import Dict, Any from typing import List, Optional logger = logging.getLogger(__name__) -class StockSelectorException(TaskException): - pass -class RefusalLevelExceededException(TaskException): +class RefusalLevelExceededException(TaskExceptionWithEmailNotify): pass @@ -46,39 +44,45 @@ class StockSelector(AbstractTask): #@handle_errors def do(self, attachment) -> None: # todo сделать проверку на наличие файла и его тип - order = attachment.get("order", None) - delivery_period = attachment.get("delivery_period") - for position in order.positions: + try: + order = attachment.get("order", None) + delivery_period = attachment.get("delivery_period") + for position in order.positions: - #1. Получаем остатки со складов - stock_data = self.client_provider.get_stock(position.sku, position.manufacturer) + #1. Получаем остатки со складов + stock_data = self.client_provider.get_stock(position.sku, position.manufacturer) - #2. Из данных остатков выбираем оптимальное значение по стратегии - if stock_data["success"]: - stock_list = stock_data.get("data", []) - asking_price = position.asking_price - asking_quantity = position.asking_quantity + #2. Из данных остатков выбираем оптимальное значение по стратегии + if stock_data["success"]: + stock_list = stock_data.get("data", []) + asking_price = position.asking_price + asking_quantity = position.asking_quantity - optimal_stock_positions = self.get_optimal_stock(stock_list, asking_price, asking_quantity, delivery_period) + optimal_stock_positions = self.get_optimal_stock(stock_list, asking_price, asking_quantity, delivery_period) - # 3. Устанавливаем выбранное значение в позицию - if len(optimal_stock_positions): - position.set_order_item(optimal_stock_positions[0]) + # 3. Устанавливаем выбранное значение в позицию + if len(optimal_stock_positions): + position.set_order_item(optimal_stock_positions[0]) + else: + position.status = PositionStatus.NO_AVAILABLE_STOCK + # Мне не очень нравится управление статусами в этом месте, кажется что лучше это делать внутри AutoPartPosition else: - position.status = PositionStatus.NO_AVAILABLE_STOCK - # Мне не очень нравится управление статусами в этом месте, кажется что лучше это делать внутри AutoPartPosition - else: - position.status = PositionStatus.STOCK_FAILED + position.status = PositionStatus.STOCK_FAILED - refusal_threshold = self.config.get("refusal_threshold", 1) - refusal_level = order.get_refusal_level() + refusal_threshold = self.config.get("refusal_threshold", 1) + refusal_level = order.get_refusal_level() - if refusal_level > refusal_threshold: - raise RefusalLevelExceededException(f"Превышен лимит по отказам, необходима ручная обработка. " - f"Уровень отказов: {refusal_level:.2%}, допустимый лимит: {refusal_threshold:.2%}") + if refusal_level > refusal_threshold: + raise RefusalLevelExceededException(f"Превышен лимит по отказам, необходима ручная обработка. " + f"Уровень отказов: {refusal_level:.2%}, допустимый лимит: {refusal_threshold:.2%}") - logger.warning("Определены оптимальные позиции со складов") + logger.warning("Определены оптимальные позиции со складов") + except RefusalLevelExceededException: + raise RefusalLevelExceededException + + except Exception as e: + raise TaskExceptionWithEmailNotify(f"Произошла ошибка при выборе позиций со складов. Детали ошибки: {e}") def get_optimal_stock(self, stock_list, asking_price, asking_quantity, delivery_period): """Выбирает позицию для заказа"""