Добавлен новый файл integration_api.py для интеграционного API, реализованы функции для создания и проверки токенов, а также эндпоинт для загрузки данных о продажах. Обновлены модели и логика работы с датами в fill_db.py и main.py для использования поля sale_date вместо create_dttm.
This commit is contained in:
parent
6e804953c0
commit
57188186c0
@ -165,6 +165,7 @@ def fill_db():
|
||||
ref=ref.id,
|
||||
sale_id=str(uuid4()),
|
||||
company_id=company.id,
|
||||
sale_date=dt,
|
||||
create_dttm=dt,
|
||||
update_dttm=dt
|
||||
)
|
||||
|
||||
75
integration_api.py
Normal file
75
integration_api.py
Normal file
@ -0,0 +1,75 @@
|
||||
from fastapi import FastAPI, HTTPException, status, Depends, Request
|
||||
from sqlmodel import Session, select
|
||||
from typing import Optional
|
||||
from datetime import datetime, timedelta
|
||||
import jwt
|
||||
from jwt.exceptions import InvalidTokenError
|
||||
from pydantic import BaseModel
|
||||
|
||||
from sql_models import Sale
|
||||
from helpers_bff import get_db, AUTH_DB_ENGINE # Assuming these are the correct imports
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Конфигурация для интеграционного API токена
|
||||
INTEGRATION_SECRET_KEY = "your-integration-super-secret-key" # Смените это на безопасный ключ!
|
||||
INTEGRATION_ALGORITHM = "HS256"
|
||||
INTEGRATION_TOKEN_EXPIRE_MINUTES = 60 * 24 # 24 часа
|
||||
|
||||
class IntegrationTokenData(BaseModel):
|
||||
client_id: str
|
||||
|
||||
class SaleCreate(BaseModel):
|
||||
cost: float
|
||||
crediting: float
|
||||
ref_id: int
|
||||
sale_id: str
|
||||
company_id: int
|
||||
sale_date: datetime = datetime.utcnow()
|
||||
|
||||
def create_integration_access_token(data: dict, expires_delta: timedelta = None):
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=INTEGRATION_TOKEN_EXPIRE_MINUTES)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, INTEGRATION_SECRET_KEY, algorithm=INTEGRATION_ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
async def verify_integration_token(request: Request):
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate integration credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
auth_header = request.headers.get("Authorization")
|
||||
if not auth_header or not auth_header.startswith("Bearer "):
|
||||
raise credentials_exception
|
||||
token = auth_header.replace("Bearer ", "").strip()
|
||||
try:
|
||||
payload = jwt.decode(token, INTEGRATION_SECRET_KEY, algorithms=[INTEGRATION_ALGORITHM])
|
||||
client_id: str = payload.get("client_id")
|
||||
if client_id is None:
|
||||
raise credentials_exception
|
||||
# Здесь вы можете добавить логику для проверки client_id, например, из базы данных
|
||||
except InvalidTokenError:
|
||||
raise credentials_exception
|
||||
return True # Токен действителен
|
||||
|
||||
@app.post("/sale", status_code=status.HTTP_201_CREATED)
|
||||
async def upload_sale(sale_data: SaleCreate, db: Session = Depends(get_db), verified: bool = Depends(verify_integration_token)):
|
||||
if not verified:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authorized")
|
||||
|
||||
db_sale = Sale(cost=sale_data.cost, crediting=sale_data.crediting, ref=sale_data.ref_id, sale_id=sale_data.sale_id, company_id=sale_data.company_id, sale_date=sale_data.sale_date)
|
||||
db.add(db_sale)
|
||||
db.commit()
|
||||
db.refresh(db_sale)
|
||||
return {"message": "Sale uploaded successfully", "sale_id": db_sale.id}
|
||||
|
||||
@app.get("/generate-integration-token")
|
||||
async def generate_token_endpoint(client_id: str):
|
||||
token_data = {"client_id": client_id}
|
||||
token = create_integration_access_token(token_data)
|
||||
return {"access_token": token, "token_type": "bearer"}
|
||||
10
main.py
10
main.py
@ -236,11 +236,11 @@ def get_dashboard_chart_total(current_account: Account = Depends(get_current_acc
|
||||
# Группируем продажи по дате (день)
|
||||
result = db.exec(
|
||||
select(
|
||||
func.strftime('%Y-%m-%d', Sale.create_dttm).label('date'),
|
||||
func.strftime('%Y-%m-%d', Sale.sale_date).label('date'),
|
||||
func.sum(Sale.cost).label('revenue'),
|
||||
func.count(Sale.id).label('sales')
|
||||
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.create_dttm))
|
||||
.order_by(func.strftime('%Y-%m-%d', Sale.create_dttm))
|
||||
).where(Sale.company_id == current_account.company_id).group_by(func.strftime('%Y-%m-%d', Sale.sale_date))
|
||||
.order_by(func.strftime('%Y-%m-%d', Sale.sale_date))
|
||||
).all()
|
||||
# Преобразуем результат в нужный формат
|
||||
data = [
|
||||
@ -368,9 +368,9 @@ def get_sales_stat(
|
||||
"""
|
||||
sales_query = select(Sale).where(Sale.company_id == current_account.company_id)
|
||||
if date_start:
|
||||
sales_query = sales_query.where(Sale.create_dttm >= date_start)
|
||||
sales_query = sales_query.where(Sale.sale_date >= date_start)
|
||||
if date_end:
|
||||
sales_query = sales_query.where(Sale.create_dttm <= date_end)
|
||||
sales_query = sales_query.where(Sale.sale_date <= date_end)
|
||||
sales = db.exec(sales_query).all()
|
||||
ref_ids = list(set(sale.ref for sale in sales))
|
||||
refs = db.exec(select(Ref).where(Ref.id.in_(ref_ids))).all() if ref_ids else []
|
||||
|
||||
@ -39,6 +39,7 @@ class Sale(SQLModel, table=True):
|
||||
ref: int = Field(foreign_key="ref.id")
|
||||
sale_id: str
|
||||
company_id: int = Field(foreign_key="company.id")
|
||||
sale_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
create_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
update_dttm: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user