This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import httpx
|
||||
@@ -11,14 +12,26 @@ from app.models.user import User
|
||||
MODERATOR_ROLES = {"admin", "verifier", "moderator"}
|
||||
|
||||
|
||||
async def notify_user(user: User, text: str) -> bool:
|
||||
async def notify_user(
|
||||
user: User,
|
||||
text: str,
|
||||
*,
|
||||
web_app_url: str | None = None,
|
||||
button_text: str = "Открыть",
|
||||
) -> bool:
|
||||
if not settings.bot_token or settings.app_env == "test":
|
||||
return False
|
||||
data: dict[str, str] = {"chat_id": str(user.telegram_id), "text": text}
|
||||
if web_app_url:
|
||||
data["reply_markup"] = json.dumps(
|
||||
{"inline_keyboard": [[{"text": button_text, "web_app": {"url": web_app_url}}]]},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=5) as client:
|
||||
response = await client.post(
|
||||
f"https://api.telegram.org/bot{settings.bot_token}/sendMessage",
|
||||
data={"chat_id": str(user.telegram_id), "text": text},
|
||||
data=data,
|
||||
)
|
||||
return response.status_code < 400
|
||||
except Exception:
|
||||
|
||||
@@ -191,6 +191,8 @@ async def create_service_notification(
|
||||
appointment_id: int | None = None,
|
||||
send_telegram: bool = True,
|
||||
idempotency_key: str | None = None,
|
||||
web_app_url: str | None = None,
|
||||
button_text: str = "Открыть",
|
||||
) -> ServiceNotification:
|
||||
if idempotency_key:
|
||||
existing = (
|
||||
@@ -214,7 +216,8 @@ async def create_service_notification(
|
||||
user = await session.get(User, recipient_user_id)
|
||||
if user is not None:
|
||||
notification.status = "processing"
|
||||
delivered = await notify_user(user, f"{title}\n{body}" if body else title)
|
||||
message = f"{title}\n{body}" if body else title
|
||||
delivered = await notify_user(user, message, web_app_url=web_app_url, button_text=button_text)
|
||||
if delivered:
|
||||
notification.status = "sent"
|
||||
notification.sent_at = datetime.now(UTC)
|
||||
|
||||
@@ -7,6 +7,7 @@ from fastapi import HTTPException
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import settings
|
||||
from app.models.car import (
|
||||
Car,
|
||||
InventoryTransaction,
|
||||
@@ -37,6 +38,10 @@ WORK_ORDER_STATUSES = {
|
||||
LOCKED_WORK_ORDER_STATUSES = {"completed", "cancelled", "archived"}
|
||||
|
||||
|
||||
def work_order_webapp_url(work_order_id: int) -> str:
|
||||
return f"{settings.effective_webapp_url.rstrip('/')}/work_order.html?id={work_order_id}"
|
||||
|
||||
|
||||
def money(value: Decimal | int | float | None) -> Decimal:
|
||||
return Decimal(str(value or 0)).quantize(Decimal("0.01"))
|
||||
|
||||
@@ -311,5 +316,7 @@ async def close_work_order(
|
||||
title="Работа по заказ-наряду завершена",
|
||||
body=f"{visit.work_order_number or visit.id}: {visit.final_total} {visit.currency}. Можно оставить отзыв.",
|
||||
idempotency_key=f"work_order:{visit.id}:completed",
|
||||
web_app_url=work_order_webapp_url(visit.id),
|
||||
button_text="Открыть заказ-наряд",
|
||||
)
|
||||
return service, expense
|
||||
|
||||
Reference in New Issue
Block a user