Compare commits

..

No commits in common. "a6308582cb3bafbb60e65007f82289091ccda760" and "bf6a6a898713bd6e06d7024d1edad7e0cbfd9674" have entirely different histories.

8 changed files with 36 additions and 41 deletions

View File

@ -145,6 +145,7 @@ class CompanyProfileResponse(BaseModel):
name: str name: str
key: str key: str
commission: float commission: float
agent_commission: float
class AccountProfileResponse(BaseModel): class AccountProfileResponse(BaseModel):
firstName: Optional[str] = None firstName: Optional[str] = None

View File

@ -4,17 +4,16 @@ import json
# Конфигурация API # Конфигурация API
BASE_URL = "http://127.0.0.1:8001" BASE_URL = "http://127.0.0.1:8001"
API_KEY = "de058226-37d3-4d0e-a483-3c2a7fac3573" API_KEY = "672a1437-70e8-461f-9bff-20f5ce4a023d"
REF = "0d9aaa96-80e6-424c-84c9-ff70a6eb915e" REF = "9bd1a6bd-98e1-48f4-a120-3b3d016011c0"
# Данные для запроса на создание продажи # Данные для запроса на создание продажи
# Замените эти значения на актуальные для вашей продажи # Замените эти значения на актуальные для вашей продажи
sale_data = { sale_data = {
"cost": 100, # Стоимость продажи "cost": 100.50, # Стоимость продажи
"ref": REF, # Ваш реферальный код "ref": REF, # Ваш реферальный код
"sale_id": str(uuid.uuid4()), # Уникальный идентификатор продажи для вашей компании "sale_id": str(uuid.uuid4()), # Уникальный идентификатор продажи для вашей компании
"category": "vip", # название категории (например, 'basic', 'premium', 'vip') "category": 1 # id категории (например, 1 - basic)
"group_sale_id": str(uuid.uuid4()) # уникальный идентификатор группы продаж
} }
# Эндпоинты # Эндпоинты

View File

