From d113ae4adbe410b612a183f632c07a61bc32bf2b Mon Sep 17 00:00:00 2001 From: Redsandyg Date: Sun, 15 Jun 2025 17:03:41 +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=D0=BE=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=20promocode=20=D0=B2=20=D0=BC=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=20StatReferralsItem=20=D0=B8=20=D0=BC=D0=BE=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=20Ref.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B2=20fill=5Fdb.py=20=D0=B4=D0=BB=D1=8F=20=D0=B3?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D1=83=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D1=85=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=BC=D0=BE=D0=BA=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B5=D1=80=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=81=D1=81=D1=8B=D0=BB=D0=BE=D0=BA.=20=D0=9E=D0=B1?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=8D=D0=BD=D0=B4?= =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D0=BD=D1=82=D1=8B=20=D0=B2=20integration=5Fa?= =?UTF-8?q?pi.py=20=D0=B4=D0=BB=D1=8F=20=D0=B2=D0=BE=D0=B7=D0=B2=D1=80?= =?UTF-8?q?=D0=B0=D1=82=D0=B0=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=D0=BE=D0=B2=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=B5=20?= =?UTF-8?q?=D1=81=20=D1=80=D0=B5=D1=84=D0=B5=D1=80=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=BC=D0=B8=20=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8.=20=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=80=D0=B5=D0=B2=D1=88=D0=B8=D0=B5=20=D1=84?= =?UTF-8?q?=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D1=8B=20=D1=81=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=D0=BC=D0=B8=20=D0=B8=D0=B7=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20SQL-=D1=81=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D1=8B?= =?UTF-8?q?=20=D0=B8=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D1=83=D1=87=D0=B5=D1=82=D0=B0=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D1=85=20=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bff_models.py | 1 + fill_db.py | 36 ++++++++---------------------------- generate_sql.py | 1 - integration_api.py | 45 +++++++++++---------------------------------- main.py | 1 + sql_create.sql | 16 +--------------- sql_models.py | 15 ++------------- tg_models.py | 13 ++++--------- 8 files changed, 28 insertions(+), 100 deletions(-) diff --git a/bff_models.py b/bff_models.py index 54d26e0..d70e983 100644 --- a/bff_models.py +++ b/bff_models.py @@ -89,6 +89,7 @@ class StatReferralsItem(BaseModel): ref: str agent: Optional[str] = None description: str + promocode: str salesSum: float salesCount: int diff --git a/fill_db.py b/fill_db.py index 8d826dd..e43c3a3 100644 --- a/fill_db.py +++ b/fill_db.py @@ -1,7 +1,7 @@ import random from uuid import uuid4 from sqlmodel import Session -from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken, PromoCode +from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken from sqlalchemy import text from datetime import datetime, timedelta from hashlib import sha256 @@ -72,7 +72,7 @@ def fill_db(): date_list = get_date_list(7) # 8 дней: от недели назад до сегодня with Session(AUTH_DB_ENGINE) as session: # Очистка таблиц - session.execute(text("DELETE FROM promocode")) + # session.execute(text("DELETE FROM promocode")) session.execute(text("DELETE FROM sale")) session.execute(text("DELETE FROM ref")) session.execute(text("DELETE FROM tgagent")) @@ -154,45 +154,25 @@ def fill_db(): # Отладка: количество агентов agent_count = session.execute(text("SELECT COUNT(*) FROM tgagent")).scalar() print(f'Агентов в базе: {agent_count}') - # Генерация промокодов для каждого агента с try/except - alphabet = string.ascii_letters + string.digits + "!@#$%^&*" - try: - for tg_agent in tg_agents: - promocode_count = random.randint(2, 4) - for _ in range(promocode_count): - promocode = ''.join(random.choices(alphabet, k=8)) - # Проверяем уникальность - while session.execute(text("SELECT 1 FROM promocode WHERE promocode = :code"), {"code": promocode}).first(): - promocode = ''.join(random.choices(alphabet, k=8)) - promo = PromoCode( - promocode=promocode, - perc=10.0, - agent_id=tg_agent.id, - description=random.choice(DESCRIPTIONS), - create_dttm=datetime.utcnow(), - update_dttm=datetime.utcnow() - ) - session.add(promo) - session.commit() - except Exception as e: - print(f'Ошибка при добавлении промокодов: {e}') - session.rollback() - # Отладка: количество промокодов - count = session.execute(text("SELECT COUNT(*) FROM promocode")).scalar() - print(f'Промокодов в базе: {count}') # 3. Refs (минимум 22 на агента) refs = [] desc_count = len(ALL_DESCRIPTIONS) + alphabet = string.ascii_letters + string.digits + "!@#$%^&*" for tg_agent in tg_agents: ref_count = random.randint(22, int(22 * 1.25)) # от 22 до 27 for j in range(ref_count): ref_val = str(uuid4()) desc_val = ALL_DESCRIPTIONS[(j % desc_count)] dt = random.choice(date_list) + promocode = ''.join(random.choices(alphabet, k=8)) + # Проверяем уникальность промокода среди уже созданных рефов + while any(r.promocode == promocode for r in refs): + promocode = ''.join(random.choices(alphabet, k=8)) ref = Ref( tg_agent_id=tg_agent.id, ref=ref_val, description=desc_val, + promocode=promocode, create_dttm=dt, update_dttm=dt ) diff --git a/generate_sql.py b/generate_sql.py index 63914cb..87c8123 100644 --- a/generate_sql.py +++ b/generate_sql.py @@ -1,5 +1,4 @@ from sqlmodel import SQLModel -from sql_models import Company, TgAgent, Ref, Sale, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, Account, IntegrationToken, PromoCode from helpers_bff import AUTH_DB_ENGINE from sqlalchemy.schema import CreateTable import os diff --git a/integration_api.py b/integration_api.py index 02b1f7b..110ba4b 100644 --- a/integration_api.py +++ b/integration_api.py @@ -7,10 +7,10 @@ import uuid from random import choices import string -from sql_models import Company, IntegrationToken, Ref, Sale, AgentTransaction, PartnerTransaction, AgentBalance, TgAgent, CompanyBalance, PromoCode +from sql_models import Company, IntegrationToken, Ref, Sale, AgentTransaction, PartnerTransaction, AgentBalance, TgAgent, CompanyBalance 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, PromoCodeAddRequest, PromoCodeResponse +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 app = FastAPI() @@ -61,22 +61,28 @@ def get_refs(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Sess Возвращает список реферальных ссылок текущего Telegram-агента. """ 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] + return [RefResponse(ref=r.ref, description=r.description or "", promocode=r.promocode) for r in refs] @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-агента. """ + # Генерация промокода (логика как была для промокодов) + alphabet = string.ascii_letters + string.digits + "!@#$%^&*" + promocode = ''.join(choices(alphabet, k=8)) + while db.exec(select(Ref).where(Ref.promocode == promocode)).first(): + promocode = ''.join(choices(alphabet, k=8)) new_ref = Ref( tg_agent_id=current_tg_agent.id, ref=str(uuid.uuid4()), - description=req.description + description=req.description, + promocode=promocode ) db.add(new_ref) db.commit() db.refresh(new_ref) - return {"ref": new_ref.ref} + return {"ref": new_ref.ref, "promocode": new_ref.promocode, "description": new_ref.description} @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)): @@ -306,32 +312,3 @@ def register(req: RegisterRequest, db: Session = Depends(get_integration_db)): db.commit() db.refresh(new_tg_agent) return {"msg": "TgAgent registered successfully"} - -@app.post("/promocode/add", tags=["agent-tg"], response_model=PromoCodeResponse) -def add_promocode(req: PromoCodeAddRequest, current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): - """ - Создает новый промокод для текущего Telegram-агента. - """ - description = req.description - alphabet = string.ascii_letters + string.digits + "!@#$%^&*" - promocode = ''.join(choices(alphabet, k=8)) - while db.exec(select(PromoCode).where(PromoCode.promocode == promocode)).first(): - promocode = ''.join(choices(alphabet, k=8)) - new_code = PromoCode( - promocode=promocode, - perc=10.0, - agent_id=current_tg_agent.id, - description=description - ) - db.add(new_code) - db.commit() - db.refresh(new_code) - return PromoCodeResponse(promocode=new_code.promocode, perc=new_code.perc, description=new_code.description) - -@app.get("/promocode", tags=["agent-tg"], response_model=List[PromoCodeResponse]) -def get_promocodes(current_tg_agent: TgAgent = Depends(get_current_tg_agent), db: Session = Depends(get_integration_db)): - """ - Получает все промокоды текущего Telegram-агента. - """ - codes = db.exec(select(PromoCode).where(PromoCode.agent_id == current_tg_agent.id)).all() - return [PromoCodeResponse(promocode=c.promocode, perc=c.perc, description=c.description) for c in codes] diff --git a/main.py b/main.py index e7943a0..59acf24 100644 --- a/main.py +++ b/main.py @@ -252,6 +252,7 @@ def get_referrals_stat( "ref": ref.ref, "agent": agent.name if agent and agent.name else f"Агент {ref.tg_agent_id}", "description": ref.description or "", + "promocode": ref.promocode, "salesSum": sales_sum, "salesCount": sales_count }) diff --git a/sql_create.sql b/sql_create.sql index 6c391ae..4fe118a 100644 --- a/sql_create.sql +++ b/sql_create.sql @@ -110,26 +110,12 @@ CREATE TABLE agent_transactions ( ; -CREATE TABLE promocode ( - id INTEGER NOT NULL, - promocode VARCHAR NOT NULL, - perc FLOAT NOT NULL, - agent_id INTEGER NOT NULL, - description VARCHAR, - create_dttm DATETIME NOT NULL, - update_dttm DATETIME NOT NULL, - PRIMARY KEY (id), - FOREIGN KEY(agent_id) REFERENCES tgagent (id) -) - -; - - CREATE TABLE ref ( id INTEGER NOT NULL, tg_agent_id INTEGER NOT NULL, ref VARCHAR NOT NULL, description VARCHAR, + promocode VARCHAR(8) NOT NULL, create_dttm DATETIME NOT NULL, update_dttm DATETIME NOT NULL, PRIMARY KEY (id), diff --git a/sql_models.py b/sql_models.py index 2555404..cc38eb1 100644 --- a/sql_models.py +++ b/sql_models.py @@ -37,13 +37,13 @@ class TgAgent(SQLModel, table=True): refs: List["Ref"] = Relationship(back_populates="tg_agent") agent_transactions: List["AgentTransaction"] = Relationship(back_populates="tg_agent") agent_balance: Optional["AgentBalance"] = Relationship(back_populates="tg_agent") - promocodes: List["PromoCode"] = Relationship(back_populates="agent") class Ref(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) tg_agent_id: int = Field(foreign_key="tgagent.id") ref: str description: Optional[str] = None + promocode: str = Field(index=True, unique=True, max_length=8) create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) @@ -137,15 +137,4 @@ class IntegrationToken(SQLModel, table=True): update_dttm: datetime = Field(default_factory=datetime.utcnow, nullable=False) use_dttm: Optional[datetime] = None - company: "Company" = Relationship(back_populates="integration_tokens") - -class PromoCode(SQLModel, table=True): - id: Optional[int] = Field(default=None, primary_key=True) - promocode: str = Field(index=True, unique=True) - perc: float = Field(default=10.0) - agent_id: int = Field(foreign_key="tgagent.id") - description: Optional[str] = None - create_dttm: datetime = Field(default_factory=datetime.utcnow) - update_dttm: datetime = Field(default_factory=datetime.utcnow) - - agent: "TgAgent" = Relationship(back_populates="promocodes") \ No newline at end of file + company: "Company" = Relationship(back_populates="integration_tokens") \ No newline at end of file diff --git a/tg_models.py b/tg_models.py index 93d298e..bde1e99 100644 --- a/tg_models.py +++ b/tg_models.py @@ -7,6 +7,7 @@ from uuid import UUID class RefResponse(BaseModel): ref: str description: str + promocode: str class RefAddRequest(BaseModel): description: str @@ -25,6 +26,8 @@ class RegisterRequest(BaseModel): # New Response Models for TG APIs class RefAddResponse(BaseModel): ref: str + promocode: str + description: str class RefStatItem(BaseModel): description: str @@ -37,12 +40,4 @@ class RefStatResponse(BaseModel): class StatResponse(BaseModel): totalSales: int totalIncome: float - availableWithdrawal: float - -class PromoCodeAddRequest(BaseModel): - description: Optional[str] = None - -class PromoCodeResponse(BaseModel): - promocode: str - perc: float - description: Optional[str] = None \ No newline at end of file + availableWithdrawal: float \ No newline at end of file