From fcaa7fe17723727610a9aced001e9edd4b3af755 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Sat, 25 Oct 2025 18:00:05 +0400 Subject: [PATCH] feat: modules creation --- models/__init__.py | 1 + models/module.py | 2 +- repositories/module.py | 50 ++++++++++++++++++++++++++++++++-------- routers/crm/v1/module.py | 13 ++++++++++- schemas/module.py | 15 +++++++++++- services/module.py | 3 ++- 6 files changed, 71 insertions(+), 13 deletions(-) diff --git a/models/__init__.py b/models/__init__.py index 09baca7..fdf3fa4 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -19,6 +19,7 @@ from .deal_tag import ( ) from .module import ( # noqa: F401 Module as Module, + ModuleTab as ModuleTab, project_module as project_module, module_dependencies as module_dependencies, ) diff --git a/models/module.py b/models/module.py index 8c3b264..4221fbf 100644 --- a/models/module.py +++ b/models/module.py @@ -84,6 +84,6 @@ class ModuleTab(BaseModel): id: Mapped[int] = mapped_column(primary_key=True) key: Mapped[str] = mapped_column(unique=True) label: Mapped[str] = mapped_column() - icon_name: Mapped[str] = mapped_column() + icon_name: Mapped[Optional[str]] = mapped_column() module_id: Mapped[int] = mapped_column(ForeignKey("modules.id")) device: Mapped[DeviceType] = mapped_column(default=DeviceType.BOTH) diff --git a/repositories/module.py b/repositories/module.py index 8a51fdd..09e0369 100644 --- a/repositories/module.py +++ b/repositories/module.py @@ -1,17 +1,16 @@ -from sqlalchemy import and_ +import uuid + +from sqlalchemy import and_, or_ from sqlalchemy.orm import selectinload -from models import Module, Attribute, AttributeLabel, module_attribute +from models import Module, Attribute, AttributeLabel, module_attribute, ModuleTab +from models.module import DeviceType from repositories.mixins import * -from schemas.module import UpdateModuleCommonInfoSchema +from schemas.module import UpdateModuleCommonInfoSchema, CreateModuleSchema class ModuleRepository( - BaseRepository, - RepGetAllMixin[Module], - RepGetByIdMixin[Module], - RepUpdateMixin[Module, UpdateModuleCommonInfoSchema], - RepDeleteMixin[Module] + RepCrudMixin[Module, CreateModuleSchema, UpdateModuleCommonInfoSchema] ): entity_class = Module @@ -43,7 +42,10 @@ class ModuleRepository( ), isouter=True, ) - .where(Module.is_deleted.is_(False), Attribute.is_deleted.is_(False)) + .where( + Module.is_deleted.is_(False), + or_(Attribute.id.is_(None), Attribute.is_deleted.is_(False)), + ) .order_by(Attribute.id) ) @@ -60,6 +62,36 @@ class ModuleRepository( stmt = stmt.where(Module.id == pk) return (await self.session.execute(stmt)).unique().all() + async def _prepare_create(self, data: CreateSchemaType) -> dict: + dump = data.model_dump() + dump["key"] = str(uuid.uuid4()) + return dump + + async def _after_create(self, module: Module, _) -> None: + tab = ModuleTab( + key=module.key, + label=module.label, + icon_name=None, + module_id=module.id, + device=DeviceType.BOTH, + ) + self.session.add(tab) + + async def get_module_tabs_by_module_id(self, module_id: int) -> list[ModuleTab]: + stmt = select(ModuleTab).where(ModuleTab.module_id == module_id) + result = await self.session.scalars(stmt) + return list(result.all()) + + async def update( + self, module: Module, data: UpdateModuleCommonInfoSchema + ) -> Module: + tabs = await self.get_module_tabs_by_module_id(module.id) + for tab in tabs: + tab.label = data.label + self.session.add(tab) + + return await self._apply_update_data_to_model(module, data, True) + async def add_attribute_to_module(self, module: Module, attribute: Attribute): module.attributes.append(attribute) await self.session.commit() diff --git a/routers/crm/v1/module.py b/routers/crm/v1/module.py index a4f3e35..bf5c33d 100644 --- a/routers/crm/v1/module.py +++ b/routers/crm/v1/module.py @@ -41,6 +41,18 @@ async def get_module_with_attributes( return await ModuleService(session).get_by_id_with_attributes(pk) +@router.post( + "/", + response_model=CreateModuleResponse, + operation_id="create_module", +) +async def create_module( + session: SessionDependency, + request: CreateModuleRequest, +): + return await ModuleService(session).create(request) + + @router.patch( "/{pk}/common-info", response_model=UpdateModuleCommonInfoResponse, @@ -66,7 +78,6 @@ async def delete_module( return await ModuleService(session).delete(pk) - @router.post( "/attribute", response_model=AddAttributeResponse, diff --git a/schemas/module.py b/schemas/module.py index 59807e0..10428ba 100644 --- a/schemas/module.py +++ b/schemas/module.py @@ -11,7 +11,7 @@ class ModuleTabSchema(BaseSchema): id: int key: str label: str - icon_name: str + icon_name: Optional[str] device: str @@ -29,6 +29,11 @@ class ModuleWithAttributesSchema(ModuleSchema): attributes: list[ModuleAttributeSchema] +class CreateModuleSchema(BaseSchema): + label: str + description: Optional[str] + + class UpdateModuleCommonInfoSchema(BaseSchema): label: str description: Optional[str] @@ -50,6 +55,10 @@ class DeleteAttributeRequest(BaseSchema): module_id: int +class CreateModuleRequest(BaseSchema): + entity: CreateModuleSchema + + class UpdateModuleCommonInfoRequest(BaseSchema): entity: UpdateModuleCommonInfoSchema @@ -71,6 +80,10 @@ class GetByIdWithAttributesResponse(BaseSchema): entity: ModuleWithAttributesSchema +class CreateModuleResponse(BaseResponse): + pass + + class UpdateModuleCommonInfoResponse(BaseResponse): pass diff --git a/services/module.py b/services/module.py index a3f566d..1f0bedc 100644 --- a/services/module.py +++ b/services/module.py @@ -7,6 +7,7 @@ from utils.exceptions import ForbiddenException class ModuleService( ServiceGetAllMixin[Module, ModuleSchema], + ServiceCreateMixin[Module, CreateModuleRequest, ModuleSchema], ServiceUpdateMixin[Module, UpdateModuleCommonInfoRequest], ServiceDeleteMixin[Module], ): @@ -34,7 +35,7 @@ class ModuleService( self, module_id: int, request: UpdateModuleCommonInfoRequest ) -> UpdateModuleCommonInfoResponse: module = await self.repository.get_by_id(module_id) - await self.repository.update_(module, request) + await self.repository.update(module, request) return UpdateModuleCommonInfoResponse(message="Данные модуля успешно сохранены") def _build_modules_with_attributes(