From 3973d6404d3b484e65629eae01aad6cc47ab6e3d Mon Sep 17 00:00:00 2001 From: Redsandyg Date: Fri, 13 Jun 2025 14:12:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9=20=D1=8D=D0=BD=D0=B4?= =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0=20=D0=BD=D0=B0=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D1=80=D0=B5=D0=B4=D1=81=D1=82?= =?UTF-8?q?=D0=B2=20=D0=B4=D0=BB=D1=8F=20Telegram-=D0=B0=D0=B3=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=B2=20integration=5Fapi.py.=20=D0=9E?= =?UTF-8?q?=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5?= =?UTF-8?q?=D0=B3=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=83=D1=89=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B8=D1=85=20=D1=8D=D0=BD?= =?UTF-8?q?=D0=B4=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=D0=BE=D0=B2,=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B8=D0=B2=20=D0=B8=D1=85=20=D1=81=20?= =?UTF-8?q?"partner-tg"=20=D0=BD=D0=B0=20"agent-tg".=20=D0=92=20integratio?= =?UTF-8?q?n=5Fmodels.py=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20WithdrawR?= =?UTF-8?q?equest=20=D0=B8=20WithdrawResponse=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=BE=D0=B2=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D1=81=D1=80=D0=B5=D0=B4=D1=81?= =?UTF-8?q?=D1=82=D0=B2.=20=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B7=D0=B0=D0=BA=D1=86=D0=B8=D0=B9=20=D0=B8=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BE=D0=BA=20=D0=B1=D0=B0=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D1=81=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- integration_api.py | 64 ++++++++++++++++++++++++++++++++++++++----- integration_models.py | 8 ++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/integration_api.py b/integration_api.py index 1aeda50..8f8cb64 100644 --- a/integration_api.py +++ b/integration_api.py @@ -6,7 +6,7 @@ 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 integration_models import Token, SaleCreateRequest, SaleCreateResponse, TransactionStatus, WithdrawRequest, WithdrawResponse from bff_models import RegisterResponse, TgAuthResponse from tg_models import RefAddRequest, RefResponse, RefAddResponse, RefStatResponse, RegisterRequest, StatResponse from helpers_bff import AUTH_DB_ENGINE, get_integration_db, create_integration_jwt_token, get_current_company_from_jwt, get_tg_agent_by_tg_id, get_current_tg_agent @@ -53,7 +53,7 @@ async def get_token_for_api_key( jwt_token = create_integration_jwt_token(integration_token_db.company_id) return {"access_token": jwt_token, "token_type": "bearer"} -@app.get("/ref", response_model=List[RefResponse], tags=["partner-tg"]) +@app.get("/ref", response_model=List[RefResponse], tags=["agent-tg"]) def get_refs(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): """ Возвращает список реферальных ссылок текущего Telegram-агента. @@ -61,7 +61,7 @@ def get_refs(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Sess refs = db.exec(select(Ref).where(Ref.tg_agent_id == current_tg_agent.id)).all() return [RefResponse(ref=r.ref, description=r.description or "") for r in refs] -@app.post("/ref/add", tags=["partner-tg"], response_model=RefAddResponse) +@app.post("/ref/add", tags=["agent-tg"], response_model=RefAddResponse) def add_ref(req: RefAddRequest, current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): """ Добавляет новую реферальную ссылку для текущего Telegram-агента. @@ -76,7 +76,7 @@ def add_ref(req: RefAddRequest, current_tg_agent: TgAgent = Depends(get_current_ db.refresh(new_ref) return {"ref": new_ref.ref} -@app.get("/ref/stat", tags=["partner-tg"], response_model=RefStatResponse) +@app.get("/ref/stat", tags=["agent-tg"], response_model=RefStatResponse) def get_ref_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): """ Возвращает статистику по реферальным ссылкам текущего Telegram-агента. @@ -96,7 +96,7 @@ def get_ref_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: }) return {"refData": result} -@app.get("/stat", tags=["partner-tg"], response_model=StatResponse) +@app.get("/stat", tags=["agent-tg"], response_model=StatResponse) def get_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): """ Возвращает общую статистику для текущего Telegram-агента. @@ -118,7 +118,7 @@ def get_stat(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Sess "availableWithdrawal": availableWithdrawal } -@app.post("/tg_auth", tags=["partner-tg"], response_model=TgAuthResponse) +@app.post("/tg_auth", tags=["agent-tg"], response_model=TgAuthResponse) def tg_auth(hash: str = Body(..., embed=True), db: Session = Depends(get_integration_db)): """ Авторизует Telegram-агента по хешу. @@ -128,6 +128,56 @@ def tg_auth(hash: str = Body(..., embed=True), db: Session = Depends(get_integra raise HTTPException(status_code=401, detail="Hash not found") return {"msg": "Auth success", "tg_id": tg_agent.tg_id} +@app.post("/withdraw", tags=["agent-tg"], response_model=WithdrawResponse) +async def withdraw_funds( + req: WithdrawRequest, + db: Session = Depends(get_integration_db) +): + """ + Запрос на вывод средств для Telegram-агента. + """ + tg_agent = db.exec(select(TgAgent).where(TgAgent.tg_id == req.tg_id)).first() + if not tg_agent: + raise HTTPException(status_code=404, detail="Telegram-агент не найден") + + company = db.exec(select(Company).where(Company.id == tg_agent.company_id)).first() + if not company: + raise HTTPException(status_code=404, detail="Компания не найдена для агента") + + if req.amount <= 0: + raise HTTPException(status_code=400, detail="Сумма для вывода должна быть положительной") + + agent_balance = db.exec(select(AgentBalance).where(AgentBalance.tg_agent_id == tg_agent.id)).first() + if not agent_balance or agent_balance.available_balance < req.amount: + raise HTTPException(status_code=400, detail="Недостаточно средств на балансе для вывода") + + # Определяем статус транзакции + transaction_status = TransactionStatus.WAITING + if company.auto_approve_transactions: + transaction_status = TransactionStatus.NEW + + # Создаем запись AgentTransaction + new_agent_transaction = AgentTransaction( + tg_agent_id=tg_agent.id, + amount=req.amount, + status=transaction_status.value, + transaction_group=uuid.uuid4() + ) + db.add(new_agent_transaction) + + + # Обновляем баланс агента + agent_balance.available_balance -= req.amount + if transaction_status == TransactionStatus.WAITING: # Если автоматически одобряется, переводим на замороженный баланс компании (т.е. компания должна выплатить) + agent_balance.frozen_balance += req.amount # Удерживаем средства, пока они не будут выведены + db.add(agent_balance) + + db.commit() + db.refresh(new_agent_transaction) + db.refresh(agent_balance) + + return {"msg": "Запрос на вывод средств успешно создан", "transaction_id": new_agent_transaction.transaction_group} + @app.post("/sale", tags=["integration"], response_model=SaleCreateResponse) async def create_sale( req: SaleCreateRequest, @@ -221,7 +271,7 @@ async def create_sale( "crediting": new_sale.crediting } -@app.post("/register", tags=["partner-tg"], response_model=RegisterResponse) +@app.post("/register", tags=["agent-tg"], response_model=RegisterResponse) def register(req: RegisterRequest, db: Session = Depends(get_integration_db)): """ Регистрирует нового Telegram-агента в системе. diff --git a/integration_models.py b/integration_models.py index ae20a9a..13100c8 100644 --- a/integration_models.py +++ b/integration_models.py @@ -25,6 +25,14 @@ class SaleCreateResponse(BaseModel): sale_id: str crediting: float +class WithdrawRequest(BaseModel): + tg_id: int + amount: float + +class WithdrawResponse(BaseModel): + msg: str + transaction_id: uuid.UUID + class TransactionStatus(str, Enum): NEW = "new" PROCESS = "process"