Compare commits

..

2 Commits

2 changed files with 138 additions and 25 deletions

View File

@ -204,9 +204,9 @@ def fill_db():
session.refresh(balance) session.refresh(balance)
# 5.3 AgentTransactions and PartnerTransactions # 5.3 AgentTransactions and PartnerTransactions
AGENT_TRANSACTION_STATUSES = ['waiting', 'process', 'done', 'reject', 'error'] AGENT_TRANSACTION_STATUSES = ['waiting', 'process', 'done', 'reject', 'error', 'new']
PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee'] PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee']
PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error'] PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error', 'new']
for tg_agent in tg_agents: for tg_agent in tg_agents:
# Генерируем несколько групп транзакций для каждого агента # Генерируем несколько групп транзакций для каждого агента

159
main.py
View File

@ -26,6 +26,7 @@ class Company(SQLModel, table=True):
key: str = Field(index=True, unique=True) key: str = Field(index=True, unique=True)
create_dttm: datetime = Field(default_factory=datetime.utcnow) create_dttm: datetime = Field(default_factory=datetime.utcnow)
update_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow)
auto_approve_transactions: bool = Field(default=False) # Новое поле для автоподтверждения
class TgAgent(SQLModel, table=True): class TgAgent(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True) id: Optional[int] = Field(default=None, primary_key=True)
@ -124,6 +125,7 @@ class TransactionStatus(str, Enum): # Определяем Enum для стат
DONE = 'done' DONE = 'done'
REJECT = 'reject' REJECT = 'reject'
ERROR = 'error' ERROR = 'error'
NEW = 'new' # Новый статус
# Новая модель ответа для агентских транзакций с именем агента # Новая модель ответа для агентских транзакций с именем агента
@ -160,6 +162,24 @@ def get_db():
with Session(AUTH_DB_ENGINE) as session: with Session(AUTH_DB_ENGINE) as session:
yield session yield session
def get_current_account(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
login: str = payload.get("sub")
if login is None:
raise credentials_exception
except InvalidTokenError:
raise credentials_exception
account = get_account_by_login(db, login)
if account is None:
raise credentials_exception
return account
# Авторизация # Авторизация
async def get_current_tg_agent(request: Request, db: Session = Depends(get_db)): async def get_current_tg_agent(request: Request, db: Session = Depends(get_db)):
credentials_exception = HTTPException( credentials_exception = HTTPException(
@ -311,7 +331,7 @@ def get_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Sess
} }
@app.get("/dashboard/cards", tags=["bff"]) @app.get("/dashboard/cards", tags=["bff"])
def get_dashboard_cards(db: Session = Depends(get_db)): def get_dashboard_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# 1. Общий доход - сумма всех Sale.cost # 1. Общий доход - сумма всех Sale.cost
total_revenue = db.exec(select(Sale)).all() total_revenue = db.exec(select(Sale)).all()
totalRevenue = sum(sale.cost for sale in total_revenue) totalRevenue = sum(sale.cost for sale in total_revenue)
@ -339,7 +359,7 @@ def get_dashboard_cards(db: Session = Depends(get_db)):
} }
@app.get("/dashboard/chart/total", tags=["bff"]) @app.get("/dashboard/chart/total", tags=["bff"])
def get_dashboard_chart_total(db: Session = Depends(get_db)): def get_dashboard_chart_total(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# Группируем продажи по дате (день) # Группируем продажи по дате (день)
result = db.exec( result = db.exec(
select( select(
@ -357,7 +377,7 @@ def get_dashboard_chart_total(db: Session = Depends(get_db)):
return JSONResponse(content=data) return JSONResponse(content=data)
@app.get("/dashboard/chart/agent", tags=["bff"]) @app.get("/dashboard/chart/agent", tags=["bff"])
def get_dashboard_chart_agent(db: Session = Depends(get_db)): def get_dashboard_chart_agent(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# Получаем всех агентов # Получаем всех агентов
agents = db.exec(select(TgAgent)).all() agents = db.exec(select(TgAgent)).all()
result = [] result = []
@ -388,6 +408,7 @@ def get_agents_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
date_end: str = Query(None), date_end: str = Query(None),
current_account: Account = Depends(get_current_account),
): ):
agents_query = select(TgAgent) agents_query = select(TgAgent)
if date_start: if date_start:
@ -427,6 +448,7 @@ def get_referrals_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
date_end: str = Query(None), date_end: str = Query(None),
current_account: Account = Depends(get_current_account),
): ):
refs_query = select(Ref) refs_query = select(Ref)
if date_start: if date_start:
@ -454,6 +476,7 @@ def get_sales_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
date_end: str = Query(None), date_end: str = Query(None),
current_account: Account = Depends(get_current_account),
): ):
sales_query = select(Sale) sales_query = select(Sale)
if date_start: if date_start:
@ -481,7 +504,7 @@ def get_sales_stat(
return JSONResponse(content=result) return JSONResponse(content=result)
@app.get("/billing/cards", tags=["bff"]) @app.get("/billing/cards", tags=["bff"])
def get_billing_cards(db: Session = Depends(get_db)): def get_billing_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# 1. cost - Общий заработок (сумма всех Sale.cost) # 1. cost - Общий заработок (сумма всех Sale.cost)
sales = db.exec(select(Sale)).all() sales = db.exec(select(Sale)).all()
cost = sum(sale.cost for sale in sales) cost = sum(sale.cost for sale in sales)
@ -505,6 +528,7 @@ def get_billing_payouts_transactions(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
date_end: str = Query(None), date_end: str = Query(None),
current_account: Account = Depends(get_current_account),
): ):
# Используем AgentTransaction вместо Transaction # Используем AgentTransaction вместо Transaction
# Явно выбираем обе модели для корректной распаковки # Явно выбираем обе модели для корректной распаковки
@ -531,7 +555,7 @@ def get_billing_payouts_transactions(
return result return result
@app.get("/billing/chart/stat", tags=["bff"]) @app.get("/billing/chart/stat", tags=["bff"])
def get_billing_chart_stat(db: Session = Depends(get_db)): def get_billing_chart_stat(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# Группируем агентские транзакции по дате (день) и статусу # Группируем агентские транзакции по дате (день) и статусу
result = db.exec( result = db.exec(
select( select(
@ -553,7 +577,7 @@ def get_billing_chart_stat(db: Session = Depends(get_db)):
return JSONResponse(content=data) return JSONResponse(content=data)
@app.get("/billing/chart/pie", tags=["bff"]) @app.get("/billing/chart/pie", tags=["bff"])
def get_billing_chart_pie(db: Session = Depends(get_db)): def get_billing_chart_pie(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
# Группируем агентские транзакции по статусу # Группируем агентские транзакции по статусу
result = db.exec( result = db.exec(
select( select(
@ -586,23 +610,7 @@ def get_account_by_login(db: Session, login: str) -> Optional[Account]:
statement = select(Account).where(Account.login == login) statement = select(Account).where(Account.login == login)
return db.exec(statement).first() return db.exec(statement).first()
def get_current_account(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
login: str = payload.get("sub")
if login is None:
raise credentials_exception
except InvalidTokenError:
raise credentials_exception
account = get_account_by_login(db, login)
if account is None:
raise credentials_exception
return account
@app.get("/account", tags=["bff"]) @app.get("/account", tags=["bff"])
def get_account(current_account: Account = Depends(get_current_account)): def get_account(current_account: Account = Depends(get_current_account)):
@ -719,3 +727,108 @@ def get_account_agent_transactions(
) )
return agent_transactions_response return agent_transactions_response
# Модель запроса для POST /account/auto-approve
class AutoApproveSettingsRequest(BaseModel):
auto_approve: bool
apply_to_current: Optional[bool] = False
@app.get("/account/auto-approve", tags=["bff"])
def get_auto_approve_settings(
current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db)
):
"""
Возвращает текущую настройку автоматического подтверждения для компании пользователя.
"""
company = db.exec(select(Company).where(Company.id == current_account.company_id)).first()
if not company:
raise HTTPException(status_code=404, detail="Компания не найдена")
return {"auto_approve_transactions": company.auto_approve_transactions}
@app.post("/account/auto-approve", tags=["bff"])
def update_auto_approve_settings(
req: AutoApproveSettingsRequest,
current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db)
):
"""
Обновляет настройку автоматического подтверждения для компании пользователя.
При необходимости переводит транзакции из 'waiting' в 'new'.
"""
company = db.exec(select(Company).where(Company.id == current_account.company_id)).first()
if not company:
raise HTTPException(status_code=404, detail="Компания не найдена")
company.auto_approve_transactions = req.auto_approve
company.update_dttm = datetime.utcnow()
db.add(company)
if req.apply_to_current and req.auto_approve: # Применяем только если авто-аппрув включается и запрошено применение к текущим
# Находим все агентские транзакции компании в статусе 'waiting'
agent_transactions_to_update = db.exec(
select(AgentTransaction)
.join(TgAgent)
.where(TgAgent.company_id == company.id)
.where(AgentTransaction.status == TransactionStatus.WAITING)
).all()
for agent_trans in agent_transactions_to_update:
agent_trans.status = TransactionStatus.NEW
agent_trans.update_dttm = datetime.utcnow()
db.add(agent_trans)
# Находим соответствующие партнерские транзакции и обновляем их статус
partner_transactions_to_update = db.exec(
select(PartnerTransaction)
.where(PartnerTransaction.agent_transaction_id == agent_trans.id) # Используем связь по ID
.where(PartnerTransaction.status == TransactionStatus.PROCESS) # Предполагаем, что связанные партнерские транзакции в статусе PROCESS
).all()
for partner_trans in partner_transactions_to_update:
partner_trans.status = TransactionStatus.NEW
partner_trans.update_dttm = datetime.utcnow()
db.add(partner_trans)
db.commit()
db.refresh(company)
return {"msg": "Настройка автоматического подтверждения обновлена", "auto_approve_transactions": company.auto_approve_transactions}
# Модель запроса для POST /account/approve-transactions
class ApproveTransactionsRequest(BaseModel):
transaction_ids: List[uuid.UUID]
@app.post("/account/approve-transactions", tags=["bff"])
def approve_agent_transactions(
req: ApproveTransactionsRequest,
current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db)
):
"""
Утверждение выбранных агентских транзакций для компании текущего пользователя.
Переводит транзакции из статуса 'waiting' в 'new'.
"""
company_id = current_account.company_id
approved_count = 0
if not req.transaction_ids:
return {"msg": "Нет транзакций для утверждения", "approved_count": 0}
# Find transactions belonging to the company and with specified IDs and statuses
transactions_to_approve = db.exec(
select(AgentTransaction)
.join(TgAgent)
.where(TgAgent.company_id == company_id)
.where(AgentTransaction.transaction_group.in_(req.transaction_ids))
.where(AgentTransaction.status == TransactionStatus.WAITING) # Утверждаем только транзакции в статусе 'waiting'
).all()
for agent_trans in transactions_to_approve:
agent_trans.status = TransactionStatus.NEW # Переводим в статус 'new'
agent_trans.update_dttm = datetime.utcnow()
db.add(agent_trans)
approved_count += 1
db.commit()
return {"msg": f"Переведено в статус NEW {approved_count} транзакций", "approved_count": approved_count}