This commit is contained in:
oleg.vodyanov91@gmail.com 2025-10-06 00:56:17 +04:00
parent 070f446159
commit 6a69c0d4d2
8 changed files with 153 additions and 14 deletions

21
new_version.sh Executable file
View File

@ -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

62
poetry.lock generated
View File

@ -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\""] 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)"] 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]] [[package]]
name = "asyncpg" name = "asyncpg"
version = "0.30.0" version = "0.30.0"
@ -1111,6 +1139,7 @@ files = [
] ]
[package.dependencies] [package.dependencies]
apscheduler = {version = ">=3.10.4,<3.12.0", optional = true, markers = "extra == \"job-queue\""}
httpx = ">=0.27,<1.0" httpx = ">=0.27,<1.0"
[package.extras] [package.extras]
@ -1352,6 +1381,37 @@ files = [
[package.dependencies] [package.dependencies]
typing-extensions = ">=4.12.0" 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]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.34.2" version = "0.34.2"
@ -1597,4 +1657,4 @@ files = [
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "337def2431e36d8fde59d4273d3db93edf87a73ac78c74307f5c44def8c0a04d" content-hash = "33b9101bfbd65f8f77dfaf7e39b2103e7ea7e8c41dbcb72bed9063198e4ed0ca"

View File

@ -18,7 +18,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.12" python = "^3.12"
python-telegram-bot = "22.1" # или aiogram v3 python-telegram-bot = {extras = ["job-queue"], version = "22.1"}
fastapi = "0.115.12" fastapi = "0.115.12"
uvicorn = {extras = ["standard"], version = "0.34.2"} uvicorn = {extras = ["standard"], version = "0.34.2"}
sqlalchemy = "2.0.41" sqlalchemy = "2.0.41"

View File

@ -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.help import get_help_handler
from docbot.handlers.utils.unknown import get_unknown_handler from docbot.handlers.utils.unknown import get_unknown_handler
from docbot.handlers.utils.cancel_handler import get_cancel_handler from docbot.handlers.utils.cancel_handler import get_cancel_handler
from docbot.tasks.payments import map_payments
def main(): def main():
@ -41,6 +42,13 @@ def main():
app.add_handler(get_unknown_handler()) app.add_handler(get_unknown_handler())
logger.info("Все хэндлеры зарегистрированы, запускаем polling") 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() app.run_polling()

View File

@ -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()

View File

@ -48,17 +48,6 @@ async def create_session(telegram_id: int, phone: str, consultation_date_time: s
return code 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: async def mark_consulted(code: str) -> bool:
""" """
Отмечает, что консультация получена (добавляет consulted_at). Отмечает, что консультация получена (добавляет consulted_at).
@ -110,3 +99,15 @@ async def get_session_info(code: str) -> dict | None:
"sent_at": sc.sent_at, "sent_at": sc.sent_at,
"consulted_at": sc.consulted_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()

View File

@ -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}")

View File

@ -1,7 +1,7 @@
from fastapi import FastAPI, Request, Header, HTTPException from fastapi import FastAPI, Request, Header, HTTPException
from starlette.background import BackgroundTask from starlette.background import BackgroundTask
from typing import Any, Dict 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 json
import logging import logging