From 92df59ad2375be1afed4c794a0087d93a0159fe2 Mon Sep 17 00:00:00 2001 From: Redsandyg Date: Sun, 15 Jun 2025 15:20:28 +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=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=84=D1=83?= =?UTF-8?q?=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D1=8B=20=D1=81=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=BC=D0=BE=D0=BA=D0=BE=D0=B4=D0=B0=D0=BC=D0=B8=20=D0=B2=20int?= =?UTF-8?q?egration=5Fapi.py,=20=D0=B2=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D1=8F?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=BC=D0=BE=D0=BA=D0=BE=D0=B4=D0=BE=D0=B2=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20Telegram-=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=B2.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BC=D0=BE=D0=B4=D0=B5=D0=BB=D0=B8=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB=20generate=5Fsql.py=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20SQL-=D1=81=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D0=B0?= =?UTF-8?q?=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=82?= =?UTF-8?q?=D0=B0=D0=B1=D0=BB=D0=B8=D1=86.=20=D0=9E=D0=B1=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20fill=5Fdb.py=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BE=D0=BA=D0=BE=D0=B4=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=20=D0=B7=D0=B0=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B8=20=D0=B1=D0=B0=D0=B7=D1=8B=20=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85.=20=D0=A2=D0=B0=D0=BA=D0=B6?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?=20sql=5Fmodels.py=20=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BC=D0=BE=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B8=20PromoCode=20=D0=B8=20=D1=81=D0=BE=D0=BE?= =?UTF-8?q?=D1=82=D0=B2=D0=B5=D1=82=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89?= =?UTF-8?q?=D0=B8=D1=85=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B5=D0=B9.=20=D0=A3?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B0=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B0=20=D0=BA=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=20=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D1=8B=20=D0=BE=D1=82=D0=BB=D0=B0=D0=B4=D0=BE=D1=87=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fill_db.py | 33 ++++++++- generate_sql.py | 23 ++++++ integration_api.py | 37 +++++++++- main.py | 4 ++ sql_create.sql | 175 +++++++++++++++++++++++++++++++++++++++++++++ sql_models.py | 42 ++++++++++- tg_models.py | 10 ++- 7 files changed, 318 insertions(+), 6 deletions(-) create mode 100644 generate_sql.py create mode 100644 sql_create.sql diff --git a/fill_db.py b/fill_db.py index 19e3ef8..8d826dd 100644 --- a/fill_db.py +++ b/fill_db.py @@ -1,11 +1,12 @@ import random from uuid import uuid4 from sqlmodel import Session -from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken +from sql_models import TgAgent, Ref, Sale, Account, Company, AgentTransaction, PartnerTransaction, CompanyBalance, AgentBalance, IntegrationToken, PromoCode from sqlalchemy import text from datetime import datetime, timedelta from hashlib import sha256 from helpers_bff import AUTH_DB_ENGINE, get_password_hash +import string # Константа: список user_ids @@ -71,6 +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 sale")) session.execute(text("DELETE FROM ref")) session.execute(text("DELETE FROM tgagent")) @@ -149,6 +151,35 @@ def fill_db(): session.commit() for tg_agent in tg_agents: session.refresh(tg_agent) + # Отладка: количество агентов + 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) diff --git a/generate_sql.py b/generate_sql.py new file mode 100644 index 0000000..63914cb --- /dev/null +++ b/generate_sql.py @@ -0,0 +1,23 @@ +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 + +# --- Отладочный вывод --- +print("Таблицы в metadata:", SQLModel.metadata.sorted_tables) +print("Все зарегистрированные модели:", SQLModel.__subclasses__()) + +# --- Генерация и сохранение SQL-скрипта создания таблиц --- +def get_sql_create_script(): + script = [] + for table in SQLModel.metadata.sorted_tables: + create_table_sql = str(CreateTable(table).compile(dialect=AUTH_DB_ENGINE.dialect)) + script.append(f"{create_table_sql};") + return "\n\n".join(script) + +sql_script = get_sql_create_script() +sql_file_path = os.path.join(os.path.dirname(__file__), "sql_create.sql") +with open(sql_file_path, "w", encoding="utf-8") as f: + f.write(sql_script) +print("SQL-скрипт успешно сгенерирован!") \ No newline at end of file diff --git a/integration_api.py b/integration_api.py index 8f8cb64..02b1f7b 100644 --- a/integration_api.py +++ b/integration_api.py @@ -1,14 +1,16 @@ -from fastapi import FastAPI, Depends, HTTPException, status, Header, Body +from fastapi import FastAPI, Depends, HTTPException, status, Header, Body, Request from sqlmodel import Session, select, Field from typing import Optional, List, Dict from datetime import datetime, timedelta import hashlib import uuid +from random import choices +import string -from sql_models import Company, IntegrationToken, Ref, Sale, AgentTransaction, PartnerTransaction, AgentBalance, TgAgent, CompanyBalance +from sql_models import Company, IntegrationToken, Ref, Sale, AgentTransaction, PartnerTransaction, AgentBalance, TgAgent, CompanyBalance, PromoCode 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 tg_models import RefAddRequest, RefResponse, RefAddResponse, RefStatResponse, RegisterRequest, StatResponse, PromoCodeAddRequest, PromoCodeResponse 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() @@ -304,3 +306,32 @@ 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 622df40..e7943a0 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +import uuid from fastapi import ( FastAPI, Depends, @@ -62,6 +63,7 @@ from helpers_bff import ( ACCESS_TOKEN_EXPIRE_MINUTES, pwd_context, ) +import os # Создание движка базы данных @@ -71,6 +73,8 @@ SQLModel.metadata.create_all(AUTH_DB_ENGINE) app = FastAPI() + + @app.post("/token", response_model=Token, tags=["bff", "token"]) def login_account_for_access_token( form_data: OAuth2PasswordRequestForm = Depends(), diff --git a/sql_create.sql b/sql_create.sql new file mode 100644 index 0000000..6c391ae --- /dev/null +++ b/sql_create.sql @@ -0,0 +1,175 @@ + +CREATE TABLE company ( + id INTEGER NOT NULL, + name VARCHAR NOT NULL, + commission FLOAT NOT NULL, + agent_commission FLOAT NOT NULL, + "key" VARCHAR NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + auto_approve_transactions BOOLEAN NOT NULL, + PRIMARY KEY (id) +) + +; + + +CREATE TABLE account ( + id INTEGER NOT NULL, + login VARCHAR NOT NULL, + password_hash VARCHAR NOT NULL, + "firstName" VARCHAR, + surname VARCHAR, + phone VARCHAR, + email VARCHAR, + company_id INTEGER NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(company_id) REFERENCES company (id) +) + +; + + +CREATE TABLE company_balances ( + id INTEGER NOT NULL, + company_id INTEGER NOT NULL, + available_balance FLOAT NOT NULL, + pending_balance FLOAT NOT NULL, + updated_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + UNIQUE (company_id), + FOREIGN KEY(company_id) REFERENCES company (id) +) + +; + + +CREATE TABLE integrationtoken ( + id INTEGER NOT NULL, + description VARCHAR NOT NULL, + token_hash VARCHAR, + masked_token VARCHAR, + company_id INTEGER NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + use_dttm DATETIME, + PRIMARY KEY (id), + FOREIGN KEY(company_id) REFERENCES company (id) +) + +; + + +CREATE TABLE tgagent ( + id INTEGER NOT NULL, + tg_id INTEGER NOT NULL, + chat_id INTEGER, + phone VARCHAR, + name VARCHAR, + login VARCHAR, + hash VARCHAR, + company_id INTEGER NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(company_id) REFERENCES company (id) +) + +; + + +CREATE TABLE agent_balances ( + id INTEGER NOT NULL, + tg_agent_id INTEGER NOT NULL, + available_balance FLOAT NOT NULL, + frozen_balance FLOAT NOT NULL, + updated_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + UNIQUE (tg_agent_id), + FOREIGN KEY(tg_agent_id) REFERENCES tgagent (id) +) + +; + + +CREATE TABLE agent_transactions ( + id INTEGER NOT NULL, + tg_agent_id INTEGER NOT NULL, + amount FLOAT NOT NULL, + status VARCHAR NOT NULL, + transaction_group CHAR(32) NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(tg_agent_id) REFERENCES tgagent (id), + UNIQUE (transaction_group) +) + +; + + +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, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(tg_agent_id) REFERENCES tgagent (id) +) + +; + + +CREATE TABLE partner_transactions ( + id INTEGER NOT NULL, + company_id INTEGER NOT NULL, + type VARCHAR NOT NULL, + amount FLOAT NOT NULL, + status VARCHAR NOT NULL, + transaction_group CHAR(32) NOT NULL, + agent_transaction_id INTEGER, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(company_id) REFERENCES company (id), + FOREIGN KEY(agent_transaction_id) REFERENCES agent_transactions (id) +) + +; + + +CREATE TABLE sale ( + id INTEGER NOT NULL, + cost FLOAT NOT NULL, + crediting FLOAT NOT NULL, + ref INTEGER NOT NULL, + sale_id VARCHAR NOT NULL, + company_id INTEGER NOT NULL, + sale_dttm DATETIME NOT NULL, + create_dttm DATETIME NOT NULL, + update_dttm DATETIME NOT NULL, + PRIMARY KEY (id), + FOREIGN KEY(ref) REFERENCES ref (id), + FOREIGN KEY(company_id) REFERENCES company (id) +) + +; \ No newline at end of file diff --git a/sql_models.py b/sql_models.py index 7cfbaeb..2555404 100644 --- a/sql_models.py +++ b/sql_models.py @@ -15,6 +15,11 @@ class Company(SQLModel, table=True): auto_approve_transactions: bool = Field(default=False) # Отвечает за автоматическое одобрение агентских транзакций на вывод. integration_tokens: List["IntegrationToken"] = Relationship(back_populates="company") + tg_agents: List["TgAgent"] = Relationship(back_populates="company") + sales: List["Sale"] = Relationship(back_populates="company") + partner_transactions: List["PartnerTransaction"] = Relationship(back_populates="company") + company_balance: Optional["CompanyBalance"] = Relationship(back_populates="company") + accounts: List["Account"] = Relationship(back_populates="company") class TgAgent(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) @@ -28,6 +33,12 @@ class TgAgent(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + company: "Company" = Relationship(back_populates="tg_agents") + 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") @@ -36,6 +47,9 @@ class Ref(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + tg_agent: "TgAgent" = Relationship(back_populates="refs") + sales: List["Sale"] = Relationship(back_populates="ref_obj") + class Sale(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) cost: float @@ -47,6 +61,9 @@ class Sale(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + ref_obj: "Ref" = Relationship(back_populates="sales") + company: "Company" = Relationship(back_populates="sales") + class AgentTransaction(SQLModel, table=True): __tablename__ = "agent_transactions" id: Optional[int] = Field(default=None, primary_key=True) @@ -57,6 +74,9 @@ class AgentTransaction(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + tg_agent: "TgAgent" = Relationship(back_populates="agent_transactions") + partner_transactions: List["PartnerTransaction"] = Relationship(back_populates="agent_transaction") + class PartnerTransaction(SQLModel, table=True): __tablename__ = "partner_transactions" id: Optional[int] = Field(default=None, primary_key=True) @@ -69,6 +89,9 @@ class PartnerTransaction(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + company: "Company" = Relationship(back_populates="partner_transactions") + agent_transaction: Optional["AgentTransaction"] = Relationship(back_populates="partner_transactions") + class CompanyBalance(SQLModel, table=True): __tablename__ = "company_balances" id: Optional[int] = Field(default=None, primary_key=True) @@ -77,6 +100,8 @@ class CompanyBalance(SQLModel, table=True): pending_balance: float = Field(default=0.0) updated_dttm: datetime = Field(default_factory=datetime.utcnow) + company: "Company" = Relationship(back_populates="company_balance") + class AgentBalance(SQLModel, table=True): __tablename__ = "agent_balances" id: Optional[int] = Field(default=None, primary_key=True) @@ -85,6 +110,8 @@ class AgentBalance(SQLModel, table=True): frozen_balance: float = Field(default=0.0) updated_dttm: datetime = Field(default_factory=datetime.utcnow) + tg_agent: "TgAgent" = Relationship(back_populates="agent_balance") + class Account(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) login: str = Field(index=True, unique=True) @@ -97,6 +124,8 @@ class Account(SQLModel, table=True): create_dttm: datetime = Field(default_factory=datetime.utcnow) update_dttm: datetime = Field(default_factory=datetime.utcnow) + company: "Company" = Relationship(back_populates="accounts") + # Новая модель для интеграционных токенов class IntegrationToken(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) @@ -108,4 +137,15 @@ 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") \ No newline at end of file + 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 diff --git a/tg_models.py b/tg_models.py index 2e2e3ff..93d298e 100644 --- a/tg_models.py +++ b/tg_models.py @@ -37,4 +37,12 @@ class RefStatResponse(BaseModel): class StatResponse(BaseModel): totalSales: int totalIncome: float - availableWithdrawal: float \ No newline at end of file + 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