Добавлены новые модели для агентских и партнерских транзакций, а также балансов компаний и агентов. Обновлено заполнение базы данных с учетом новых таблиц и логики транзакций. Изменены функции для работы с транзакциями, включая фильтрацию по статусам и датам. Улучшены комментарии для ясности кода.
This commit is contained in:
parent
161e0b3ec4
commit
8c6fadb180
118
fill_db.py
118
fill_db.py
@ -1,7 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
from main import AUTH_DB_ENGINE, TgAgent, Ref, Sale, Transaction, Account, Company
|
from main import AUTH_DB_ENGINE, TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
@ -80,7 +80,10 @@ def fill_db():
|
|||||||
session.execute(text("DELETE FROM ref"))
|
session.execute(text("DELETE FROM ref"))
|
||||||
session.execute(text("DELETE FROM tgagent"))
|
session.execute(text("DELETE FROM tgagent"))
|
||||||
session.execute(text("DELETE FROM account"))
|
session.execute(text("DELETE FROM account"))
|
||||||
session.execute(text('DELETE FROM "transaction"'))
|
session.execute(text('DELETE FROM "agent_transactions"'))
|
||||||
|
session.execute(text('DELETE FROM "partner_transactions"'))
|
||||||
|
session.execute(text('DELETE FROM "company_balances"'))
|
||||||
|
session.execute(text('DELETE FROM "agent_balances"'))
|
||||||
session.execute(text("DELETE FROM company"))
|
session.execute(text("DELETE FROM company"))
|
||||||
session.commit()
|
session.commit()
|
||||||
# 0. Company
|
# 0. Company
|
||||||
@ -172,29 +175,102 @@ def fill_db():
|
|||||||
)
|
)
|
||||||
session.add(sale)
|
session.add(sale)
|
||||||
session.commit()
|
session.commit()
|
||||||
# 5. Transactions (только withdrawal на агента)
|
# 5. Заполнение новых таблиц
|
||||||
TRANSACTION_STATUSES = ['process', 'done', 'error', 'waiting']
|
# 5.1 CompanyBalance
|
||||||
for tg_agent in tg_agents:
|
company_balance = CompanyBalance(
|
||||||
withdrawal_count = random.randint(5, int(5 * 1.25)) # от 5 до 6
|
|
||||||
used_statuses = set()
|
|
||||||
for i in range(withdrawal_count):
|
|
||||||
dt = random.choice(date_list)
|
|
||||||
# Гарантируем, что каждый статус будет использован хотя бы раз
|
|
||||||
if len(used_statuses) < len(TRANSACTION_STATUSES):
|
|
||||||
status = TRANSACTION_STATUSES[len(used_statuses)]
|
|
||||||
used_statuses.add(status)
|
|
||||||
else:
|
|
||||||
status = random.choice(TRANSACTION_STATUSES)
|
|
||||||
transaction = Transaction(
|
|
||||||
transaction_id=str(uuid4()),
|
|
||||||
sum=round(random.uniform(200, 3000), 2),
|
|
||||||
tg_agent_id=tg_agent.id,
|
|
||||||
status=status,
|
|
||||||
company_id=company.id,
|
company_id=company.id,
|
||||||
|
available_balance=round(random.uniform(10000, 50000), 2),
|
||||||
|
pending_balance=round(random.uniform(1000, 10000), 2),
|
||||||
|
updated_dttm=datetime.utcnow()
|
||||||
|
)
|
||||||
|
session.add(company_balance)
|
||||||
|
session.commit()
|
||||||
|
session.refresh(company_balance)
|
||||||
|
|
||||||
|
# 5.2 AgentBalances
|
||||||
|
agent_balances = []
|
||||||
|
for tg_agent in tg_agents:
|
||||||
|
dt = random.choice(date_list)
|
||||||
|
agent_balance = AgentBalance(
|
||||||
|
tg_agent_id=tg_agent.id,
|
||||||
|
available_balance=round(random.uniform(100, 5000), 2),
|
||||||
|
frozen_balance=round(random.uniform(0, 1000), 2),
|
||||||
|
updated_dttm=dt
|
||||||
|
)
|
||||||
|
session.add(agent_balance)
|
||||||
|
agent_balances.append(agent_balance)
|
||||||
|
session.commit()
|
||||||
|
for balance in agent_balances:
|
||||||
|
session.refresh(balance)
|
||||||
|
|
||||||
|
# 5.3 AgentTransactions and PartnerTransactions
|
||||||
|
AGENT_TRANSACTION_STATUSES = ['waiting', 'process', 'done', 'reject', 'error']
|
||||||
|
PARTNER_TRANSACTION_TYPES = ['deposit', 'agent_payout', 'service_fee']
|
||||||
|
PARTNER_TRANSACTION_STATUSES = ['process', 'done', 'error']
|
||||||
|
|
||||||
|
for tg_agent in tg_agents:
|
||||||
|
# Генерируем несколько групп транзакций для каждого агента
|
||||||
|
for _ in range(random.randint(3, 6)): # От 3 до 6 групп на агента
|
||||||
|
transaction_group_id = uuid4()
|
||||||
|
dt = random.choice(date_list)
|
||||||
|
agent_trans_amount = round(random.uniform(500, 3000), 2)
|
||||||
|
agent_trans_status = random.choice(AGENT_TRANSACTION_STATUSES)
|
||||||
|
|
||||||
|
# Создаем AgentTransaction
|
||||||
|
agent_transaction = AgentTransaction(
|
||||||
|
tg_agent_id=tg_agent.id,
|
||||||
|
amount=agent_trans_amount,
|
||||||
|
status=agent_trans_status,
|
||||||
|
transaction_group=transaction_group_id,
|
||||||
create_dttm=dt,
|
create_dttm=dt,
|
||||||
update_dttm=dt
|
update_dttm=dt
|
||||||
)
|
)
|
||||||
session.add(transaction)
|
session.add(agent_transaction)
|
||||||
|
session.commit()
|
||||||
|
session.refresh(agent_transaction)
|
||||||
|
|
||||||
|
# Создаем соответствующие PartnerTransactions
|
||||||
|
# Для каждой AgentTransaction создаем PartnerTransaction типа 'agent_payout'
|
||||||
|
if agent_trans_status != 'waiting': # Создаем партнерскую транзакцию только если агентская не в статусе 'waiting'
|
||||||
|
# Добавляем PartnerTransaction для выплаты агенту
|
||||||
|
partner_payout = PartnerTransaction(
|
||||||
|
company_id=company.id,
|
||||||
|
type='agent_payout',
|
||||||
|
amount=agent_trans_amount,
|
||||||
|
status=random.choice([s for s in PARTNER_TRANSACTION_STATUSES if s != 'process']) if agent_trans_status in ['done', 'error', 'reject'] else 'process', # Статус зависит от статуса агентской
|
||||||
|
transaction_group=transaction_group_id,
|
||||||
|
agent_transaction_id=agent_transaction.id,
|
||||||
|
create_dttm=dt,
|
||||||
|
update_dttm=dt
|
||||||
|
)
|
||||||
|
session.add(partner_payout)
|
||||||
|
|
||||||
|
|
||||||
|
# Добавляем другие типы PartnerTransactions для разнообразия
|
||||||
|
if random.random() < 0.5: # 50% шанс добавить депозит
|
||||||
|
partner_deposit = PartnerTransaction(
|
||||||
|
company_id=company.id,
|
||||||
|
type='deposit',
|
||||||
|
amount=round(random.uniform(1000, 10000), 2),
|
||||||
|
status=random.choice(PARTNER_TRANSACTION_STATUSES),
|
||||||
|
transaction_group=uuid4(), # Новая группа для независимых транзакций
|
||||||
|
create_dttm=dt,
|
||||||
|
update_dttm=dt
|
||||||
|
)
|
||||||
|
session.add(partner_deposit)
|
||||||
|
|
||||||
|
if random.random() < 0.3: # 30% шанс добавить комиссию
|
||||||
|
partner_fee = PartnerTransaction(
|
||||||
|
company_id=company.id,
|
||||||
|
type='service_fee',
|
||||||
|
amount=round(random.uniform(50, 500), 2),
|
||||||
|
status=random.choice(PARTNER_TRANSACTION_STATUSES),
|
||||||
|
transaction_group=uuid4(), # Новая группа
|
||||||
|
create_dttm=dt,
|
||||||
|
update_dttm=dt
|
||||||
|
)
|
||||||
|
session.add(partner_fee)
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
print("База успешно заполнена!")
|
print("База успешно заполнена!")
|
||||||
|
|
||||||
|
|||||||
208
main.py
208
main.py
@ -1,3 +1,4 @@
|
|||||||
|
import uuid
|
||||||
from fastapi import FastAPI, Depends, HTTPException, status, Query, Body, Request
|
from fastapi import FastAPI, Depends, HTTPException, status, Query, Body, Request
|
||||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
from sqlmodel import SQLModel, Field, create_engine, Session, select
|
from sqlmodel import SQLModel, Field, create_engine, Session, select
|
||||||
@ -12,6 +13,7 @@ from hashlib import sha256
|
|||||||
import jwt
|
import jwt
|
||||||
from jwt.exceptions import InvalidTokenError
|
from jwt.exceptions import InvalidTokenError
|
||||||
from pydantic import BaseModel, EmailStr
|
from pydantic import BaseModel, EmailStr
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
# Конфигурация
|
# Конфигурация
|
||||||
AUTH_DATABASE_ADDRESS = "sqlite:///partner.db"
|
AUTH_DATABASE_ADDRESS = "sqlite:///partner.db"
|
||||||
@ -55,20 +57,48 @@ class Sale(SQLModel, table=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)
|
||||||
|
|
||||||
class Transaction(SQLModel, table=True):
|
class AgentTransaction(SQLModel, table=True):
|
||||||
|
__tablename__ = "agent_transactions" # Указываем имя таблицы явно
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
transaction_id: str = Field(default_factory=lambda: str(uuid4()), index=True, unique=True)
|
tg_agent_id: int = Field(foreign_key="tgagent.id") # ID агента, связь с TgAgent
|
||||||
sum: float
|
amount: float # Используем float для DECIMAL(15,2)
|
||||||
tg_agent_id: int = Field(foreign_key="tgagent.id")
|
status: str # 'waiting', 'process', 'done', 'reject', 'error'
|
||||||
status: str # 'process' || 'done' || 'error' || 'waiting'
|
transaction_group: uuid.UUID = Field(default_factory=uuid.uuid4) # UUID для группировки
|
||||||
company_id: int = Field(foreign_key="company.id")
|
|
||||||
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)
|
||||||
|
|
||||||
|
class PartnerTransaction(SQLModel, table=True):
|
||||||
|
__tablename__ = "partner_transactions" # Указываем имя таблицы явно
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
company_id: int = Field(foreign_key="company.id") # ID партнера, связь с Company
|
||||||
|
type: str # 'deposit', 'agent_payout', 'service_fee'
|
||||||
|
amount: float # Используем float для DECIMAL(15,2)
|
||||||
|
status: str # 'process', 'done', 'error'
|
||||||
|
transaction_group: uuid.UUID # UUID для группировки, может быть связан с agent_transactions
|
||||||
|
agent_transaction_id: Optional[int] = Field(default=None, foreign_key="agent_transactions.id") # Связь с агентской транзакцией
|
||||||
|
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
|
class CompanyBalance(SQLModel, table=True):
|
||||||
|
__tablename__ = "company_balances" # Указываем имя таблицы явно
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
company_id: int = Field(foreign_key="company.id", unique=True) # ID компании, уникальный баланс на компанию
|
||||||
|
available_balance: float = Field(default=0.0) # Используем float для DECIMAL(15,2)
|
||||||
|
pending_balance: float = Field(default=0.0) # Используем float для DECIMAL(15,2)
|
||||||
|
updated_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
|
class AgentBalance(SQLModel, table=True):
|
||||||
|
__tablename__ = "agent_balances" # Указываем имя таблицы явно
|
||||||
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
|
tg_agent_id: int = Field(foreign_key="tgagent.id", unique=True) # ID агента, уникальный баланс на агента
|
||||||
|
available_balance: float = Field(default=0.0) # Используем float для DECIMAL(15,2)
|
||||||
|
frozen_balance: float = Field(default=0.0) # Используем float для DECIMAL(15,2)
|
||||||
|
updated_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||||
|
|
||||||
class Account(SQLModel, table=True):
|
class Account(SQLModel, table=True):
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
login: str = Field(index=True, unique=True)
|
login: str = Field(index=True, unique=True)
|
||||||
password_hash: str # теперь хранится hash пароля
|
password_hash: str
|
||||||
firstName: Optional[str] = None
|
firstName: Optional[str] = None
|
||||||
surname: Optional[str] = None
|
surname: Optional[str] = None
|
||||||
phone: Optional[str] = None
|
phone: Optional[str] = None
|
||||||
@ -87,6 +117,25 @@ class AccountPasswordChangeRequest(BaseModel):
|
|||||||
currentPassword: str
|
currentPassword: str
|
||||||
newPassword: str
|
newPassword: str
|
||||||
|
|
||||||
|
|
||||||
|
class TransactionStatus(str, Enum): # Определяем Enum для статусов
|
||||||
|
WAITING = 'waiting'
|
||||||
|
PROCESS = 'process'
|
||||||
|
DONE = 'done'
|
||||||
|
REJECT = 'reject'
|
||||||
|
ERROR = 'error'
|
||||||
|
|
||||||
|
|
||||||
|
# Новая модель ответа для агентских транзакций с именем агента
|
||||||
|
class AgentTransactionResponse(BaseModel):
|
||||||
|
amount: float
|
||||||
|
status: TransactionStatus # Используем Enum
|
||||||
|
transaction_group: uuid.UUID
|
||||||
|
create_dttm: datetime
|
||||||
|
update_dttm: datetime
|
||||||
|
agent_name: Optional[str] = None # Поле для имени агента
|
||||||
|
|
||||||
|
|
||||||
# Создание движка базы данных
|
# Создание движка базы данных
|
||||||
AUTH_DB_ENGINE = create_engine(AUTH_DATABASE_ADDRESS, echo=True)
|
AUTH_DB_ENGINE = create_engine(AUTH_DATABASE_ADDRESS, echo=True)
|
||||||
SQLModel.metadata.create_all(AUTH_DB_ENGINE)
|
SQLModel.metadata.create_all(AUTH_DB_ENGINE)
|
||||||
@ -188,12 +237,13 @@ def create_access_token(data: dict, expires_delta: timedelta = None):
|
|||||||
|
|
||||||
@app.post("/token", response_model=Token, tags=["bff"])
|
@app.post("/token", response_model=Token, tags=["bff"])
|
||||||
def login_account_for_access_token(
|
def login_account_for_access_token(
|
||||||
login: str = Body(...),
|
# login: str = Body(...),
|
||||||
password: str = Body(...),
|
# password: str = Body(...),
|
||||||
|
form_data: OAuth2PasswordRequestForm = Depends(),
|
||||||
db: Session = Depends(get_db)
|
db: Session = Depends(get_db)
|
||||||
):
|
):
|
||||||
account = get_account_by_login(db, login)
|
account = get_account_by_login(db, form_data.username)
|
||||||
if not account or not verify_password(password, account.password_hash):
|
if not account or not verify_password(form_data.password, account.password_hash):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail="Incorrect login or password",
|
detail="Incorrect login or password",
|
||||||
@ -251,12 +301,9 @@ def get_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Sess
|
|||||||
total_sales = db.exec(select(Sale).where(Sale.ref.in_(ref_ids))).all()
|
total_sales = db.exec(select(Sale).where(Sale.ref.in_(ref_ids))).all()
|
||||||
totalSales = len(total_sales)
|
totalSales = len(total_sales)
|
||||||
totalIncome = sum(sale.crediting for sale in total_sales)
|
totalIncome = sum(sale.crediting for sale in total_sales)
|
||||||
withdrawals = db.exec(
|
# Заменено получение доступного остатка из AgentBalance
|
||||||
select(Transaction).where(
|
agent_balance = db.exec(select(AgentBalance).where(AgentBalance.tg_agent_id == current_tg_agent.id)).first()
|
||||||
Transaction.tg_agent_id == current_tg_agent.id
|
availableWithdrawal = agent_balance.available_balance if agent_balance else 0.0
|
||||||
)
|
|
||||||
).all()
|
|
||||||
availableWithdrawal = totalIncome - sum(t.sum for t in withdrawals)
|
|
||||||
return {
|
return {
|
||||||
"totalSales": totalSales,
|
"totalSales": totalSales,
|
||||||
"totalIncome": totalIncome,
|
"totalIncome": totalIncome,
|
||||||
@ -276,10 +323,9 @@ def get_dashboard_cards(db: Session = Depends(get_db)):
|
|||||||
unique_agents = db.exec(select(TgAgent.tg_id)).all()
|
unique_agents = db.exec(select(TgAgent.tg_id)).all()
|
||||||
activeReferrals = len(set(unique_agents))
|
activeReferrals = len(set(unique_agents))
|
||||||
|
|
||||||
# 4. Ожидающие выплаты - разница между суммой всех Sale.crediting и суммой всех Transaction.sum
|
# 4. Ожидающие выплаты - сумма AgentTransaction со статусом 'waiting'
|
||||||
all_transactions = db.exec(select(Transaction)).all()
|
pending_agent_transactions = db.exec(select(AgentTransaction).where(AgentTransaction.status == 'waiting')).all()
|
||||||
totalTransactions = sum(t.sum for t in all_transactions)
|
pendingPayouts = sum(t.amount for t in pending_agent_transactions)
|
||||||
pendingPayouts = totalPayouts - totalTransactions
|
|
||||||
|
|
||||||
# 5. Количество продаж
|
# 5. Количество продаж
|
||||||
totalSales = len(total_revenue)
|
totalSales = len(total_revenue)
|
||||||
@ -436,15 +482,18 @@ def get_sales_stat(
|
|||||||
|
|
||||||
@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(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)
|
||||||
# 2. crediting - сумма всех Sale.crediting
|
|
||||||
crediting = sum(sale.crediting for sale in sales)
|
# 2. crediting - Общие выплаты (сумма PartnerTransaction типа 'agent_payout' со статусом 'done')
|
||||||
# 3. pendingPayouts - разница между crediting и суммой всех Transaction.sum
|
completed_payouts = db.exec(select(PartnerTransaction).where(PartnerTransaction.type == 'agent_payout').where(PartnerTransaction.status == 'done')).all()
|
||||||
transactions = db.exec(select(Transaction)).all()
|
crediting = sum(t.amount for t in completed_payouts)
|
||||||
total_transactions = sum(t.sum for t in transactions)
|
|
||||||
pendingPayouts = crediting - total_transactions
|
# 3. pendingPayouts - Доступно к выводу всеми партнерами (сумма всех доступных балансов агентов)
|
||||||
|
agent_balances = db.exec(select(AgentBalance)).all()
|
||||||
|
pendingPayouts = sum(balance.available_balance for balance in agent_balances)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"cost": cost,
|
"cost": cost,
|
||||||
"crediting": crediting,
|
"crediting": crediting,
|
||||||
@ -457,39 +506,44 @@ def get_billing_payouts_transactions(
|
|||||||
date_start: str = Query(None),
|
date_start: str = Query(None),
|
||||||
date_end: str = Query(None),
|
date_end: str = Query(None),
|
||||||
):
|
):
|
||||||
query = select(Transaction)
|
# Используем AgentTransaction вместо Transaction
|
||||||
|
# Явно выбираем обе модели для корректной распаковки
|
||||||
|
query = select(AgentTransaction, TgAgent).join(TgAgent)
|
||||||
if date_start:
|
if date_start:
|
||||||
query = query.where(Transaction.create_dttm >= date_start)
|
query = query.where(AgentTransaction.create_dttm >= date_start)
|
||||||
if date_end:
|
if date_end:
|
||||||
query = query.where(Transaction.create_dttm <= date_end)
|
query = query.where(AgentTransaction.create_dttm <= date_end)
|
||||||
transactions = db.exec(query).all()
|
# Заказываем по дате создания
|
||||||
|
query = query.order_by(AgentTransaction.create_dttm.desc())
|
||||||
|
|
||||||
|
# Выполняем запрос и формируем результат
|
||||||
|
results = db.exec(query).all()
|
||||||
result = []
|
result = []
|
||||||
for t in transactions:
|
for agent_trans, agent in results:
|
||||||
agent = db.exec(select(TgAgent).where(TgAgent.id == t.tg_agent_id)).first()
|
|
||||||
result.append({
|
result.append({
|
||||||
"id": t.transaction_id,
|
"id": agent_trans.transaction_group, # Используем transaction_group как ID транзакции группы
|
||||||
"sum": t.sum,
|
"amount": agent_trans.amount,
|
||||||
"agent": agent.name if agent else None,
|
"agent": agent.name if agent else None, # Имя агента из join
|
||||||
"status": t.status,
|
"status": agent_trans.status,
|
||||||
"create_dttm": t.create_dttm,
|
"create_dttm": agent_trans.create_dttm,
|
||||||
"update_dttm": t.update_dttm,
|
"update_dttm": agent_trans.update_dttm,
|
||||||
})
|
})
|
||||||
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(db: Session = Depends(get_db)):
|
||||||
# Группируем транзакции по дате (день) и статусу
|
# Группируем агентские транзакции по дате (день) и статусу
|
||||||
result = db.exec(
|
result = db.exec(
|
||||||
select(
|
select(
|
||||||
func.strftime('%Y-%m-%d', Transaction.create_dttm).label('date'),
|
func.strftime('%Y-%m-%d', AgentTransaction.create_dttm).label('date'),
|
||||||
Transaction.status.label('status'),
|
AgentTransaction.status.label('status'),
|
||||||
func.count(Transaction.id).label('count')
|
func.count(AgentTransaction.id).label('count')
|
||||||
).group_by(
|
).group_by(
|
||||||
func.strftime('%Y-%m-%d', Transaction.create_dttm),
|
func.strftime('%Y-%m-%d', AgentTransaction.create_dttm),
|
||||||
Transaction.status
|
AgentTransaction.status
|
||||||
).order_by(
|
).order_by(
|
||||||
func.strftime('%Y-%m-%d', Transaction.create_dttm),
|
func.strftime('%Y-%m-%d', AgentTransaction.create_dttm),
|
||||||
Transaction.status
|
AgentTransaction.status
|
||||||
)
|
)
|
||||||
).all()
|
).all()
|
||||||
data = [
|
data = [
|
||||||
@ -500,11 +554,12 @@ def get_billing_chart_stat(db: Session = Depends(get_db)):
|
|||||||
|
|
||||||
@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(db: Session = Depends(get_db)):
|
||||||
|
# Группируем агентские транзакции по статусу
|
||||||
result = db.exec(
|
result = db.exec(
|
||||||
select(
|
select(
|
||||||
Transaction.status.label('status'),
|
AgentTransaction.status.label('status'),
|
||||||
func.count(Transaction.id).label('count')
|
func.count(AgentTransaction.id).label('count')
|
||||||
).group_by(Transaction.status)
|
).group_by(AgentTransaction.status)
|
||||||
).all()
|
).all()
|
||||||
data = [
|
data = [
|
||||||
{"status": row.status, "count": row.count}
|
{"status": row.status, "count": row.count}
|
||||||
@ -613,3 +668,54 @@ def change_account_password(
|
|||||||
db.commit()
|
db.commit()
|
||||||
db.refresh(current_account)
|
db.refresh(current_account)
|
||||||
return {"msg": "Пароль успешно изменён"}
|
return {"msg": "Пароль успешно изменён"}
|
||||||
|
|
||||||
|
# --- Новый функционал для агентских транзакций партнера ---
|
||||||
|
|
||||||
|
@app.get("/account/agent-transaction", response_model=List[AgentTransactionResponse], tags=["bff"])
|
||||||
|
def get_account_agent_transactions(
|
||||||
|
statuses: Optional[List[TransactionStatus]] = Query(None), # Изменено на List[TransactionStatus]
|
||||||
|
date_start: str = Query(None), # Добавлен параметр date_start
|
||||||
|
date_end: str = Query(None), # Добавлен параметр date_end
|
||||||
|
current_account: Account = Depends(get_current_account),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Возвращает список агентских транзакций для компании текущего пользователя,
|
||||||
|
с возможностью фильтрации по статусу и дате создания.
|
||||||
|
"""
|
||||||
|
# Получаем ID компании текущего аккаунта
|
||||||
|
company_id = current_account.company_id
|
||||||
|
|
||||||
|
# Строим базовый запрос: выбрать AgentTransaction и TgAgent, связанные с агентами этой компании
|
||||||
|
query = select(AgentTransaction, TgAgent).join(TgAgent).where(TgAgent.company_id == company_id)
|
||||||
|
|
||||||
|
# Если переданы статусы, добавляем фильтрацию по статусам
|
||||||
|
if statuses:
|
||||||
|
query = query.where(AgentTransaction.status.in_(statuses))
|
||||||
|
|
||||||
|
# Если передана дата начала, добавляем фильтрацию по дате создания >= date_start
|
||||||
|
if date_start:
|
||||||
|
query = query.where(AgentTransaction.create_dttm >= date_start)
|
||||||
|
|
||||||
|
# Если передана дата окончания, добавляем фильтрацию по дате создания <= date_end
|
||||||
|
if date_end:
|
||||||
|
query = query.where(AgentTransaction.create_dttm <= date_end)
|
||||||
|
|
||||||
|
# Выполняем запрос
|
||||||
|
results = db.exec(query).all()
|
||||||
|
|
||||||
|
# Формируем список ответов в формате AgentTransactionResponse
|
||||||
|
agent_transactions_response = []
|
||||||
|
for agent_trans, agent in results:
|
||||||
|
agent_transactions_response.append(
|
||||||
|
AgentTransactionResponse(
|
||||||
|
amount=agent_trans.amount,
|
||||||
|
status=agent_trans.status,
|
||||||
|
transaction_group=agent_trans.transaction_group,
|
||||||
|
create_dttm=agent_trans.create_dttm,
|
||||||
|
update_dttm=agent_trans.update_dttm,
|
||||||
|
agent_name=agent.name # Используем имя агента
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return agent_transactions_response
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user