This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Background service that e-mails CDEK waybill PDFs to customers."""
|
||||
"""Background service that e-mails provider waybill PDFs to customers."""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable, Sequence
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from contextlib import AbstractAsyncContextManager
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
@@ -15,15 +15,18 @@ logger = structlog.get_logger(__name__)
|
||||
_EMAIL_SUBJECT_TEMPLATE = "Накладная по заказу {order_uuid}"
|
||||
_EMAIL_BODY_TEMPLATE = (
|
||||
"Здравствуйте!\n\n"
|
||||
"По вашему заказу {order_uuid} сформирована транспортная накладная CDEK.\n"
|
||||
"По вашему заказу {order_uuid} сформирована "
|
||||
"транспортная накладная.\n"
|
||||
"PDF-файл накладной приложен к этому письму.\n"
|
||||
)
|
||||
_EMAIL_BODY_URL_LINE_TEMPLATE = (
|
||||
"Также накладная доступна по ссылке: {waybill_url}\n"
|
||||
)
|
||||
_ATTACHMENT_FILENAME_TEMPLATE = "waybill_{order_uuid}.pdf"
|
||||
|
||||
|
||||
class WaybillPDFDownloaderProtocol(Protocol):
|
||||
async def download_waybill_pdf(self, url: str) -> bytes: ...
|
||||
async def download_waybill_pdf(self, order: "OrderRecord") -> bytes: ...
|
||||
|
||||
|
||||
class EmailSenderProtocol(Protocol):
|
||||
@@ -40,7 +43,9 @@ class EmailSenderProtocol(Protocol):
|
||||
|
||||
class OrderRecord(Protocol):
|
||||
order_uuid: str
|
||||
provider: str
|
||||
account_email: str
|
||||
provider_waybill_id: str | None
|
||||
provider_waybill_url: str | None
|
||||
|
||||
|
||||
@@ -72,13 +77,13 @@ class WaybillEmailSenderService:
|
||||
self,
|
||||
*,
|
||||
order_repository: WaybillEmailSenderRepositoryProtocol,
|
||||
waybill_downloader: WaybillPDFDownloaderProtocol,
|
||||
waybill_downloaders: Mapping[str, WaybillPDFDownloaderProtocol],
|
||||
email_sender: EmailSenderProtocol,
|
||||
batch_size: int,
|
||||
datetime_now: Callable[[], datetime] = lambda: datetime.now(timezone.utc),
|
||||
) -> None:
|
||||
self._repository = order_repository
|
||||
self._waybill_downloader = waybill_downloader
|
||||
self._waybill_downloaders = dict(waybill_downloaders)
|
||||
self._email_sender = email_sender
|
||||
self._batch_size = batch_size
|
||||
self._datetime_now = datetime_now
|
||||
@@ -99,6 +104,7 @@ class WaybillEmailSenderService:
|
||||
logger.exception(
|
||||
"waybill_email_order_failed",
|
||||
order_uuid=order.order_uuid,
|
||||
provider=order.provider,
|
||||
account_email=order.account_email,
|
||||
)
|
||||
return SendBatchSummary(
|
||||
@@ -133,16 +139,17 @@ class WaybillEmailSenderService:
|
||||
continue
|
||||
|
||||
async def _handle_order(self, session: object, order: OrderRecord) -> None:
|
||||
waybill_url = order.provider_waybill_url
|
||||
if waybill_url is None:
|
||||
if order.provider_waybill_url is None and order.provider_waybill_id is None:
|
||||
return
|
||||
|
||||
pdf_bytes = await self._waybill_downloader.download_waybill_pdf(waybill_url)
|
||||
downloader = self._resolve_downloader(order.provider)
|
||||
pdf_bytes = await downloader.download_waybill_pdf(order)
|
||||
subject = _EMAIL_SUBJECT_TEMPLATE.format(order_uuid=order.order_uuid)
|
||||
body = _EMAIL_BODY_TEMPLATE.format(
|
||||
order_uuid=order.order_uuid,
|
||||
waybill_url=waybill_url,
|
||||
)
|
||||
body = _EMAIL_BODY_TEMPLATE.format(order_uuid=order.order_uuid)
|
||||
if order.provider_waybill_url is not None:
|
||||
body += _EMAIL_BODY_URL_LINE_TEMPLATE.format(
|
||||
waybill_url=order.provider_waybill_url,
|
||||
)
|
||||
filename = _ATTACHMENT_FILENAME_TEMPLATE.format(order_uuid=order.order_uuid)
|
||||
|
||||
await self._email_sender.send_email(
|
||||
@@ -162,6 +169,13 @@ class WaybillEmailSenderService:
|
||||
logger.info(
|
||||
"waybill_email_sent",
|
||||
order_uuid=order.order_uuid,
|
||||
provider=order.provider,
|
||||
account_email=order.account_email,
|
||||
sent_at=sent_at,
|
||||
)
|
||||
|
||||
def _resolve_downloader(self, provider: str) -> WaybillPDFDownloaderProtocol:
|
||||
downloader = self._waybill_downloaders.get(provider)
|
||||
if downloader is None:
|
||||
raise RuntimeError(f"Waybill downloader is not configured for {provider}.")
|
||||
return downloader
|
||||
|
||||
Reference in New Issue
Block a user