partner-core/integration_api.py

170 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import FastAPI, Depends, HTTPException, status, Header
from fastapi.security import OAuth2PasswordBearer
from sqlmodel import Session, select
from typing import Optional
from datetime import datetime
import hashlib
import uuid
from sql_models import Company, IntegrationToken, Ref, Sale, AgentTransaction, PartnerTransaction, AgentBalance, TgAgent, CompanyBalance
from integration_models import Token, SaleCreateRequest, SaleCreateResponse, TransactionStatus
from helpers_bff import AUTH_DB_ENGINE, get_integration_db, create_integration_jwt_token, get_current_company_from_jwt
app = FastAPI()
#7c06945b-f4b8-4929-8350-b9841405a609
@app.post("/token", tags=["integration"], response_model=Token)
async def get_token_for_api_key(
x_api_key: str = Header(..., alias="X-API-Key"),
db: Session = Depends(get_integration_db)
):
"""
Обменивает API-ключ на JWT токен.
"""
if not x_api_key:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="API-ключ не предоставлен",
headers={"WWW-Authenticate": "Bearer"},
)
api_key_hash = hashlib.sha256(x_api_key.encode()).hexdigest()
integration_token_db = db.exec(
select(IntegrationToken).where(IntegrationToken.token_hash == api_key_hash)
).first()
if not integration_token_db:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Неверный API-ключ",
headers={"WWW-Authenticate": "Bearer"},
)
# Обновляем use_dttm токена
integration_token_db.use_dttm = datetime.utcnow()
db.add(integration_token_db)
db.commit()
db.refresh(integration_token_db)
jwt_token = create_integration_jwt_token(integration_token_db.company_id)
return {"access_token": jwt_token, "token_type": "bearer"}
@app.post("/sale", tags=["integration"], response_model=SaleCreateResponse)
async def create_sale(
req: SaleCreateRequest,
company: Company = Depends(get_current_company_from_jwt), # Используем новую зависимость
db: Session = Depends(get_integration_db)
):
"""
Регистрирует новую продажу в системе.
"""
# 1. Найти Ref по `ref` и `company.id`
# Сначала находим TgAgent, связанный с компанией, затем Ref
tg_agent = db.exec(
select(TgAgent)
.join(Ref)
.where(TgAgent.company_id == company.id)
.where(Ref.ref == req.ref)
).first()
if not tg_agent:
raise HTTPException(status_code=404, detail="Реферальная ссылка не найдена или не принадлежит данной компании")
referral = db.exec(select(Ref).where(Ref.ref == req.ref).where(Ref.tg_agent_id == tg_agent.id)).first()
if not referral:
raise HTTPException(status_code=404, detail="Реферальная ссылка не найдена")
# 2. Проверить, что sale_id уникален для данной компании
existing_sale = db.exec(
select(Sale)
.where(Sale.company_id == company.id)
.where(Sale.sale_id == req.sale_id)
).first()
if existing_sale:
raise HTTPException(status_code=400, detail="Продажа с таким sale_id уже существует для данной компании")
# 3. Рассчитать crediting
crediting_amount = req.cost * (company.agent_commission / 100.0)
# 4. Создать Sale
new_sale = Sale(
cost=req.cost,
crediting=crediting_amount,
ref=referral.id,
sale_id=req.sale_id,
company_id=company.id,
sale_dttm=datetime.utcnow()
)
db.add(new_sale)
db.commit()
db.refresh(new_sale)
# 5. Обновить AgentBalance и CompanyBalance
# AgentBalance
agent_balance = db.exec(select(AgentBalance).where(AgentBalance.tg_agent_id == tg_agent.id)).first()
if not agent_balance:
agent_balance = AgentBalance(tg_agent_id=tg_agent.id, available_balance=0.0, frozen_balance=0.0)
db.add(agent_balance)
db.commit()
db.refresh(agent_balance)
# CompanyBalance
company_balance = db.exec(select(CompanyBalance).where(CompanyBalance.company_id == company.id)).first()
if not company_balance:
company_balance = CompanyBalance(company_id=company.id, available_balance=0.0, pending_balance=0.0)
db.add(company_balance)
db.commit()
db.refresh(company_balance)
# Создать AgentTransaction
agent_transaction_status = TransactionStatus.NEW if company.auto_approve_transactions else TransactionStatus.WAITING
agent_transaction = AgentTransaction(
tg_agent_id=tg_agent.id,
amount=crediting_amount,
status=agent_transaction_status.value,
transaction_group=uuid.uuid4()
)
db.add(agent_transaction)
db.commit()
db.refresh(agent_transaction)
# Создать PartnerTransaction
partner_transaction_status = TransactionStatus.NEW if company.auto_approve_transactions else TransactionStatus.PROCESS
partner_transaction = PartnerTransaction(
company_id=company.id,
type="sale_crediting",
amount=crediting_amount,
status=partner_transaction_status.value,
transaction_group=agent_transaction.transaction_group,
agent_transaction_id=agent_transaction.id
)
db.add(partner_transaction)
db.commit()
db.refresh(partner_transaction)
# Обновление балансов в зависимости от auto_approve_transactions
if company.auto_approve_transactions:
agent_balance.available_balance += crediting_amount
company_balance.available_balance -= crediting_amount
company_balance.updated_dttm = datetime.utcnow()
else:
agent_balance.frozen_balance += crediting_amount
company_balance.pending_balance -= crediting_amount
company_balance.updated_dttm = datetime.utcnow()
db.add(agent_balance)
db.add(company_balance)
db.commit()
db.refresh(agent_balance)
db.refresh(company_balance)
return {
"msg": "Продажа успешно зарегистрирована",
"sale_id": new_sale.sale_id,
"crediting": new_sale.crediting
}