fix: removed crap, category on service and deal
This commit is contained in:
33
auth/jwt.py
33
auth/jwt.py
@@ -1,33 +0,0 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import HTTPException, Depends
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from sqlalchemy import select
|
||||
from starlette import status
|
||||
|
||||
from backend import config
|
||||
from database import User
|
||||
from jose import jwt
|
||||
|
||||
from database.base import DatabaseDependency
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer("")
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
|
||||
def generate_jwt_token(user: User):
|
||||
return jwt.encode({'sub': user.id}, settings.SECRET_KEY, algorithm=ALGORITHM)
|
||||
|
||||
|
||||
def require_jwt_sub(token: Annotated[str, Depends(oauth2_scheme)]):
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM])
|
||||
user_id = payload.get("sub")
|
||||
if not user_id:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail='Invalid authorization credentials')
|
||||
return payload
|
||||
|
||||
|
||||
async def get_current_user(db_session: DatabaseDependency, user_id: Annotated[int, Depends(require_jwt_sub)]) -> User:
|
||||
user = await db_session.scalar(select(User).where(User.id == user_id))
|
||||
if user:
|
||||
return user
|
||||
@@ -1,27 +0,0 @@
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
from backend import config
|
||||
|
||||
|
||||
def _generate_hash(telegram_data: dict):
|
||||
data = telegram_data.copy()
|
||||
del data['hash']
|
||||
keys = sorted(data.keys())
|
||||
string_arr = []
|
||||
for key in keys:
|
||||
if data[key] is not None:
|
||||
string_arr.append(key + '=' + str(data[key]))
|
||||
string_cat = '\n'.join(string_arr)
|
||||
|
||||
secret_key = hashlib.sha256(settings.TELEGRAM_BOT_TOKEN.encode('utf-8')).digest()
|
||||
hash_bytes = bytes(string_cat, 'utf-8')
|
||||
hmac_hash = hmac.new(secret_key, hash_bytes, hashlib.sha256).hexdigest()
|
||||
return hmac_hash
|
||||
|
||||
|
||||
def telegram_authorize(telegram_data: dict):
|
||||
generated_hash = _generate_hash(telegram_data)
|
||||
user_hash = telegram_data['hash']
|
||||
return generated_hash == user_hash
|
||||
|
||||
@@ -9,7 +9,7 @@ from .marketplace import BaseMarketplace
|
||||
from .shipping_warehouse import ShippingWarehouse
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import DealBillRequest
|
||||
from . import DealBillRequest, ServicePriceCategory
|
||||
|
||||
|
||||
@unique
|
||||
@@ -23,6 +23,12 @@ class DealStatus(IntEnum):
|
||||
CANCELLED = 6
|
||||
|
||||
|
||||
class DealPriceCategory(BaseModel):
|
||||
__tablename__ = 'deal_price_category'
|
||||
deal_id: Mapped[int] = mapped_column(ForeignKey('deals.id'), primary_key=True, unique=True)
|
||||
category_id: Mapped[int] = mapped_column(ForeignKey('service_price_category.id'), primary_key=True)
|
||||
|
||||
|
||||
class Deal(BaseModel):
|
||||
__tablename__ = 'deals'
|
||||
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||
@@ -64,6 +70,9 @@ class Deal(BaseModel):
|
||||
|
||||
comment = Column(String, nullable=False, server_default='', comment='Коментарий к заданию')
|
||||
bill_request: Mapped[Optional['DealBillRequest']] = relationship(back_populates='deal', lazy='joined')
|
||||
category: Mapped[Optional["ServicePriceCategory"]] = relationship('ServicePriceCategory',
|
||||
secondary=DealPriceCategory.__table__,
|
||||
lazy='joined')
|
||||
|
||||
|
||||
class DealStatusHistory(BaseModel):
|
||||
|
||||
@@ -42,6 +42,10 @@ class Service(BaseModel):
|
||||
lazy='selectin',
|
||||
order_by="asc(ServicePriceRange.from_quantity)",
|
||||
cascade="all, delete-orphan")
|
||||
category_prices = relationship('ServiceCategoryPrice',
|
||||
back_populates='service',
|
||||
lazy='selectin',
|
||||
cascade="all, delete-orphan")
|
||||
|
||||
|
||||
class ServicePriceRange(BaseModel):
|
||||
@@ -54,6 +58,23 @@ class ServicePriceRange(BaseModel):
|
||||
price = Column(Double, nullable=False, comment='Цена')
|
||||
|
||||
|
||||
class ServiceCategoryPrice(BaseModel):
|
||||
__tablename__ = 'service_category_prices'
|
||||
service_id: Mapped[int] = mapped_column(ForeignKey('services.id'), primary_key=True)
|
||||
category_id: Mapped[int] = mapped_column(ForeignKey('service_price_category.id'), primary_key=True)
|
||||
|
||||
price: Mapped[float] = mapped_column(Double, nullable=False, comment='Цена')
|
||||
|
||||
service: Mapped["Service"] = relationship('Service', lazy='joined', back_populates='category_prices')
|
||||
category: Mapped["ServicePriceCategory"] = relationship('ServicePriceCategory', lazy='joined')
|
||||
|
||||
|
||||
class ServicePriceCategory(BaseModel):
|
||||
__tablename__ = 'service_price_category'
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(nullable=False)
|
||||
|
||||
|
||||
class ServiceCategory(BaseModel):
|
||||
__tablename__ = 'service_categories'
|
||||
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||
|
||||
@@ -17,6 +17,7 @@ service_router = APIRouter(
|
||||
)
|
||||
|
||||
|
||||
# region Services
|
||||
@service_router.get(
|
||||
'/get-all',
|
||||
response_model=ServiceGetAllResponse,
|
||||
@@ -69,6 +70,10 @@ async def delete(
|
||||
return await ServiceService(session).delete(request)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Categories
|
||||
|
||||
@service_router.get(
|
||||
'/categories/get-all',
|
||||
response_model=ServiceGetAllCategoriesResponse,
|
||||
@@ -94,6 +99,9 @@ async def create_category(
|
||||
return await ServiceService(session).create_category(request)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Types
|
||||
@service_router.get(
|
||||
'/types/get-all',
|
||||
response_model=BaseEnumListSchema,
|
||||
@@ -108,6 +116,10 @@ async def get_all_service_types(
|
||||
return BaseEnumListSchema(items=result)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Kits
|
||||
|
||||
@service_router.get(
|
||||
'/kits/get-all',
|
||||
response_model=GetAllServicesKitsResponse,
|
||||
@@ -144,3 +156,60 @@ async def update_services_kit(
|
||||
request: UpdateServicesKitRequest
|
||||
):
|
||||
return await ServiceService(session).update_kit(request)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Price Categories
|
||||
# crud price categories
|
||||
@service_router.get(
|
||||
'/price-categories/get-all',
|
||||
response_model=GetAllPriceCategoriesResponse,
|
||||
operation_id='get_all_price_categories',
|
||||
dependencies=[Depends(guest_user)]
|
||||
)
|
||||
async def get_all_price_categories(
|
||||
session: SessionDependency
|
||||
):
|
||||
return await ServiceService(session).get_all_price_categories()
|
||||
|
||||
|
||||
@service_router.post(
|
||||
'/price-categories/create',
|
||||
response_model=CreatePriceCategoryResponse,
|
||||
operation_id='create_price_category',
|
||||
dependencies=[Depends(authorized_user)]
|
||||
)
|
||||
async def create_price_category(
|
||||
session: SessionDependency,
|
||||
request: CreatePriceCategoryRequest
|
||||
):
|
||||
return await ServiceService(session).create_price_category(request)
|
||||
|
||||
|
||||
@service_router.post(
|
||||
'/price-categories/update',
|
||||
response_model=UpdatePriceCategoryResponse,
|
||||
operation_id='update_price_category',
|
||||
dependencies=[Depends(authorized_user)]
|
||||
)
|
||||
async def update_price_category(
|
||||
session: SessionDependency,
|
||||
request: UpdatePriceCategoryRequest
|
||||
):
|
||||
return await ServiceService(session).update_price_category(request)
|
||||
|
||||
|
||||
@service_router.post(
|
||||
'/price-categories/delete',
|
||||
response_model=DeletePriceCategoryResponse,
|
||||
operation_id='delete_price_category',
|
||||
dependencies=[Depends(authorized_user)]
|
||||
)
|
||||
async def delete_price_category(
|
||||
session: SessionDependency,
|
||||
request: DeletePriceCategoryRequest
|
||||
):
|
||||
return await ServiceService(session).delete_price_category(request)
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -3,12 +3,13 @@ from typing import List, Optional, Union
|
||||
|
||||
from pydantic import constr, field_validator
|
||||
|
||||
from models import ServiceCategoryPrice, ServicePriceCategory
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
from schemas.billing import DealBillRequestSchema
|
||||
from schemas.client import ClientSchema
|
||||
from schemas.marketplace import BaseMarketplaceSchema
|
||||
from schemas.product import ProductSchema
|
||||
from schemas.service import ServiceSchema
|
||||
from schemas.service import ServiceSchema, ServicePriceCategorySchema
|
||||
from schemas.shipping_warehouse import ShippingWarehouseSchema
|
||||
from schemas.user import UserSchema
|
||||
|
||||
@@ -37,6 +38,7 @@ class DealSummary(BaseSchema):
|
||||
shipment_warehouse_id: Optional[int]
|
||||
shipment_warehouse_name: Optional[str]
|
||||
|
||||
|
||||
class DealServiceSchema(BaseSchema):
|
||||
service: ServiceSchema
|
||||
quantity: int
|
||||
@@ -81,6 +83,7 @@ class DealSchema(BaseSchema):
|
||||
comment: str
|
||||
shipping_warehouse: Optional[Union[ShippingWarehouseSchema, str]] = None
|
||||
bill_request: Optional[DealBillRequestSchema] = None
|
||||
category: Optional[ServicePriceCategorySchema] = None
|
||||
|
||||
|
||||
class DealGeneralInfoSchema(BaseSchema):
|
||||
@@ -110,6 +113,7 @@ class DealQuickCreateRequest(BaseSchema):
|
||||
acceptance_date: datetime.datetime
|
||||
shipping_warehouse: constr(strip_whitespace=True)
|
||||
base_marketplace: BaseMarketplaceSchema
|
||||
category: Optional[ServicePriceCategorySchema] = None
|
||||
|
||||
|
||||
class DealSummaryRequest(BaseSchema):
|
||||
@@ -212,9 +216,11 @@ class DealAddKitRequest(BaseSchema):
|
||||
class DealCreateGuestUrlRequest(BaseSchema):
|
||||
deal_id: int
|
||||
|
||||
|
||||
class DealCompleteRequest(BaseSchema):
|
||||
deal_id: int
|
||||
|
||||
|
||||
# endregion Requests
|
||||
|
||||
# region Responses
|
||||
@@ -311,6 +317,7 @@ class DealAddKitResponse(OkMessageSchema):
|
||||
class DealCreateGuestUrlResponse(OkMessageSchema):
|
||||
url: str
|
||||
|
||||
|
||||
class DealCompleteResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ from schemas.base import BaseSchema, OkMessageSchema, BaseEnumSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
|
||||
# region Services
|
||||
class ServicePriceRangeSchema(BaseSchema):
|
||||
id: int | None
|
||||
from_quantity: int
|
||||
@@ -16,6 +18,16 @@ class ServiceCategorySchema(BaseSchema):
|
||||
name: str
|
||||
|
||||
|
||||
class ServicePriceCategorySchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class ServiceCategoryPriceSchema(BaseSchema):
|
||||
category: ServicePriceCategorySchema
|
||||
price: float
|
||||
|
||||
|
||||
class ServiceSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
@@ -23,9 +35,13 @@ class ServiceSchema(BaseSchema):
|
||||
price: float
|
||||
service_type: int
|
||||
price_ranges: List[ServicePriceRangeSchema]
|
||||
category_prices: List[ServiceCategoryPriceSchema]
|
||||
cost: Optional[int]
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Kits
|
||||
class BaseServiceKitSchema(BaseSchema):
|
||||
name: str
|
||||
service_type: int
|
||||
@@ -47,6 +63,12 @@ class UpdateServiceKitSchema(BaseServiceKitSchema):
|
||||
|
||||
# endregion
|
||||
|
||||
# region Category prices
|
||||
|
||||
# endregion
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
# region Requests
|
||||
class ServiceCreateRequest(BaseSchema):
|
||||
@@ -73,6 +95,19 @@ class UpdateServicesKitRequest(BaseSchema):
|
||||
data: UpdateServiceKitSchema
|
||||
|
||||
|
||||
class CreatePriceCategoryRequest(BaseSchema):
|
||||
name: str
|
||||
|
||||
|
||||
class UpdatePriceCategoryRequest(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class DeletePriceCategoryRequest(BaseSchema):
|
||||
id: int
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
@@ -111,4 +146,21 @@ class UpdateServicesKitResponse(OkMessageSchema):
|
||||
|
||||
class GetAllServicesKitsResponse(BaseSchema):
|
||||
services_kits: List[GetServiceKitSchema]
|
||||
|
||||
|
||||
class GetAllPriceCategoriesResponse(BaseSchema):
|
||||
price_categories: List[ServicePriceCategorySchema]
|
||||
|
||||
|
||||
class CreatePriceCategoryResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
class UpdatePriceCategoryResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
class DeletePriceCategoryResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
# endregion
|
||||
|
||||
@@ -130,6 +130,14 @@ class DealService(BaseService):
|
||||
user,
|
||||
deadline=request.acceptance_date,
|
||||
comment=request.comment)
|
||||
# add category if specified
|
||||
if request.category:
|
||||
deal_category = DealPriceCategory(
|
||||
deal_id=deal.id,
|
||||
category_id=request.category.id
|
||||
)
|
||||
self.session.add(deal_category)
|
||||
|
||||
await self.session.commit()
|
||||
return DealQuickCreateResponse(deal_id=deal.id)
|
||||
|
||||
@@ -1004,7 +1012,7 @@ class DealService(BaseService):
|
||||
for product in deal.products:
|
||||
total_one_product = sum((service.price for service in product.services))
|
||||
total = total_one_product * product.quantity
|
||||
totals.append({ "total_one_product": total_one_product, "total": total })
|
||||
totals.append({"total_one_product": total_one_product, "total": total})
|
||||
|
||||
return totals
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ from typing import Union
|
||||
from sqlalchemy import select, update, insert, delete
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from models import Service, ServiceCategory, ServicePriceRange, ServicesKit, services_kit_services
|
||||
from models import Service, ServiceCategory, ServicePriceRange, ServicesKit, services_kit_services, \
|
||||
ServiceCategoryPrice, ServicePriceCategory
|
||||
from services.base import BaseService
|
||||
from schemas.service import *
|
||||
|
||||
@@ -27,6 +28,7 @@ class ServiceService(BaseService):
|
||||
del service_dict['id']
|
||||
del service_dict['category']
|
||||
del service_dict['price_ranges']
|
||||
del service_dict['category_prices']
|
||||
service = Service(**service_dict)
|
||||
self.session.add(service)
|
||||
await self.session.flush()
|
||||
@@ -37,7 +39,15 @@ class ServiceService(BaseService):
|
||||
del price_range_dict['id']
|
||||
price_range_obj = ServicePriceRange(**price_range_dict)
|
||||
self.session.add(price_range_obj)
|
||||
category_prices = request.service.category_prices
|
||||
for category_price in category_prices:
|
||||
category_price_dict = category_price.model_dump()
|
||||
category_price_dict['service_id'] = service.id
|
||||
category_price_dict['category_id'] = category_price.category.id
|
||||
|
||||
del category_price_dict['category']
|
||||
category_price_obj = ServiceCategoryPrice(**category_price_dict)
|
||||
self.session.add(category_price_obj)
|
||||
await self.session.commit()
|
||||
return ServiceCreateResponse(ok=True, message="Услуга успешно создана")
|
||||
except Exception as e:
|
||||
@@ -54,6 +64,7 @@ class ServiceService(BaseService):
|
||||
service_dict['category_id'] = raw_service.category.id
|
||||
del service_dict['category']
|
||||
del service_dict['price_ranges']
|
||||
del service_dict['category_prices']
|
||||
await self.session.execute(
|
||||
update(Service)
|
||||
.where(Service.id == raw_service.id)
|
||||
@@ -81,6 +92,26 @@ class ServiceService(BaseService):
|
||||
del price_range_dict['id']
|
||||
price_range_obj = ServicePriceRange(**price_range_dict)
|
||||
self.session.add(price_range_obj)
|
||||
|
||||
# deleting previouse category prices
|
||||
stmt = (
|
||||
delete(
|
||||
ServiceCategoryPrice
|
||||
).where(
|
||||
ServiceCategoryPrice.service_id == service.id
|
||||
)
|
||||
)
|
||||
await self.session.execute(stmt)
|
||||
await self.session.flush()
|
||||
# inserting new category prices
|
||||
for category_price in raw_service.category_prices:
|
||||
category_price_dict = category_price.dict()
|
||||
category_price_dict['service_id'] = raw_service.id
|
||||
category_price_dict['category_id'] = category_price.category.id
|
||||
del category_price_dict['category']
|
||||
category_price_obj = ServiceCategoryPrice(**category_price_dict)
|
||||
self.session.add(category_price_obj)
|
||||
|
||||
await self.session.commit()
|
||||
return ServiceUpdateResponse(ok=True, message="Услуга успешно обновлена")
|
||||
except Exception as e:
|
||||
@@ -205,3 +236,60 @@ class ServiceService(BaseService):
|
||||
|
||||
except Exception as e:
|
||||
return UpdateServicesKitResponse(ok=False, message=str(e))
|
||||
|
||||
async def get_all_price_categories(self) -> GetAllPriceCategoriesResponse:
|
||||
query = await (self.session
|
||||
.scalars(select(ServicePriceCategory)
|
||||
.order_by(ServicePriceCategory.id)))
|
||||
price_categories = []
|
||||
for category in query.all():
|
||||
price_categories.append(ServicePriceCategorySchema.model_validate(category))
|
||||
return GetAllPriceCategoriesResponse(price_categories=price_categories)
|
||||
|
||||
async def create_price_category(self, request: CreatePriceCategoryRequest) -> ServiceCreateCategoryResponse:
|
||||
try:
|
||||
raw_category = request.name
|
||||
category = ServicePriceCategory(name=raw_category)
|
||||
self.session.add(category)
|
||||
await self.session.commit()
|
||||
return ServiceCreateCategoryResponse(ok=True, message="Категория цен успешно создана")
|
||||
except Exception as e:
|
||||
return ServiceCreateCategoryResponse(ok=False, message=f"Неудалось создать категорию цен, ошибка: {e}")
|
||||
|
||||
async def update_price_category(self, request: UpdatePriceCategoryRequest) -> ServiceUpdateResponse:
|
||||
try:
|
||||
raw_category = request.name
|
||||
category = await (self.session.get(ServicePriceCategory, request.id))
|
||||
if not category:
|
||||
return ServiceUpdateResponse(ok=False, message="Категория цен не найдена")
|
||||
await self.session.execute(
|
||||
update(ServicePriceCategory)
|
||||
.where(ServicePriceCategory.id == request.id)
|
||||
.values(name=raw_category)
|
||||
)
|
||||
await self.session.commit()
|
||||
return ServiceUpdateResponse(ok=True, message="Категория цен успешно обновлена")
|
||||
except Exception as e:
|
||||
return ServiceUpdateResponse(ok=False, message=f"Неудалось обновить категорию цен, ошибка: {e}")
|
||||
|
||||
async def delete_price_category(self, request: DeletePriceCategoryRequest) -> ServiceDeleteResponse:
|
||||
try:
|
||||
category = await (
|
||||
self.session
|
||||
.scalar(
|
||||
select(
|
||||
ServicePriceCategory
|
||||
)
|
||||
.filter(
|
||||
ServicePriceCategory.id == request.id
|
||||
)
|
||||
)
|
||||
)
|
||||
if not category:
|
||||
return ServiceDeleteResponse(ok=False, message="Категория цен не найдена")
|
||||
|
||||
await self.session.delete(category)
|
||||
await self.session.commit()
|
||||
return ServiceDeleteResponse(ok=True, message="Категория цен успешно удалена")
|
||||
except Exception as e:
|
||||
return ServiceDeleteResponse(ok=False, message=f"Неудалось удалить категорию цен, ошибка: {e}")
|
||||
|
||||
Reference in New Issue
Block a user