From 6a69c0d4d216d5b795f1dbbda740b7765fd37db5 Mon Sep 17 00:00:00 2001 From: "oleg.vodyanov91@gmail.com" Date: Mon, 6 Oct 2025 00:56:17 +0400 Subject: [PATCH] add task --- new_version.sh | 21 +++++++++ poetry.lock | 62 ++++++++++++++++++++++++- pyproject.toml | 2 +- src/docbot/main.py | 8 ++++ src/docbot/services/payments_service.py | 32 +++++++++++++ src/docbot/services/session_service.py | 23 ++++----- src/docbot/tasks/payments.py | 17 +++++++ src/webhook/main.py | 2 +- 8 files changed, 153 insertions(+), 14 deletions(-) create mode 100755 new_version.sh create mode 100644 src/docbot/services/payments_service.py create mode 100644 src/docbot/tasks/payments.py diff --git a/new_version.sh b/new_version.sh new file mode 100755 index 0000000..de751c9 --- /dev/null +++ b/new_version.sh @@ -0,0 +1,21 @@ +#/usr/bin/env bash + +set -ex + +stop=$1 + +if [[ -z "$stop" ]]; then + echo "stopping containers" + docker stop chatbot webhook + + docker rm chatbot webhook + + echo "deleting images" + docker rmi docbot-webhook docbot-chat + + echo "starting services" + docker-compose --progress=plain --profile development up -d +else + docker-compose --progress=plain --profile development down +fi + diff --git a/poetry.lock b/poetry.lock index a27ead4..fa1a140 100644 --- a/poetry.lock +++ b/poetry.lock @@ -89,6 +89,34 @@ doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] +[[package]] +name = "apscheduler" +version = "3.11.0" +description = "In-process task scheduler with Cron-like capabilities" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "APScheduler-3.11.0-py3-none-any.whl", hash = "sha256:fc134ca32e50f5eadcc4938e3a4545ab19131435e851abb40b34d63d5141c6da"}, + {file = "apscheduler-3.11.0.tar.gz", hash = "sha256:4c622d250b0955a65d5d0eb91c33e6d43fd879834bf541e0a18661ae60460133"}, +] + +[package.dependencies] +tzlocal = ">=3.0" + +[package.extras] +doc = ["packaging", "sphinx", "sphinx-rtd-theme (>=1.3.0)"] +etcd = ["etcd3", "protobuf (<=3.21.0)"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=1.4)"] +test = ["APScheduler[etcd,mongodb,redis,rethinkdb,sqlalchemy,tornado,zookeeper]", "PySide6 ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "anyio (>=4.5.2)", "gevent ; python_version < \"3.14\"", "pytest", "pytz", "twisted ; python_version < \"3.14\""] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + [[package]] name = "asyncpg" version = "0.30.0" @@ -1111,6 +1139,7 @@ files = [ ] [package.dependencies] +apscheduler = {version = ">=3.10.4,<3.12.0", optional = true, markers = "extra == \"job-queue\""} httpx = ">=0.27,<1.0" [package.extras] @@ -1352,6 +1381,37 @@ files = [ [package.dependencies] typing-extensions = ">=4.12.0" +[[package]] +name = "tzdata" +version = "2025.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"}, + {file = "tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd"}, +] + +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "uvicorn" version = "0.34.2" @@ -1597,4 +1657,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = "^3.12" -content-hash = "337def2431e36d8fde59d4273d3db93edf87a73ac78c74307f5c44def8c0a04d" +content-hash = "33b9101bfbd65f8f77dfaf7e39b2103e7ea7e8c41dbcb72bed9063198e4ed0ca" diff --git a/pyproject.toml b/pyproject.toml index 05fe402..d5e3cd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.dependencies] python = "^3.12" -python-telegram-bot = "22.1" # или aiogram v3 +python-telegram-bot = {extras = ["job-queue"], version = "22.1"} fastapi = "0.115.12" uvicorn = {extras = ["standard"], version = "0.34.2"} sqlalchemy = "2.0.41" diff --git a/src/docbot/main.py b/src/docbot/main.py index 6be376c..e74a110 100644 --- a/src/docbot/main.py +++ b/src/docbot/main.py @@ -13,6 +13,7 @@ from docbot.handlers.doctors.add_payments_method import get_add_payment_method_h from docbot.handlers.utils.help import get_help_handler from docbot.handlers.utils.unknown import get_unknown_handler from docbot.handlers.utils.cancel_handler import get_cancel_handler +from docbot.tasks.payments import map_payments def main(): @@ -41,6 +42,13 @@ def main(): app.add_handler(get_unknown_handler()) logger.info("Все хэндлеры зарегистрированы, запускаем polling") + + logger.info("Запускаем таски") + job_queue = app.job_queue + + payments_mapping_task = job_queue.run_repeating(map_payments, interval=60, first=10) + logger.info("Таски запущены") + app.run_polling() diff --git a/src/docbot/services/payments_service.py b/src/docbot/services/payments_service.py new file mode 100644 index 0000000..25b6a4a --- /dev/null +++ b/src/docbot/services/payments_service.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +from datetime import datetime + +from sqlalchemy import select + +from db.session import AsyncSessionLocal +from db.models import ( + Sessions, + PaymentsRegistered +) +from core.logging import logger + + +async def save_payment_completed_info_from_prodamus(code: str) -> bool: + async with AsyncSessionLocal() as session: + async with session.begin(): + payment_completed = PaymentsRegistered( + code=code + ) + session.add(payment_completed) + return True + return False + + +async def get_not_mapped_payments() -> Sequence[Row[Tuple[PaymentsRegistered]]] | None: + async with AsyncSessionLocal() as session: + result = await session.execute( + select(PaymentsRegistered) + ) + + return result.all() \ No newline at end of file diff --git a/src/docbot/services/session_service.py b/src/docbot/services/session_service.py index bedd92f..5e26c07 100644 --- a/src/docbot/services/session_service.py +++ b/src/docbot/services/session_service.py @@ -48,17 +48,6 @@ async def create_session(telegram_id: int, phone: str, consultation_date_time: s return code -async def save_payment_completed_info_from_prodamus(code: str) -> bool: - async with AsyncSessionLocal() as session: - async with session.begin(): - payment_completed = PaymentsRegistered( - code=code - ) - session.add(payment_completed) - return True - return False - - async def mark_consulted(code: str) -> bool: """ Отмечает, что консультация получена (добавляет consulted_at). @@ -110,3 +99,15 @@ async def get_session_info(code: str) -> dict | None: "sent_at": sc.sent_at, "consulted_at": sc.consulted_at, } + + +async def get_sessions_awaiting_payments() -> Sequence[Row[Sessions]]: + async with AsyncSessionLocal() as session: + async with session.begin(): + result = await session.execute( + select(Sessions).where(Sessions.paid_at.is_(None)) + ) + sc: Sessions | None = result.scalars() + if not sc: + return False + return result.all() \ No newline at end of file diff --git a/src/docbot/tasks/payments.py b/src/docbot/tasks/payments.py new file mode 100644 index 0000000..e1ecd8c --- /dev/null +++ b/src/docbot/tasks/payments.py @@ -0,0 +1,17 @@ +from telegram.ext import ( + ContextTypes +) +from docbot.services.payments_service import get_not_mapped_payments +from docbot.services.session_service import get_sessions_awaiting_payments +from core.logging import logger + +# Сопоставляем оплаты, которые пришли от продамуса с сессиями, по которым ещё не было оплаты +async def map_payments(context: ContextTypes.DEFAULT_TYPE) -> None: + not_mapped_payments: Sequence[Row[PaymentsRegistered]] = await get_not_mapped_payments() + sessions_awaiting_payments: Sequence[Row[Sessions]] = await get_sessions_awaiting_payments() + + for payment in not_mapped_payments: + logger.info(f"Оплата с продамуса: {payment.PaymentsRegistered.code}") + + for session in sessions_awaiting_payments: + logger.info(f"Неоплаченная сессия: {session.Sessions.code}") diff --git a/src/webhook/main.py b/src/webhook/main.py index 060f159..5d34958 100644 --- a/src/webhook/main.py +++ b/src/webhook/main.py @@ -1,7 +1,7 @@ from fastapi import FastAPI, Request, Header, HTTPException from starlette.background import BackgroundTask from typing import Any, Dict -from docbot.services.session_service import save_payment_completed_info_from_prodamus +from docbot.services.payments_service import save_payment_completed_info_from_prodamus import json import logging