feat: вфыв
This commit is contained in:
8
backend/dependecies.py
Normal file
8
backend/dependecies.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from backend.session import get_session
|
||||
|
||||
SessionDependency = Annotated[AsyncSession, Depends(get_session)]
|
||||
8
enums/user.py
Normal file
8
enums/user.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class UserRole(StrEnum):
|
||||
user = 'user'
|
||||
employee = 'employee'
|
||||
manager = 'manager'
|
||||
admin = 'admin'
|
||||
5
main.py
5
main.py
@@ -32,7 +32,10 @@ routers_list = [
|
||||
routers.service_router,
|
||||
routers.product_router,
|
||||
routers.barcode_router,
|
||||
routers.shipping_warehouse_router
|
||||
routers.shipping_warehouse_router,
|
||||
routers.position_router,
|
||||
routers.user_router,
|
||||
routers.role_router,
|
||||
]
|
||||
for router in routers_list:
|
||||
app.include_router(router)
|
||||
|
||||
@@ -1,12 +1,83 @@
|
||||
from sqlalchemy import Column, Integer, BigInteger, String, Boolean
|
||||
from sqlalchemy import BigInteger, Table, ForeignKey, Column
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from models.base import BaseModel
|
||||
|
||||
role_permissions = Table(
|
||||
'role_permissions',
|
||||
BaseModel.metadata,
|
||||
Column('role_key', ForeignKey('roles.key'), primary_key=True),
|
||||
Column('permission_key', ForeignKey('permissions.key'), primary_key=True)
|
||||
)
|
||||
|
||||
user_position = Table(
|
||||
'user_position',
|
||||
BaseModel.metadata,
|
||||
Column('position_key', ForeignKey('positions.key'), primary_key=True),
|
||||
Column('user_id', ForeignKey('users.id'), primary_key=True, unique=True)
|
||||
|
||||
)
|
||||
|
||||
|
||||
class Permission(BaseModel):
|
||||
__tablename__ = 'permissions'
|
||||
key: Mapped[str] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column()
|
||||
|
||||
roles: Mapped[list["Role"]] = relationship('Role',
|
||||
secondary=role_permissions,
|
||||
back_populates='permissions')
|
||||
|
||||
|
||||
class Role(BaseModel):
|
||||
__tablename__ = 'roles'
|
||||
key: Mapped[str] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column()
|
||||
permissions: Mapped[list["Permission"]] = relationship('Permission',
|
||||
secondary=role_permissions,
|
||||
back_populates='roles',
|
||||
lazy='selectin')
|
||||
# users: Mapped[list["User"]] = relationship("User", back_populates="users")
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
__tablename__ = 'users'
|
||||
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
|
||||
telegram_id = Column(BigInteger, nullable=False, index=True)
|
||||
phone_number = Column(String)
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
|
||||
is_admin = Column(Boolean, nullable=False, default=False)
|
||||
first_name: Mapped[str] = mapped_column(nullable=False, server_default='')
|
||||
second_name: Mapped[str] = mapped_column(nullable=False, server_default='')
|
||||
comment: Mapped[str] = mapped_column(nullable=False, server_default='')
|
||||
telegram_id: Mapped[int] = mapped_column(BigInteger,
|
||||
nullable=False,
|
||||
index=True)
|
||||
phone_number: Mapped[str] = mapped_column(nullable=True)
|
||||
is_admin: Mapped[bool] = mapped_column(nullable=False, default=False)
|
||||
is_blocked: Mapped[bool] = mapped_column(nullable=False, server_default='0')
|
||||
is_deleted: Mapped[bool] = mapped_column(nullable=False, server_default='0')
|
||||
|
||||
role_key: Mapped[int] = mapped_column(ForeignKey('roles.key'))
|
||||
role: Mapped["Role"] = relationship(
|
||||
'Role',
|
||||
lazy='joined'
|
||||
)
|
||||
|
||||
position: Mapped["Position"] = relationship(
|
||||
'Position',
|
||||
secondary=user_position,
|
||||
uselist=False,
|
||||
back_populates='users',
|
||||
lazy="joined"
|
||||
)
|
||||
|
||||
|
||||
class Position(BaseModel):
|
||||
__tablename__ = 'positions'
|
||||
key: Mapped[str] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column()
|
||||
|
||||
users: Mapped["User"] = relationship(
|
||||
'User',
|
||||
secondary=user_position,
|
||||
uselist=False,
|
||||
back_populates='position'
|
||||
)
|
||||
|
||||
@@ -5,3 +5,6 @@ from .service import service_router
|
||||
from .product import product_router
|
||||
from .barcode import barcode_router
|
||||
from .shipping_warehouse import shipping_warehouse_router
|
||||
from .position import position_router
|
||||
from .user import user_router
|
||||
from .role import role_router
|
||||
|
||||
33
routers/position.py
Normal file
33
routers/position.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from schemas.position import *
|
||||
from services.position import PositionService
|
||||
|
||||
position_router = APIRouter(
|
||||
prefix="/position",
|
||||
tags=["position"]
|
||||
)
|
||||
|
||||
|
||||
@position_router.get(
|
||||
'/get-all',
|
||||
operation_id='get_all_positions',
|
||||
response_model=GetAllPositionsResponse
|
||||
)
|
||||
async def get_all(
|
||||
session: SessionDependency
|
||||
):
|
||||
return await PositionService(session).get_all()
|
||||
|
||||
|
||||
@position_router.post(
|
||||
'/create',
|
||||
operation_id='create_position',
|
||||
response_model=CreatePositionResponse
|
||||
)
|
||||
async def create(
|
||||
session: SessionDependency,
|
||||
request: CreatePositionRequest
|
||||
):
|
||||
return await PositionService(session).create(request)
|
||||
@@ -1,18 +1,16 @@
|
||||
import base64
|
||||
from io import BytesIO
|
||||
from typing import Annotated, Union
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, UploadFile
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from starlette.responses import StreamingResponse
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
import utils.dependecies
|
||||
from backend.session import get_session
|
||||
from schemas.barcode import GetProductBarcodeResponse, GetProductBarcodeRequest, GetProductBarcodePdfResponse, \
|
||||
GetProductBarcodePdfRequest
|
||||
from schemas.base import PaginationSchema
|
||||
from schemas.product import *
|
||||
from services.auth import get_current_user
|
||||
from services.barcode import BarcodeService
|
||||
from services.product import ProductService
|
||||
|
||||
|
||||
21
routers/role.py
Normal file
21
routers/role.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from schemas.role import *
|
||||
from services.role import RoleService
|
||||
|
||||
role_router = APIRouter(
|
||||
prefix='/role',
|
||||
tags=['role']
|
||||
)
|
||||
|
||||
|
||||
@role_router.get(
|
||||
'/get-all',
|
||||
response_model=GetAllRolesResponse,
|
||||
operation_id='get_all_roles'
|
||||
)
|
||||
async def get_all(
|
||||
session: SessionDependency
|
||||
):
|
||||
return await RoleService(session).get_all()
|
||||
33
routers/user.py
Normal file
33
routers/user.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from schemas.user import *
|
||||
from services.user import UserService
|
||||
|
||||
user_router = APIRouter(
|
||||
prefix="/user",
|
||||
tags=["user"]
|
||||
)
|
||||
|
||||
|
||||
@user_router.get(
|
||||
'/get-all',
|
||||
response_model=GetAllUsersResponse,
|
||||
operation_id='get_all_users'
|
||||
)
|
||||
async def get_all(
|
||||
session: SessionDependency
|
||||
):
|
||||
return await UserService(session).get_all()
|
||||
|
||||
|
||||
@user_router.post(
|
||||
'/update',
|
||||
response_model=UpdateUserResponse,
|
||||
operation_id='update_user'
|
||||
)
|
||||
async def update(
|
||||
session: SessionDependency,
|
||||
request: UpdateUserRequest
|
||||
):
|
||||
return await UserService(session).update(request)
|
||||
@@ -1,4 +1,4 @@
|
||||
from schemas.base import CustomModelCamel, CustomModelSnake
|
||||
from schemas.base import BaseSchema, CustomModelSnake
|
||||
|
||||
|
||||
class AuthLoginRequest(CustomModelSnake):
|
||||
@@ -9,5 +9,5 @@ class AuthLoginRequest(CustomModelSnake):
|
||||
photo_url: str
|
||||
|
||||
|
||||
class AuthLoginResponse(CustomModelCamel):
|
||||
class AuthLoginResponse(BaseSchema):
|
||||
access_token: str
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
from typing import List
|
||||
|
||||
from schemas.base import CustomModelCamel, OkMessageSchema
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
class BarcodeTemplateAttributeSchema(CustomModelCamel):
|
||||
class BarcodeTemplateAttributeSchema(BaseSchema):
|
||||
id: int
|
||||
key: str
|
||||
name: str
|
||||
|
||||
|
||||
class BarcodeTemplateSizeSchema(CustomModelCamel):
|
||||
class BarcodeTemplateSizeSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
key: str
|
||||
@@ -18,12 +18,12 @@ class BarcodeTemplateSizeSchema(CustomModelCamel):
|
||||
height: int
|
||||
|
||||
|
||||
class BarcodeTemplateAdditionalAttributeSchema(CustomModelCamel):
|
||||
class BarcodeTemplateAdditionalAttributeSchema(BaseSchema):
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
class BaseBarcodeTemplateSchema(CustomModelCamel):
|
||||
class BaseBarcodeTemplateSchema(BaseSchema):
|
||||
name: str
|
||||
is_default: bool
|
||||
size: BarcodeTemplateSizeSchema
|
||||
@@ -36,12 +36,12 @@ class BarcodeTemplateSchema(BaseBarcodeTemplateSchema):
|
||||
attributes: list[BarcodeTemplateAttributeSchema]
|
||||
|
||||
|
||||
class BarcodeAttributeSchema(CustomModelCamel):
|
||||
class BarcodeAttributeSchema(BaseSchema):
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
class BarcodeSchema(CustomModelCamel):
|
||||
class BarcodeSchema(BaseSchema):
|
||||
barcode: str
|
||||
attributes: List[BarcodeAttributeSchema]
|
||||
additional_field: str | None = None
|
||||
@@ -50,7 +50,7 @@ class BarcodeSchema(CustomModelCamel):
|
||||
# endregion
|
||||
|
||||
# region Requests
|
||||
class GetBarcodeTemplateByIdRequest(CustomModelCamel):
|
||||
class GetBarcodeTemplateByIdRequest(BaseSchema):
|
||||
id: int
|
||||
|
||||
|
||||
@@ -62,16 +62,16 @@ class BarcodeTemplateUpdateResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
class CreateBarcodeTemplateAttributeRequest(CustomModelCamel):
|
||||
class CreateBarcodeTemplateAttributeRequest(BaseSchema):
|
||||
name: str
|
||||
label: str
|
||||
|
||||
|
||||
class BarcodeTemplateDeleteRequest(CustomModelCamel):
|
||||
class BarcodeTemplateDeleteRequest(BaseSchema):
|
||||
id: int
|
||||
|
||||
|
||||
class GetProductBarcodeRequest(CustomModelCamel):
|
||||
class GetProductBarcodeRequest(BaseSchema):
|
||||
product_id: int
|
||||
barcode: str
|
||||
barcode_template_id: int | None = None
|
||||
@@ -84,7 +84,7 @@ class GetProductBarcodePdfRequest(GetProductBarcodeRequest):
|
||||
# endregion
|
||||
|
||||
# region Responses
|
||||
class GetBarcodeTemplateByIdResponse(CustomModelCamel):
|
||||
class GetBarcodeTemplateByIdResponse(BaseSchema):
|
||||
barcode_template: BarcodeTemplateSchema
|
||||
|
||||
|
||||
@@ -101,11 +101,11 @@ class CreateBarcodeTemplateAttributeResponse(OkMessageSchema):
|
||||
id: int
|
||||
|
||||
|
||||
class GetAllBarcodeTemplatesResponse(CustomModelCamel):
|
||||
class GetAllBarcodeTemplatesResponse(BaseSchema):
|
||||
templates: list[BarcodeTemplateSchema]
|
||||
|
||||
|
||||
class GetAllBarcodeTemplateAttributesResponse(CustomModelCamel):
|
||||
class GetAllBarcodeTemplateAttributesResponse(BaseSchema):
|
||||
attributes: list[BarcodeTemplateAttributeSchema]
|
||||
|
||||
|
||||
@@ -113,15 +113,15 @@ class BarcodeTemplateDeleteResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
class GetProductBarcodeResponse(CustomModelCamel):
|
||||
class GetProductBarcodeResponse(BaseSchema):
|
||||
barcode: BarcodeSchema
|
||||
|
||||
|
||||
class GetAllBarcodeTemplateSizesResponse(CustomModelCamel):
|
||||
class GetAllBarcodeTemplateSizesResponse(BaseSchema):
|
||||
sizes: list[BarcodeTemplateSizeSchema]
|
||||
|
||||
|
||||
class GetProductBarcodePdfResponse(CustomModelCamel):
|
||||
class GetProductBarcodePdfResponse(BaseSchema):
|
||||
base64_string: str
|
||||
filename: str
|
||||
mime_type: str
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Self
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
@@ -7,44 +9,52 @@ class CustomConfig:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CustomModelCamel(BaseModel):
|
||||
class BaseSchema(BaseModel):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
alias_generator = to_camel
|
||||
populate_by_name = True
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_sql_model(cls, model, fields: dict):
|
||||
model_dict = {c.name: getattr(model, c.name) for c in model.__table__.columns}
|
||||
model_dict.update(fields)
|
||||
return cls(**model_dict)
|
||||
|
||||
def model_dump_parent(self):
|
||||
parent_class: BaseModel = self.__class__.__bases__[0]
|
||||
parent_fields = set(parent_class.model_fields.keys())
|
||||
return self.model_dump(include=parent_fields)
|
||||
|
||||
@classmethod
|
||||
def from_orm_list(cls, sql_models) -> list[Self]:
|
||||
return [cls.model_validate(model) for model in sql_models]
|
||||
|
||||
|
||||
class CustomModelSnake(BaseModel):
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class OkMessageSchema(CustomModelCamel):
|
||||
class OkMessageSchema(BaseSchema):
|
||||
ok: bool
|
||||
message: str
|
||||
|
||||
|
||||
class PaginationSchema(CustomModelCamel):
|
||||
class PaginationSchema(BaseSchema):
|
||||
page: int | None = None
|
||||
items_per_page: int | None = None
|
||||
|
||||
|
||||
class PaginationInfoSchema(CustomModelCamel):
|
||||
class PaginationInfoSchema(BaseSchema):
|
||||
total_pages: int
|
||||
total_items: int
|
||||
|
||||
|
||||
class BaseEnumSchema(CustomModelCamel):
|
||||
class BaseEnumSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class BaseEnumListSchema(CustomModelCamel):
|
||||
class BaseEnumListSchema(BaseSchema):
|
||||
items: list[BaseEnumSchema]
|
||||
|
||||
@@ -3,11 +3,11 @@ from typing import List
|
||||
from pydantic import field_validator
|
||||
|
||||
from schemas.barcode import BarcodeTemplateSchema
|
||||
from schemas.base import CustomModelCamel, OkMessageSchema
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
class ClientDetailsSchema(CustomModelCamel):
|
||||
class ClientDetailsSchema(BaseSchema):
|
||||
telegram: str | None = None
|
||||
phone_number: str | None = None
|
||||
inn: str | None = None
|
||||
@@ -18,7 +18,7 @@ class ClientDetailsSchema(CustomModelCamel):
|
||||
return '' if v is None else v
|
||||
|
||||
|
||||
class ClientSchema(CustomModelCamel):
|
||||
class ClientSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
company_name: str
|
||||
@@ -29,39 +29,39 @@ class ClientSchema(CustomModelCamel):
|
||||
# endregion
|
||||
|
||||
# region Requests
|
||||
class ClientSearchRequest(CustomModelCamel):
|
||||
class ClientSearchRequest(BaseSchema):
|
||||
name: str
|
||||
|
||||
|
||||
class ClientUpdateDetailsRequest(CustomModelCamel):
|
||||
class ClientUpdateDetailsRequest(BaseSchema):
|
||||
client_id: int
|
||||
details: ClientDetailsSchema
|
||||
|
||||
|
||||
class ClientCreateRequest(CustomModelCamel):
|
||||
class ClientCreateRequest(BaseSchema):
|
||||
data: ClientSchema
|
||||
|
||||
|
||||
class ClientUpdateRequest(CustomModelCamel):
|
||||
class ClientUpdateRequest(BaseSchema):
|
||||
data: ClientSchema
|
||||
|
||||
|
||||
class ClientDeleteRequest(CustomModelCamel):
|
||||
class ClientDeleteRequest(BaseSchema):
|
||||
client_id: int
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Responses
|
||||
class ClientSearchResponse(CustomModelCamel):
|
||||
class ClientSearchResponse(BaseSchema):
|
||||
clients: List[ClientSchema]
|
||||
|
||||
|
||||
class ClientUpdateDetailsResponse(CustomModelCamel):
|
||||
class ClientUpdateDetailsResponse(BaseSchema):
|
||||
ok: bool
|
||||
|
||||
|
||||
class ClientGetAllResponse(CustomModelCamel):
|
||||
class ClientGetAllResponse(BaseSchema):
|
||||
clients: List[ClientSchema]
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import datetime
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from pydantic import constr
|
||||
from pydantic import constr, field_validator
|
||||
|
||||
from schemas.base import CustomModelCamel, OkMessageSchema
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
from schemas.client import ClientSchema
|
||||
from schemas.product import ProductSchema
|
||||
from schemas.service import ServiceSchema
|
||||
@@ -12,14 +12,14 @@ from schemas.user import UserSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
class FastDeal(CustomModelCamel):
|
||||
class FastDeal(BaseSchema):
|
||||
name: str
|
||||
client: ClientSchema
|
||||
comment: str
|
||||
acceptance_date: datetime.datetime
|
||||
|
||||
|
||||
class DealSummary(CustomModelCamel):
|
||||
class DealSummary(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
client_name: str
|
||||
@@ -30,24 +30,24 @@ class DealSummary(CustomModelCamel):
|
||||
rank: int
|
||||
|
||||
|
||||
class DealServiceSchema(CustomModelCamel):
|
||||
class DealServiceSchema(BaseSchema):
|
||||
service: ServiceSchema
|
||||
quantity: int
|
||||
price: int
|
||||
|
||||
|
||||
class DealProductServiceSchema(CustomModelCamel):
|
||||
class DealProductServiceSchema(BaseSchema):
|
||||
service: ServiceSchema
|
||||
price: int
|
||||
|
||||
|
||||
class DealProductSchema(CustomModelCamel):
|
||||
class DealProductSchema(BaseSchema):
|
||||
product: ProductSchema
|
||||
services: List[DealProductServiceSchema]
|
||||
quantity: int
|
||||
|
||||
|
||||
class DealStatusHistorySchema(CustomModelCamel):
|
||||
class DealStatusHistorySchema(BaseSchema):
|
||||
user: UserSchema
|
||||
changed_at: datetime.datetime
|
||||
from_status: int
|
||||
@@ -56,7 +56,7 @@ class DealStatusHistorySchema(CustomModelCamel):
|
||||
comment: str | None = None
|
||||
|
||||
|
||||
class DealSchema(CustomModelCamel):
|
||||
class DealSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
client_id: int
|
||||
@@ -69,29 +69,30 @@ class DealSchema(CustomModelCamel):
|
||||
is_completed: bool
|
||||
client: ClientSchema
|
||||
comment: str
|
||||
shipping_warehouse: Optional[ShippingWarehouseSchema] = None
|
||||
shipping_warehouse: Optional[Union[ShippingWarehouseSchema, str]] = None
|
||||
|
||||
|
||||
class DealGeneralInfoSchema(CustomModelCamel):
|
||||
class DealGeneralInfoSchema(BaseSchema):
|
||||
name: str
|
||||
is_deleted: bool
|
||||
is_completed: bool
|
||||
comment: str
|
||||
shipping_warehouse: Optional[str] = None
|
||||
|
||||
|
||||
# endregion Entities
|
||||
|
||||
# region Requests
|
||||
class DealChangeStatusRequest(CustomModelCamel):
|
||||
class DealChangeStatusRequest(BaseSchema):
|
||||
deal_id: int
|
||||
new_status: int
|
||||
|
||||
|
||||
class DealCreateRequest(CustomModelCamel):
|
||||
class DealCreateRequest(BaseSchema):
|
||||
name: str
|
||||
|
||||
|
||||
class DealQuickCreateRequest(CustomModelCamel):
|
||||
class DealQuickCreateRequest(BaseSchema):
|
||||
name: constr(strip_whitespace=True)
|
||||
client_name: constr(strip_whitespace=True)
|
||||
comment: str
|
||||
@@ -99,70 +100,70 @@ class DealQuickCreateRequest(CustomModelCamel):
|
||||
shipping_warehouse: constr(strip_whitespace=True)
|
||||
|
||||
|
||||
class DealSummaryRequest(CustomModelCamel):
|
||||
class DealSummaryRequest(BaseSchema):
|
||||
pass
|
||||
|
||||
|
||||
class DealAddServicesRequest(CustomModelCamel):
|
||||
class DealAddServicesRequest(BaseSchema):
|
||||
deal_id: int
|
||||
services: list[DealServiceSchema]
|
||||
|
||||
|
||||
class DealUpdateServiceQuantityRequest(CustomModelCamel):
|
||||
class DealUpdateServiceQuantityRequest(BaseSchema):
|
||||
deal_id: int
|
||||
service_id: int
|
||||
quantity: int
|
||||
|
||||
|
||||
class DealUpdateServiceRequest(CustomModelCamel):
|
||||
class DealUpdateServiceRequest(BaseSchema):
|
||||
deal_id: int
|
||||
service: DealServiceSchema
|
||||
|
||||
|
||||
class DealAddServiceRequest(CustomModelCamel):
|
||||
class DealAddServiceRequest(BaseSchema):
|
||||
deal_id: int
|
||||
service_id: int
|
||||
quantity: int
|
||||
price: int
|
||||
|
||||
|
||||
class DealDeleteServiceRequest(CustomModelCamel):
|
||||
class DealDeleteServiceRequest(BaseSchema):
|
||||
deal_id: int
|
||||
service_id: int
|
||||
|
||||
|
||||
class DealDeleteServicesRequest(CustomModelCamel):
|
||||
class DealDeleteServicesRequest(BaseSchema):
|
||||
deal_id: int
|
||||
service_ids: List[int]
|
||||
|
||||
|
||||
class DealUpdateProductQuantityRequest(CustomModelCamel):
|
||||
class DealUpdateProductQuantityRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
quantity: int
|
||||
|
||||
|
||||
class DealAddProductRequest(CustomModelCamel):
|
||||
class DealAddProductRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product: DealProductSchema
|
||||
|
||||
|
||||
class DealDeleteProductRequest(CustomModelCamel):
|
||||
class DealDeleteProductRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
|
||||
|
||||
class DealDeleteProductsRequest(CustomModelCamel):
|
||||
class DealDeleteProductsRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product_ids: List[int]
|
||||
|
||||
|
||||
class DealUpdateGeneralInfoRequest(CustomModelCamel):
|
||||
class DealUpdateGeneralInfoRequest(BaseSchema):
|
||||
deal_id: int
|
||||
data: DealGeneralInfoSchema
|
||||
|
||||
|
||||
class DealSummaryReorderRequest(CustomModelCamel):
|
||||
class DealSummaryReorderRequest(BaseSchema):
|
||||
deal_id: int
|
||||
status: int
|
||||
index: int
|
||||
@@ -170,11 +171,11 @@ class DealSummaryReorderRequest(CustomModelCamel):
|
||||
comment: str | None = None
|
||||
|
||||
|
||||
class DealDeleteRequest(CustomModelCamel):
|
||||
class DealDeleteRequest(BaseSchema):
|
||||
deal_id: int
|
||||
|
||||
|
||||
class DealUpdateProductRequest(CustomModelCamel):
|
||||
class DealUpdateProductRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product: DealProductSchema
|
||||
|
||||
@@ -190,32 +191,32 @@ class DealDeleteServicesResponse(OkMessageSchema):
|
||||
pass
|
||||
|
||||
|
||||
class DealGetAllResponse(CustomModelCamel):
|
||||
class DealGetAllResponse(BaseSchema):
|
||||
deals: List[DealSchema]
|
||||
|
||||
|
||||
class DealChangeStatusResponse(CustomModelCamel):
|
||||
class DealChangeStatusResponse(BaseSchema):
|
||||
ok: bool
|
||||
|
||||
|
||||
class DealCreateResponse(CustomModelCamel):
|
||||
class DealCreateResponse(BaseSchema):
|
||||
ok: bool
|
||||
|
||||
|
||||
class DealQuickCreateResponse(CustomModelCamel):
|
||||
class DealQuickCreateResponse(BaseSchema):
|
||||
deal_id: int
|
||||
|
||||
|
||||
class DealSummaryResponse(CustomModelCamel):
|
||||
class DealSummaryResponse(BaseSchema):
|
||||
summaries: List[DealSummary]
|
||||
|
||||
|
||||
class DealAddServicesResponse(CustomModelCamel):
|
||||
class DealAddServicesResponse(BaseSchema):
|
||||
ok: bool
|
||||
message: str
|
||||
|
||||
|
||||
class DealUpdateServiceQuantityResponse(CustomModelCamel):
|
||||
class DealUpdateServiceQuantityResponse(BaseSchema):
|
||||
ok: bool
|
||||
message: str
|
||||
|
||||
|
||||
20
schemas/position.py
Normal file
20
schemas/position.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from typing import List
|
||||
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
|
||||
|
||||
class PositionSchema(BaseSchema):
|
||||
name: str
|
||||
key: str
|
||||
|
||||
|
||||
class CreatePositionRequest(BaseSchema):
|
||||
data: PositionSchema
|
||||
|
||||
|
||||
class GetAllPositionsResponse(BaseSchema):
|
||||
positions: List[PositionSchema]
|
||||
|
||||
|
||||
class CreatePositionResponse(OkMessageSchema):
|
||||
pass
|
||||
@@ -1,18 +1,18 @@
|
||||
from typing import List
|
||||
from schemas.barcode import BarcodeTemplateSchema
|
||||
from schemas.base import CustomModelCamel, PaginationInfoSchema, OkMessageSchema
|
||||
from schemas.base import BaseSchema, PaginationInfoSchema, OkMessageSchema
|
||||
from pydantic import field_validator, model_validator
|
||||
from models import ProductBarcode
|
||||
|
||||
|
||||
# region Entities
|
||||
class ProductImageSchema(CustomModelCamel):
|
||||
class ProductImageSchema(BaseSchema):
|
||||
id: int
|
||||
product_id: int
|
||||
image_url: str
|
||||
|
||||
|
||||
class BaseProductSchema(CustomModelCamel):
|
||||
class BaseProductSchema(BaseSchema):
|
||||
name: str
|
||||
article: str | None = ''
|
||||
client_id: int
|
||||
@@ -55,25 +55,25 @@ class ProductCreateRequest(BaseProductSchema):
|
||||
pass
|
||||
|
||||
|
||||
class ProductDeleteRequest(CustomModelCamel):
|
||||
class ProductDeleteRequest(BaseSchema):
|
||||
product_id: int
|
||||
|
||||
|
||||
class ProductUpdateRequest(CustomModelCamel):
|
||||
class ProductUpdateRequest(BaseSchema):
|
||||
product: ProductSchema
|
||||
|
||||
|
||||
class ProductAddBarcodeRequest(CustomModelCamel):
|
||||
class ProductAddBarcodeRequest(BaseSchema):
|
||||
product_id: int
|
||||
barcode: str
|
||||
|
||||
|
||||
class ProductDeleteBarcodeRequest(CustomModelCamel):
|
||||
class ProductDeleteBarcodeRequest(BaseSchema):
|
||||
product_id: int
|
||||
barcode: str
|
||||
|
||||
|
||||
class ProductGenerateBarcodeRequest(CustomModelCamel):
|
||||
class ProductGenerateBarcodeRequest(BaseSchema):
|
||||
product_id: int
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ class ProductCreateResponse(OkMessageSchema):
|
||||
product_id: int | None = None
|
||||
|
||||
|
||||
class ProductGetResponse(CustomModelCamel):
|
||||
class ProductGetResponse(BaseSchema):
|
||||
products: List[ProductSchema]
|
||||
pagination_info: PaginationInfoSchema
|
||||
|
||||
@@ -109,7 +109,7 @@ class ProductGenerateBarcodeResponse(OkMessageSchema):
|
||||
barcode: str
|
||||
|
||||
|
||||
class ProductExistsBarcodeResponse(CustomModelCamel):
|
||||
class ProductExistsBarcodeResponse(BaseSchema):
|
||||
exists: bool
|
||||
|
||||
|
||||
|
||||
26
schemas/role.py
Normal file
26
schemas/role.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from typing import List
|
||||
|
||||
from schemas.base import BaseSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
class PermissionSchema(BaseSchema):
|
||||
key: str
|
||||
name: str
|
||||
|
||||
|
||||
class RoleSchema(BaseSchema):
|
||||
key: str
|
||||
name: str
|
||||
permissions: List[PermissionSchema]
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Requests
|
||||
# endregion
|
||||
|
||||
# region Responses
|
||||
class GetAllRolesResponse(BaseSchema):
|
||||
roles: List[RoleSchema]
|
||||
# endregion
|
||||
@@ -1,22 +1,22 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from schemas.base import CustomModelCamel, OkMessageSchema, BaseEnumSchema
|
||||
from schemas.base import BaseSchema, OkMessageSchema, BaseEnumSchema
|
||||
|
||||
|
||||
# region Entities
|
||||
class ServicePriceRangeSchema(CustomModelCamel):
|
||||
class ServicePriceRangeSchema(BaseSchema):
|
||||
id: int | None
|
||||
from_quantity: int
|
||||
to_quantity: int
|
||||
price: float
|
||||
|
||||
|
||||
class ServiceCategorySchema(CustomModelCamel):
|
||||
class ServiceCategorySchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class ServiceSchema(CustomModelCamel):
|
||||
class ServiceSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
category: ServiceCategorySchema
|
||||
@@ -30,19 +30,19 @@ class ServiceSchema(CustomModelCamel):
|
||||
|
||||
|
||||
# region Requests
|
||||
class ServiceCreateRequest(CustomModelCamel):
|
||||
class ServiceCreateRequest(BaseSchema):
|
||||
service: ServiceSchema
|
||||
|
||||
|
||||
class ServiceCreateCategoryRequest(CustomModelCamel):
|
||||
class ServiceCreateCategoryRequest(BaseSchema):
|
||||
category: ServiceCategorySchema
|
||||
|
||||
|
||||
class ServiceUpdateRequest(CustomModelCamel):
|
||||
class ServiceUpdateRequest(BaseSchema):
|
||||
data: ServiceSchema
|
||||
|
||||
|
||||
class ServiceDeleteRequest(CustomModelCamel):
|
||||
class ServiceDeleteRequest(BaseSchema):
|
||||
service_id: int
|
||||
|
||||
|
||||
@@ -50,11 +50,11 @@ class ServiceDeleteRequest(CustomModelCamel):
|
||||
|
||||
|
||||
# region Responses
|
||||
class ServiceGetAllResponse(CustomModelCamel):
|
||||
class ServiceGetAllResponse(BaseSchema):
|
||||
services: List[ServiceSchema]
|
||||
|
||||
|
||||
class ServiceGetAllCategoriesResponse(CustomModelCamel):
|
||||
class ServiceGetAllCategoriesResponse(BaseSchema):
|
||||
categories: List[ServiceCategorySchema]
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from typing import List
|
||||
|
||||
from schemas.base import CustomModelCamel
|
||||
from schemas.base import BaseSchema
|
||||
|
||||
|
||||
class ShippingWarehouseSchema(CustomModelCamel):
|
||||
class ShippingWarehouseSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
|
||||
class GetAllShippingWarehousesResponse(CustomModelCamel):
|
||||
class GetAllShippingWarehousesResponse(BaseSchema):
|
||||
shipping_warehouses: List[ShippingWarehouseSchema]
|
||||
|
||||
@@ -1,8 +1,50 @@
|
||||
from schemas.base import CustomModelCamel
|
||||
from typing import List, Optional
|
||||
|
||||
from schemas.base import BaseSchema, OkMessageSchema
|
||||
from schemas.position import PositionSchema
|
||||
from schemas.role import RoleSchema
|
||||
|
||||
|
||||
class UserSchema(CustomModelCamel):
|
||||
# region Entities
|
||||
|
||||
|
||||
class BaseUser(BaseSchema):
|
||||
id: int
|
||||
telegram_id: int
|
||||
phone_number: str | None = None
|
||||
first_name: str
|
||||
second_name: str
|
||||
comment: str
|
||||
|
||||
is_admin: bool
|
||||
is_blocked: bool
|
||||
is_deleted: bool
|
||||
|
||||
|
||||
class UserSchema(BaseUser):
|
||||
role_key: str
|
||||
role: RoleSchema
|
||||
position: Optional[PositionSchema] = None
|
||||
|
||||
|
||||
class UserUpdate(BaseUser):
|
||||
position_key: Optional[str] = None
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Requests
|
||||
class UpdateUserRequest(BaseSchema):
|
||||
data: UserUpdate
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Responses
|
||||
class GetAllUsersResponse(BaseSchema):
|
||||
users: List[UserSchema]
|
||||
|
||||
|
||||
class UpdateUserResponse(OkMessageSchema):
|
||||
pass
|
||||
# endregion
|
||||
|
||||
@@ -10,6 +10,7 @@ from starlette import status
|
||||
import backend.config
|
||||
import constants
|
||||
from backend.session import get_session
|
||||
from enums.user import UserRole
|
||||
from models import User
|
||||
from schemas.auth import *
|
||||
from services.base import BaseService
|
||||
@@ -52,8 +53,11 @@ class AuthService(BaseService):
|
||||
|
||||
user: Union[User, None] = await self.session.scalar(select(User).where(User.telegram_id == request.id))
|
||||
if not user:
|
||||
user = User(telegram_id=request.id,
|
||||
is_admin=False)
|
||||
user = User(
|
||||
telegram_id=request.id,
|
||||
is_admin=False,
|
||||
role_key=UserRole.user
|
||||
)
|
||||
self.session.add(user)
|
||||
await self.session.commit()
|
||||
access_token = self._generate_jwt_token(user)
|
||||
|
||||
@@ -240,13 +240,21 @@ class DealService(BaseService):
|
||||
|
||||
async def update_general_info(self, request: DealUpdateGeneralInfoRequest) -> DealUpdateGeneralInfoResponse:
|
||||
try:
|
||||
deal = await self.session.scalar(select(Deal).where(Deal.id == request.deal_id))
|
||||
deal: Deal = await self.session.scalar(select(Deal).where(Deal.id == request.deal_id))
|
||||
if not deal:
|
||||
raise HTTPException(status_code=404, detail="Сделка не найдена")
|
||||
deal.name = request.data.name
|
||||
deal.comment = request.data.comment
|
||||
deal.is_deleted = request.data.is_deleted
|
||||
deal.is_completed = request.data.is_completed
|
||||
|
||||
# Updating shipping warehouse
|
||||
shipping_warehouse_service = ShippingWarehouseService(self.session)
|
||||
shipping_warehouse = await shipping_warehouse_service.get_by_name(request.data.shipping_warehouse)
|
||||
if not shipping_warehouse and request.data.shipping_warehouse:
|
||||
shipping_warehouse = await shipping_warehouse_service.create_by_name(request.data.shipping_warehouse)
|
||||
|
||||
deal.shipping_warehouse = shipping_warehouse
|
||||
await self.session.commit()
|
||||
return DealUpdateGeneralInfoResponse(ok=True, message='Данные о сделке успешно обновлены')
|
||||
except Exception as e:
|
||||
|
||||
32
services/position.py
Normal file
32
services/position.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from typing import Union
|
||||
|
||||
from sqlalchemy import select, insert
|
||||
|
||||
from models import Position
|
||||
from schemas.position import *
|
||||
from services.base import BaseService
|
||||
|
||||
|
||||
class PositionService(BaseService):
|
||||
async def get_all(self) -> GetAllPositionsResponse:
|
||||
stmt = select(Position).order_by(Position.key)
|
||||
positions = (await self.session.scalars(stmt)).all()
|
||||
positions_schemas = [PositionSchema.model_validate(position) for position in positions]
|
||||
response = GetAllPositionsResponse(positions=positions_schemas)
|
||||
return response
|
||||
|
||||
async def get_by_key(self, key: str) -> Union[Position, None]:
|
||||
stmt = select(Position).where(Position.key == key)
|
||||
return await self.session.scalar(stmt)
|
||||
|
||||
|
||||
async def create(self, request: CreatePositionRequest) -> CreatePositionResponse:
|
||||
try:
|
||||
if await self.get_by_key(request.data.key):
|
||||
return CreatePositionResponse(ok=False, message='Должность с таким ключом уже существует')
|
||||
stmt = insert(Position).values(request.data.model_dump())
|
||||
await self.session.execute(stmt)
|
||||
await self.session.commit()
|
||||
return CreatePositionResponse(ok=True, message='Должность успешно создана')
|
||||
except Exception as e:
|
||||
return CreatePositionResponse(ok=False, message=str(e))
|
||||
14
services/role.py
Normal file
14
services/role.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from sqlalchemy import select
|
||||
|
||||
from models import Role
|
||||
from schemas.role import *
|
||||
from services.base import BaseService
|
||||
|
||||
|
||||
class RoleService(BaseService):
|
||||
async def get_all(self) -> GetAllRolesResponse:
|
||||
stmt = (select(Role).order_by(Role.key))
|
||||
roles = (await self.session.scalars(stmt)).all()
|
||||
return GetAllRolesResponse(
|
||||
roles=RoleSchema.from_orm_list(roles)
|
||||
)
|
||||
47
services/user.py
Normal file
47
services/user.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from sqlalchemy import select, update, delete, insert
|
||||
|
||||
from models import User, user_position
|
||||
from services.base import BaseService
|
||||
from schemas.user import *
|
||||
|
||||
|
||||
class UserService(BaseService):
|
||||
async def get_all(self) -> GetAllUsersResponse:
|
||||
stmt = (
|
||||
select(User)
|
||||
.order_by(User.id.desc())
|
||||
# .where(User.is_deleted == False)
|
||||
)
|
||||
users = (await self.session.scalars(stmt)).all()
|
||||
users_schemas = [UserSchema.model_validate(user) for user in users]
|
||||
return GetAllUsersResponse(users=users_schemas)
|
||||
|
||||
async def get_by_id(self, user_id: int) -> Optional[User]:
|
||||
return await self.session.scalar(select(User).where(User.id == user_id))
|
||||
|
||||
async def update(self, request: UpdateUserRequest) -> UpdateUserResponse:
|
||||
try:
|
||||
if not self.get_by_id(request.data.id):
|
||||
return UpdateUserResponse(ok=False, message='Указанный пользователь не найден')
|
||||
base_fields = request.data.model_dump_parent()
|
||||
stmt = update(User).values(**base_fields).where(User.id == request.data.id)
|
||||
await self.session.execute(stmt)
|
||||
await self.session.flush()
|
||||
|
||||
# Updating position
|
||||
stmt = delete(user_position).where(user_position.c.user_id == request.data.id)
|
||||
await self.session.execute(stmt)
|
||||
await self.session.flush()
|
||||
|
||||
if not request.data.position_key:
|
||||
await self.session.commit()
|
||||
return UpdateUserResponse(ok=True, message='Пользователь успешно обновлен')
|
||||
stmt = insert(user_position).values(**{
|
||||
'user_id': request.data.id,
|
||||
'position_key': request.data.position_key
|
||||
})
|
||||
await self.session.execute(stmt)
|
||||
await self.session.commit()
|
||||
return UpdateUserResponse(ok=True, message='Пользователь успешно обновлен')
|
||||
except Exception as e:
|
||||
pass
|
||||
19
test.py
19
test.py
@@ -1,9 +1,14 @@
|
||||
import struct
|
||||
import sys
|
||||
from typing import Self
|
||||
|
||||
sys.set_int_max_str_digits(-0)
|
||||
with open('Дизайн.jpg', 'rb') as rf:
|
||||
data = int.from_bytes(rf.read())
|
||||
|
||||
with open('result', 'wb') as rf:
|
||||
rf.write(data.to_bytes(length=len(str(data))))
|
||||
class A:
|
||||
@classmethod
|
||||
def test(cls) -> Self:
|
||||
return cls()
|
||||
|
||||
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
|
||||
a = B.test()
|
||||
|
||||
30
utils/init_roles.py
Normal file
30
utils/init_roles.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import asyncio
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from backend.session import session_maker
|
||||
from enums.user import UserRole
|
||||
from models import Role
|
||||
|
||||
|
||||
async def main():
|
||||
role_name_dictionary = {
|
||||
UserRole.admin: "Админ",
|
||||
UserRole.user: "Базовый пользователь",
|
||||
UserRole.manager: "Менеджер",
|
||||
UserRole.employee: "Сотрудник",
|
||||
}
|
||||
session: AsyncSession = session_maker()
|
||||
for key, name in role_name_dictionary.items():
|
||||
role = Role(
|
||||
key=key,
|
||||
name=name
|
||||
)
|
||||
session.add(role)
|
||||
await session.commit()
|
||||
await session.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main())
|
||||
Reference in New Issue
Block a user