Добавлены новые поля для агентской комиссии в модели Company и CompanyProfileResponse. Реализованы функции для обработки продаж через интеграционный API, включая создание и регистрацию продаж с учетом агентской комиссии. Обновлены соответствующие эндпоинты и модели для работы с токенами и продажами. Улучшена логика обработки транзакций и обновления балансов компаний и агентов.

This commit is contained in:
Redsandyg
2025-06-10 14:15:46 +03:00
parent 076cdd1828
commit 1cc18e0364
9 changed files with 312 additions and 160 deletions

View File

@@ -3,12 +3,13 @@ from passlib.context import CryptContext
from typing import Optional
from datetime import datetime, timedelta
from bff_models import Token, TransactionStatus
from sql_models import Company, TgAgent, Account, AgentBalance, AgentTransaction, PartnerTransaction, Sale, Ref
from sql_models import Company, TgAgent, Account, AgentBalance, AgentTransaction, PartnerTransaction, Sale, Ref, IntegrationToken, CompanyBalance
from hashlib import sha256
import jwt
from jwt.exceptions import InvalidTokenError
from fastapi import HTTPException, status, Depends, Request
from fastapi import HTTPException, status, Depends, Request, Header
from fastapi.security import OAuth2PasswordBearer
import hashlib
# Конфигурация
AUTH_DATABASE_ADDRESS = "sqlite:///partner.db"
@@ -18,9 +19,60 @@ SECRET_KEY = "supersecretkey"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60
# JWT Configuration for Integration API
INTEGRATION_SECRET_KEY = "your-super-secret-jwt-key" # TODO: Замените на реальный секретный ключ из переменных окружения
INTEGRATION_ALGORITHM = "HS256"
INTEGRATION_ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 # Токен действителен 7 дней
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def get_integration_db():
with Session(AUTH_DB_ENGINE) as session:
yield session
def create_integration_jwt_token(company_id: int):
expires = datetime.utcnow() + timedelta(minutes=INTEGRATION_ACCESS_TOKEN_EXPIRE_MINUTES)
payload = {
"sub": str(company_id),
"exp": expires,
"type": "access"
}
return jwt.encode(payload, INTEGRATION_SECRET_KEY, algorithm=INTEGRATION_ALGORITHM)
async def get_current_company_from_jwt(
token: str = Depends(OAuth2PasswordBearer(tokenUrl="/token")),
db: Session = Depends(get_integration_db)
):
"""
Зависимость для получения текущей компании на основе JWT токена для Integration API.
"""
try:
payload = jwt.decode(token, INTEGRATION_SECRET_KEY, algorithms=[INTEGRATION_ALGORITHM])
company_id: int = int(payload.get("sub"))
if company_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Недействительная полезная нагрузка токена",
headers={"WWW-Authenticate": "Bearer"},
)
company = db.exec(select(Company).where(Company.id == company_id)).first()
if not company:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Компания не найдена")
return company
except InvalidTokenError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Недействительный токен",
headers={"WWW-Authenticate": "Bearer"},
)
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Срок действия токена истек",
headers={"WWW-Authenticate": "Bearer"},
)
def get_tg_agent_by_tg_id(db: Session, tg_id: int) -> Optional[TgAgent]:
statement = select(TgAgent).where(TgAgent.tg_id == tg_id)
return db.exec(statement).first()