fix: removed crap, category on service and deal

This commit is contained in:
2024-09-27 04:50:01 +03:00
parent 5df64d4916
commit 91cf44f3ae
10 changed files with 258 additions and 64 deletions

View File

View File

@@ -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

View File

@@ -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

View File

@@ -9,7 +9,7 @@ from .marketplace import BaseMarketplace
from .shipping_warehouse import ShippingWarehouse from .shipping_warehouse import ShippingWarehouse
if TYPE_CHECKING: if TYPE_CHECKING:
from . import DealBillRequest from . import DealBillRequest, ServicePriceCategory
@unique @unique
@@ -23,6 +23,12 @@ class DealStatus(IntEnum):
CANCELLED = 6 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): class Deal(BaseModel):
__tablename__ = 'deals' __tablename__ = 'deals'
id = Column(Integer, autoincrement=True, primary_key=True, index=True) 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='Коментарий к заданию') comment = Column(String, nullable=False, server_default='', comment='Коментарий к заданию')
bill_request: Mapped[Optional['DealBillRequest']] = relationship(back_populates='deal', lazy='joined') 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): class DealStatusHistory(BaseModel):

View File

@@ -42,6 +42,10 @@ class Service(BaseModel):
lazy='selectin', lazy='selectin',
order_by="asc(ServicePriceRange.from_quantity)", order_by="asc(ServicePriceRange.from_quantity)",
cascade="all, delete-orphan") cascade="all, delete-orphan")
category_prices = relationship('ServiceCategoryPrice',
back_populates='service',
lazy='selectin',
cascade="all, delete-orphan")
class ServicePriceRange(BaseModel): class ServicePriceRange(BaseModel):
@@ -54,6 +58,23 @@ class ServicePriceRange(BaseModel):
price = Column(Double, nullable=False, comment='Цена') 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): class ServiceCategory(BaseModel):
__tablename__ = 'service_categories' __tablename__ = 'service_categories'
id = Column(Integer, autoincrement=True, primary_key=True, index=True) id = Column(Integer, autoincrement=True, primary_key=True, index=True)

View File

