Compare commits
1 Commits
features/f
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| ac6297415c |
@@ -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}")
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"]} - только из наличия")
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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):
|
||||
"""Выбирает позицию для заказа"""
|
||||
|
||||
Reference in New Issue
Block a user