@ -87,7 +87,8 @@ def fill_db():
# 0. Company # 0. Company
company = Company( company = Company(
name="RE: Premium", name="RE: Premium",
commission=0.0, commission=10.0,
agent_commission=15.0,
key="re-premium-key", key="re-premium-key",
) )
session.add(company) session.add(company)
@ -197,9 +198,7 @@ def fill_db():
all_categories = session.query(SaleCategory).filter_by(company_id=company.id).all() all_categories = session.query(SaleCategory).filter_by(company_id=company.id).all()
for ref in refs: for ref in refs:
sale_count = random.randint(20, int(20 * 1.25)) # от 20 до 25 sale_count = random.randint(20, int(20 * 1.25)) # от 20 до 25
group_size = 5 for _ in range(sale_count):
group_sale_ids = [str(uuid4()) for _ in range((sale_count // group_size) + 1)]
for idx in range(sale_count):
cost = round(random.uniform(100, 1000), 2) cost = round(random.uniform(100, 1000), 2)
sale_category = random.choice(all_categories) sale_category = random.choice(all_categories)
crediting = round(cost * (sale_category.perc / 100.0), 2) crediting = round(cost * (sale_category.perc / 100.0), 2)
@ -209,13 +208,11 @@ def fill_db():
time_diff = end_dttm - start_dttm time_diff = end_dttm - start_dttm
random_seconds = random.uniform(0, time_diff.total_seconds()) random_seconds = random.uniform(0, time_diff.total_seconds())
sale_dttm = start_dttm + timedelta(seconds=random_seconds) sale_dttm = start_dttm + timedelta(seconds=random_seconds)
group_sale_id = group_sale_ids[idx // group_size]
sale = Sale( sale = Sale(
cost=cost, cost=cost,
crediting=crediting, crediting=crediting,
ref=ref.id, ref=ref.id,
sale_id=str(uuid4()), sale_id=str(uuid4()),
group_sale_id=group_sale_id,
company_id=company.id, company_id=company.id,
category=sale_category.id, category=sale_category.id,
sale_dttm=sale_dttm, sale_dttm=sale_dttm,

View File

@ -257,7 +257,6 @@ async def create_sale(
crediting=crediting_amount, crediting=crediting_amount,
ref=referral.id, ref=referral.id,
sale_id=req.sale_id, sale_id=req.sale_id,
group_sale_id=req.group_sale_id,
company_id=company.id, company_id=company.id,
category=sale_category.id, category=sale_category.id,
sale_dttm=datetime.utcnow() sale_dttm=datetime.utcnow()

View File

@ -20,8 +20,7 @@ class SaleCreateRequest(BaseModel):
promocode: Optional[str] = None promocode: Optional[str] = None
sale_id: str sale_id: str
cost: float cost: float
category: str # название категории продажи category: int # id категории продажи
group_sale_id: str # новое поле для группировки продаж
class SaleCreateResponse(BaseModel): class SaleCreateResponse(BaseModel):
msg: str msg: str

51
main.py
View File

@ -79,7 +79,7 @@ app = FastAPI()
@app.post("/token", response_model=Token, tags=[ "token"]) @app.post("/token", response_model=Token, tags=["bff", "token"])
def login_account_for_access_token( def login_account_for_access_token(
form_data: OAuth2PasswordRequestForm = Depends(), form_data: OAuth2PasswordRequestForm = Depends(),
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -103,7 +103,7 @@ def login_account_for_access_token(
return Token(access_token=access_token, token_type="bearer") return Token(access_token=access_token, token_type="bearer")
@app.get("/dashboard/cards", tags=[ "dashboard"], response_model=DashboardCardsResponse) @app.get("/dashboard/cards", tags=["bff", "dashboard"], response_model=DashboardCardsResponse)
def get_dashboard_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_dashboard_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает данные для карточек на главной панели (dashboard) пользователя, включая общий доход, выплаты, активных рефералов, ожидающие выплаты и общее количество продаж. Возвращает данные для карточек на главной панели (dashboard) пользователя, включая общий доход, выплаты, активных рефералов, ожидающие выплаты и общее количество продаж.
@ -134,7 +134,7 @@ def get_dashboard_cards(current_account: Account = Depends(get_current_account),
"totalSales": totalSales "totalSales": totalSales
} }
@app.get("/dashboard/chart/total", tags=[ "dashboard"], response_model=DashboardChartTotalResponse) @app.get("/dashboard/chart/total", tags=["bff", "dashboard"], response_model=DashboardChartTotalResponse)
def get_dashboard_chart_total(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_dashboard_chart_total(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает данные для графика "Общий доход и продажи по датам" на главной панели (dashboard). Возвращает данные для графика "Общий доход и продажи по датам" на главной панели (dashboard).
@ -155,7 +155,7 @@ def get_dashboard_chart_total(current_account: Account = Depends(get_current_acc
] ]
return DashboardChartTotalResponse(items=data) return DashboardChartTotalResponse(items=data)
@app.get("/dashboard/chart/agent", tags=[ "dashboard"], response_model=DashboardChartAgentResponse) @app.get("/dashboard/chart/agent", tags=["bff", "dashboard"], response_model=DashboardChartAgentResponse)
def get_dashboard_chart_agent(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_dashboard_chart_agent(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает данные для графика "Продажи по агентам" на главной панели (dashboard). Возвращает данные для графика "Продажи по агентам" на главной панели (dashboard).
@ -185,7 +185,7 @@ def get_dashboard_chart_agent(current_account: Account = Depends(get_current_acc
}) })
return DashboardChartAgentResponse(items=result) return DashboardChartAgentResponse(items=result)
@app.get("/stat/agents", tags=[ "stat"], response_model=StatAgentsResponse) @app.get("/stat/agents", tags=["bff", "stat"], response_model=StatAgentsResponse)
def get_agents_stat( def get_agents_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
@ -229,7 +229,7 @@ def get_agents_stat(
}) })
return StatAgentsResponse(items=result) return StatAgentsResponse(items=result)
@app.get("/stat/referrals", tags=[ "stat"], response_model=StatReferralsResponse) @app.get("/stat/referrals", tags=["bff", "stat"], response_model=StatReferralsResponse)
def get_referrals_stat( def get_referrals_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
@ -262,7 +262,7 @@ def get_referrals_stat(
}) })
return StatReferralsResponse(items=result) return StatReferralsResponse(items=result)
@app.get("/stat/sales", tags=[ "stat"], response_model=StatSalesResponse) @app.get("/stat/sales", tags=["bff", "stat"], response_model=StatSalesResponse)
def get_sales_stat( def get_sales_stat(
db: Session = Depends(get_db), db: Session = Depends(get_db),
date_start: str = Query(None), date_start: str = Query(None),
@ -298,7 +298,7 @@ def get_sales_stat(
}) })
return StatSalesResponse(items=result) return StatSalesResponse(items=result)
@app.get("/billing/cards", tags=[ "billing"], response_model=BillingCardsResponse) @app.get("/billing/cards", tags=["bff", "billing"], response_model=BillingCardsResponse)
def get_billing_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_billing_cards(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает ключевые показатели биллинга для компании, включая общий заработок, общие выплаты и доступные к выводу средства. Возвращает ключевые показатели биллинга для компании, включая общий заработок, общие выплаты и доступные к выводу средства.
@ -321,7 +321,7 @@ def get_billing_cards(current_account: Account = Depends(get_current_account), d
"pendingPayouts": pendingPayouts "pendingPayouts": pendingPayouts
} }
@app.get("/billing/payouts/transactions", tags=[ "billing"], response_model=BillingPayoutsTransactionsResponse) @app.get("/billing/payouts/transactions", tags=["bff", "billing"], response_model=BillingPayoutsTransactionsResponse)
def get_billing_payouts_transactions( 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),
@ -361,7 +361,7 @@ def get_billing_payouts_transactions(
}) })
return BillingPayoutsTransactionsResponse(items=result) return BillingPayoutsTransactionsResponse(items=result)
@app.get("/billing/chart/stat", tags=[ "billing"], response_model=BillingChartStatResponse) @app.get("/billing/chart/stat", tags=["bff", "billing"], response_model=BillingChartStatResponse)
def get_billing_chart_stat(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_billing_chart_stat(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает статистику выплат по датам и статусам для компании текущего пользователя. Возвращает статистику выплат по датам и статусам для компании текущего пользователя.
@ -386,7 +386,7 @@ def get_billing_chart_stat(current_account: Account = Depends(get_current_accoun
] ]
return BillingChartStatResponse(items=data) return BillingChartStatResponse(items=data)
@app.get("/billing/chart/pie", tags=[ "billing"], response_model=BillingChartPieResponse) @app.get("/billing/chart/pie", tags=["bff", "billing"], response_model=BillingChartPieResponse)
def get_billing_chart_pie(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_billing_chart_pie(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает круговую диаграмму статистики выплат по статусам для компании текущего пользователя. Возвращает круговую диаграмму статистики выплат по статусам для компании текущего пользователя.
@ -406,7 +406,7 @@ def get_billing_chart_pie(current_account: Account = Depends(get_current_account
@app.get("/account", tags=[ "account"], response_model=AccountResponse) @app.get("/account", tags=["bff", "account"], response_model=AccountResponse)
def get_account(current_account: Account = Depends(get_current_account)): def get_account(current_account: Account = Depends(get_current_account)):
""" """
Возвращает базовую информацию об аккаунте текущего пользователя (имя и фамилию). Возвращает базовую информацию об аккаунте текущего пользователя (имя и фамилию).
@ -416,7 +416,7 @@ def get_account(current_account: Account = Depends(get_current_account)):
"surname": current_account.surname "surname": current_account.surname
} }
@app.get("/account/profile", tags=[ "account"], response_model=AccountProfileResponse) @app.get("/account/profile", tags=["bff", "account"], response_model=AccountProfileResponse)
def get_account_profile(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)): def get_account_profile(current_account: Account = Depends(get_current_account), db: Session = Depends(get_db)):
""" """
Возвращает полную информацию о профиле аккаунта текущего пользователя, включая данные компании. Возвращает полную информацию о профиле аккаунта текущего пользователя, включая данные компании.
@ -434,10 +434,11 @@ def get_account_profile(current_account: Account = Depends(get_current_account),
"name": company.name, "name": company.name,
"key": company.key, "key": company.key,
"commission": company.commission, "commission": company.commission,
"agent_commission": company.agent_commission
} }
} }
@app.post("/account/profile", tags=[ "account"], response_model=AccountProfileUpdateResponse) @app.post("/account/profile", tags=["bff", "account"], response_model=AccountProfileUpdateResponse)
def update_account_profile( def update_account_profile(
req: AccountProfileUpdateRequest, req: AccountProfileUpdateRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -459,7 +460,7 @@ def update_account_profile(
db.refresh(current_account) db.refresh(current_account)
return {"msg": "Профиль обновлён успешно"} return {"msg": "Профиль обновлён успешно"}
@app.post("/account/password", tags=[ "account"], response_model=AccountPasswordChangeResponse) @app.post("/account/password", tags=["bff", "account"], response_model=AccountPasswordChangeResponse)
def change_account_password( def change_account_password(
req: AccountPasswordChangeRequest, req: AccountPasswordChangeRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -485,7 +486,7 @@ def change_account_password(
# --- Новый функционал для агентских транзакций партнера --- # --- Новый функционал для агентских транзакций партнера ---
@app.get("/account/agent-transaction", response_model=List[AgentTransactionResponse], tags=[ "account"]) @app.get("/account/agent-transaction", response_model=List[AgentTransactionResponse], tags=["bff", "account"])
def get_account_agent_transactions( def get_account_agent_transactions(
statuses: Optional[List[TransactionStatus]] = Query(None), statuses: Optional[List[TransactionStatus]] = Query(None),
date_start: str = Query(None), date_start: str = Query(None),
@ -542,7 +543,7 @@ def get_account_agent_transactions(
@app.get("/account/auto-approve", tags=[ "account"], response_model=AutoApproveSettingsGetResponse) @app.get("/account/auto-approve", tags=["bff", "account"], response_model=AutoApproveSettingsGetResponse)
def get_auto_approve_settings( def get_auto_approve_settings(
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -555,7 +556,7 @@ def get_auto_approve_settings(
raise HTTPException(status_code=404, detail="Компания не найдена") raise HTTPException(status_code=404, detail="Компания не найдена")
return {"auto_approve_transactions": company.auto_approve_transactions} return {"auto_approve_transactions": company.auto_approve_transactions}
@app.post("/account/auto-approve", tags=[ "account"], response_model=AutoApproveSettingsUpdateResponse) @app.post("/account/auto-approve", tags=["bff", "account"], response_model=AutoApproveSettingsUpdateResponse)
def update_auto_approve_settings( def update_auto_approve_settings(
req: AutoApproveSettingsRequest, req: AutoApproveSettingsRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -605,7 +606,7 @@ def update_auto_approve_settings(
@app.post("/account/approve-transactions", tags=[ "account"], response_model=ApproveTransactionsResult) @app.post("/account/approve-transactions", tags=["bff", "account"], response_model=ApproveTransactionsResult)
def approve_agent_transactions( def approve_agent_transactions(
req: ApproveTransactionsRequest, req: ApproveTransactionsRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -642,7 +643,7 @@ def approve_agent_transactions(
# --- Новый функционал для интеграционных токенов --- # --- Новый функционал для интеграционных токенов ---
@app.get("/account/integration-tokens", tags=[ "account"], response_model=List[IntegrationTokenResponse]) @app.get("/account/integration-tokens", tags=["bff", "account"], response_model=List[IntegrationTokenResponse])
def get_integration_tokens( def get_integration_tokens(
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -654,7 +655,7 @@ def get_integration_tokens(
return tokens # Позволяем FastAPI самостоятельно сериализовать объекты IntegrationToken в IntegrationTokenResponse return tokens # Позволяем FastAPI самостоятельно сериализовать объекты IntegrationToken в IntegrationTokenResponse
@app.post("/account/integration-tokens", tags=[ "account"], response_model=IntegrationTokenResponse) @app.post("/account/integration-tokens", tags=["bff", "account"], response_model=IntegrationTokenResponse)
def create_integration_token( def create_integration_token(
req: IntegrationTokenCreateRequest, req: IntegrationTokenCreateRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -687,7 +688,7 @@ def create_integration_token(
return response_token return response_token
@app.post("/account/integration-tokens/update-description", tags=[ "account"], response_model=Dict[str, str]) @app.post("/account/integration-tokens/update-description", tags=["bff", "account"], response_model=Dict[str, str])
def update_integration_token_description( def update_integration_token_description(
req: IntegrationTokenUpdateRequest, req: IntegrationTokenUpdateRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -710,7 +711,7 @@ def update_integration_token_description(
db.refresh(token) db.refresh(token)
return {"msg": "Описание токена обновлено успешно"} return {"msg": "Описание токена обновлено успешно"}
@app.delete("/account/integration-tokens/{token_id}", tags=[ "account"], response_model=Dict[str, str]) @app.delete("/account/integration-tokens/{token_id}", tags=["bff", "account"], response_model=Dict[str, str])
def delete_integration_token( def delete_integration_token(
token_id: int, token_id: int,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
@ -732,7 +733,7 @@ def delete_integration_token(
# --- Категории продаж --- # --- Категории продаж ---
@app.get("/category", tags=["category"], response_model=List[SaleCategoryResponse]) @app.get("/account/category", tags=["bff", "account"], response_model=List[SaleCategoryResponse])
def get_sale_categories( def get_sale_categories(
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -743,7 +744,7 @@ def get_sale_categories(
categories = db.exec(select(SaleCategory).where(SaleCategory.company_id == current_account.company_id)).all() categories = db.exec(select(SaleCategory).where(SaleCategory.company_id == current_account.company_id)).all()
return categories return categories
@app.post("/category", tags=["category"], response_model=SaleCategoryResponse) @app.post("/account/category", tags=["bff", "account"], response_model=SaleCategoryResponse)
def create_or_update_sale_category( def create_or_update_sale_category(
req: SaleCategoryRequest, req: SaleCategoryRequest,
current_account: Account = Depends(get_current_account), current_account: Account = Depends(get_current_account),

View File

@ -164,7 +164,6 @@ CREATE TABLE sale (
crediting FLOAT NOT NULL, crediting FLOAT NOT NULL,
ref INTEGER NOT NULL, ref INTEGER NOT NULL,
sale_id VARCHAR NOT NULL, sale_id VARCHAR NOT NULL,
group_sale_id VARCHAR NOT NULL,
company_id INTEGER NOT NULL, company_id INTEGER NOT NULL,
category INTEGER NOT NULL, category INTEGER NOT NULL,
sale_dttm DATETIME NOT NULL, sale_dttm DATETIME NOT NULL,

View File

@ -8,6 +8,7 @@ class Company(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True) id: Optional[int] = Field(default=None, primary_key=True)
name: str name: str
commission: float # процент комиссии, который взымается за пользование сервисом commission: float # процент комиссии, который взымается за пользование сервисом
agent_commission: float = Field(default=0.0) # процент от продаж, который начисляется агенту
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)
@ -68,7 +69,6 @@ class Sale(SQLModel, table=True):
crediting: float # сколько начислено за продажу crediting: float # сколько начислено за продажу
ref: int = Field(foreign_key="ref.id") ref: int = Field(foreign_key="ref.id")
sale_id: str sale_id: str
group_sale_id: str # новое поле для группировки продаж
company_id: int = Field(foreign_key="company.id") company_id: int = Field(foreign_key="company.id")
category: int = Field(foreign_key="salecategory.id") # новая ссылка на категорию category: int = Field(foreign_key="salecategory.id") # новая ссылка на категорию
sale_dttm: datetime = Field(default_factory=datetime.utcnow) sale_dttm: datetime = Field(default_factory=datetime.utcnow)