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\""]
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"

View File

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

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

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

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