@@ -17,6 +17,7 @@ service_router = APIRouter(
) )
# region Services
@service_router.get( @service_router.get(
'/get-all', '/get-all',
response_model=ServiceGetAllResponse, response_model=ServiceGetAllResponse,
@@ -69,6 +70,10 @@ async def delete(
return await ServiceService(session).delete(request) return await ServiceService(session).delete(request)
# endregion
# region Categories
@service_router.get( @service_router.get(
'/categories/get-all', '/categories/get-all',
response_model=ServiceGetAllCategoriesResponse, response_model=ServiceGetAllCategoriesResponse,
@@ -94,6 +99,9 @@ async def create_category(
return await ServiceService(session).create_category(request) return await ServiceService(session).create_category(request)
# endregion
# region Types
@service_router.get( @service_router.get(
'/types/get-all', '/types/get-all',
response_model=BaseEnumListSchema, response_model=BaseEnumListSchema,
@@ -108,6 +116,10 @@ async def get_all_service_types(
return BaseEnumListSchema(items=result) return BaseEnumListSchema(items=result)
# endregion
# region Kits
@service_router.get( @service_router.get(
'/kits/get-all', '/kits/get-all',
response_model=GetAllServicesKitsResponse, response_model=GetAllServicesKitsResponse,
@@ -144,3 +156,60 @@ async def update_services_kit(
request: UpdateServicesKitRequest request: UpdateServicesKitRequest
): ):
return await ServiceService(session).update_kit(request) 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

View File

@@ -3,12 +3,13 @@ from typing import List, Optional, Union
from pydantic import constr, field_validator from pydantic import constr, field_validator
from models import ServiceCategoryPrice, ServicePriceCategory
from schemas.base import BaseSchema, OkMessageSchema from schemas.base import BaseSchema, OkMessageSchema
from schemas.billing import DealBillRequestSchema from schemas.billing import DealBillRequestSchema
from schemas.client import ClientSchema from schemas.client import ClientSchema
from schemas.marketplace import BaseMarketplaceSchema from schemas.marketplace import BaseMarketplaceSchema
from schemas.product import ProductSchema from schemas.product import ProductSchema
from schemas.service import ServiceSchema from schemas.service import ServiceSchema, ServicePriceCategorySchema
from schemas.shipping_warehouse import ShippingWarehouseSchema from schemas.shipping_warehouse import ShippingWarehouseSchema
from schemas.user import UserSchema from schemas.user import UserSchema
@@ -37,6 +38,7 @@ class DealSummary(BaseSchema):
shipment_warehouse_id: Optional[int] shipment_warehouse_id: Optional[int]
shipment_warehouse_name: Optional[str] shipment_warehouse_name: Optional[str]
class DealServiceSchema(BaseSchema): class DealServiceSchema(BaseSchema):
service: ServiceSchema service: ServiceSchema
quantity: int quantity: int
@@ -81,6 +83,7 @@ class DealSchema(BaseSchema):
comment: str comment: str
shipping_warehouse: Optional[Union[ShippingWarehouseSchema, str]] = None shipping_warehouse: Optional[Union[ShippingWarehouseSchema, str]] = None
bill_request: Optional[DealBillRequestSchema] = None bill_request: Optional[DealBillRequestSchema] = None
category: Optional[ServicePriceCategorySchema] = None
class DealGeneralInfoSchema(BaseSchema): class DealGeneralInfoSchema(BaseSchema):
@@ -110,6 +113,7 @@ class DealQuickCreateRequest(BaseSchema):
acceptance_date: datetime.datetime acceptance_date: datetime.datetime
shipping_warehouse: constr(strip_whitespace=True) shipping_warehouse: constr(strip_whitespace=True)
base_marketplace: BaseMarketplaceSchema base_marketplace: BaseMarketplaceSchema
category: Optional[ServicePriceCategorySchema] = None
class DealSummaryRequest(BaseSchema): class DealSummaryRequest(BaseSchema):
@@ -212,9 +216,11 @@ class DealAddKitRequest(BaseSchema):
class DealCreateGuestUrlRequest(BaseSchema): class DealCreateGuestUrlRequest(BaseSchema):
deal_id: int deal_id: int
class DealCompleteRequest(BaseSchema): class DealCompleteRequest(BaseSchema):
deal_id: int deal_id: int
# endregion Requests # endregion Requests
# region Responses # region Responses
@@ -311,6 +317,7 @@ class DealAddKitResponse(OkMessageSchema):
class DealCreateGuestUrlResponse(OkMessageSchema): class DealCreateGuestUrlResponse(OkMessageSchema):
url: str url: str
class DealCompleteResponse(OkMessageSchema): class DealCompleteResponse(OkMessageSchema):
pass pass

View File

@@ -4,6 +4,8 @@ from schemas.base import BaseSchema, OkMessageSchema, BaseEnumSchema
# region Entities # region Entities
# region Services
class ServicePriceRangeSchema(BaseSchema): class ServicePriceRangeSchema(BaseSchema):
id: int | None id: int | None
from_quantity: int from_quantity: int
@@ -16,6 +18,16 @@ class ServiceCategorySchema(BaseSchema):
name: str name: str
class ServicePriceCategorySchema(BaseSchema):
id: int
name: str
class ServiceCategoryPriceSchema(BaseSchema):
category: ServicePriceCategorySchema
price: float
class ServiceSchema(BaseSchema): class ServiceSchema(BaseSchema):
id: int id: int
name: str name: str
@@ -23,9 +35,13 @@ class ServiceSchema(BaseSchema):
price: float price: float
service_type: int service_type: int
price_ranges: List[ServicePriceRangeSchema] price_ranges: List[ServicePriceRangeSchema]
category_prices: List[ServiceCategoryPriceSchema]
cost: Optional[int] cost: Optional[int]
# endregion
# region Kits
class BaseServiceKitSchema(BaseSchema): class BaseServiceKitSchema(BaseSchema):
name: str name: str
service_type: int service_type: int
@@ -47,6 +63,12 @@ class UpdateServiceKitSchema(BaseServiceKitSchema):
# endregion # endregion
# region Category prices
# endregion
# endregion
# region Requests # region Requests
class ServiceCreateRequest(BaseSchema): class ServiceCreateRequest(BaseSchema):
@@ -73,6 +95,19 @@ class UpdateServicesKitRequest(BaseSchema):
data: UpdateServiceKitSchema data: UpdateServiceKitSchema
class CreatePriceCategoryRequest(BaseSchema):
name: str
class UpdatePriceCategoryRequest(BaseSchema):
id: int
name: str
class DeletePriceCategoryRequest(BaseSchema):
id: int
# endregion # endregion
@@ -111,4 +146,21 @@ class UpdateServicesKitResponse(OkMessageSchema):
class GetAllServicesKitsResponse(BaseSchema): class GetAllServicesKitsResponse(BaseSchema):
services_kits: List[GetServiceKitSchema] services_kits: List[GetServiceKitSchema]
class GetAllPriceCategoriesResponse(BaseSchema):
price_categories: List[ServicePriceCategorySchema]
class CreatePriceCategoryResponse(OkMessageSchema):
pass
class UpdatePriceCategoryResponse(OkMessageSchema):
pass
class DeletePriceCategoryResponse(OkMessageSchema):
pass
# endregion # endregion

View File

@@ -130,6 +130,14 @@ class DealService(BaseService):
user, user,
deadline=request.acceptance_date, deadline=request.acceptance_date,
comment=request.comment) 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() await self.session.commit()
return DealQuickCreateResponse(deal_id=deal.id) return DealQuickCreateResponse(deal_id=deal.id)

View File

@@ -3,7 +3,8 @@ from typing import Union
from sqlalchemy import select, update, insert, delete from sqlalchemy import select, update, insert, delete
from sqlalchemy.orm import joinedload 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 services.base import BaseService
from schemas.service import * from schemas.service import *
@@ -27,6 +28,7 @@ class ServiceService(BaseService):
del service_dict['id'] del service_dict['id']
del service_dict['category'] del service_dict['category']
del service_dict['price_ranges'] del service_dict['price_ranges']
del service_dict['category_prices']
service = Service(**service_dict) service = Service(**service_dict)
self.session.add(service) self.session.add(service)
await self.session.flush() await self.session.flush()
@@ -37,7 +39,15 @@ class ServiceService(BaseService):
del price_range_dict['id'] del price_range_dict['id']
price_range_obj = ServicePriceRange(**price_range_dict) price_range_obj = ServicePriceRange(**price_range_dict)
self.session.add(price_range_obj) 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() await self.session.commit()
return ServiceCreateResponse(ok=True, message="Услуга успешно создана") return ServiceCreateResponse(ok=True, message="Услуга успешно создана")
except Exception as e: except Exception as e:
@@ -54,6 +64,7 @@ class ServiceService(BaseService):
service_dict['category_id'] = raw_service.category.id service_dict['category_id'] = raw_service.category.id
del service_dict['category'] del service_dict['category']
del service_dict['price_ranges'] del service_dict['price_ranges']
del service_dict['category_prices']
await self.session.execute( await self.session.execute(
update(Service) update(Service)
.where(Service.id == raw_service.id) .where(Service.id == raw_service.id)
@@ -81,6 +92,26 @@ class ServiceService(BaseService):
del price_range_dict['id'] del price_range_dict['id']
price_range_obj = ServicePriceRange(**price_range_dict) price_range_obj = ServicePriceRange(**price_range_dict)
self.session.add(price_range_obj) 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() await self.session.commit()
return ServiceUpdateResponse(ok=True, message="Услуга успешно обновлена") return ServiceUpdateResponse(ok=True, message="Услуга успешно обновлена")
except Exception as e: except Exception as e:
@@ -205,3 +236,60 @@ class ServiceService(BaseService):
except Exception as e: except Exception as e:
return UpdateServicesKitResponse(ok=False, message=str(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}")