feat: attributes in cards and projects

This commit is contained in:
2025-02-27 18:34:38 +04:00
parent c6c006d45b
commit a2c9fd8e3b
16 changed files with 391 additions and 27 deletions

85
services/attribute.py Normal file
View File

@@ -0,0 +1,85 @@
from sqlalchemy import select, and_
from models import Attribute, AttributeType
from schemas.attribute import *
from services.base import BaseService
class AttributeService(BaseService):
async def get_all(self) -> GetAttributesResponse:
stmt = (
select(Attribute)
.where(Attribute.is_deleted == False)
.order_by(Attribute.label)
)
attrs = (await self.session.scalars(stmt)).all()
return GetAttributesResponse(attributes=attrs)
async def get_types(self) -> GetAttributeTypesResponse:
stmt = (
select(AttributeType)
.where(AttributeType.is_deleted == False)
)
types = (await self.session.scalars(stmt)).all()
return GetAttributeTypesResponse(types=types)
async def get_attr_by_name(self, attr_name: str) -> Optional[Attribute]:
stmt = (
select(Attribute)
.where(
and_(
Attribute.name == attr_name,
Attribute.is_deleted == False,
)
)
)
attribute = (await self.session.scalars(stmt)).first()
return attribute
async def create(self, request: CreateAttributeRequest) -> CreateAttributeResponse:
existing_attr = await self.get_attr_by_name(request.attribute.name)
if existing_attr:
return CreateAttributeResponse(ok=False, message="Атрибут с данным уникальным ключом уже существует")
default_value = pickle.dumps(request.attribute.default_value)
values = request.attribute.model_dump()
del values["default_value"]
attribute = Attribute(
**values,
default_value=default_value,
)
self.session.add(attribute)
await self.session.commit()
return CreateAttributeResponse(ok=True, message="Атрибут успешно создан")
async def update(self, request: UpdateAttributeRequest) -> UpdateAttributeResponse:
attribute = await self.session.get(Attribute, request.attribute.id)
if not attribute:
return UpdateAttributeResponse(ok=False, message=f"Атрибут с ID {request.attribute.id} не найден")
if attribute.name != request.attribute.name:
attr_with_same_name = await self.get_attr_by_name(request.attribute.name)
if attr_with_same_name:
return CreateAttributeResponse(ok=False, message="Атрибут с данным уникальным ключом уже существует")
default_value = pickle.dumps(request.attribute.default_value) if request.attribute.default_value else None
attribute.name = request.attribute.name
attribute.label = request.attribute.label
attribute.default_value = default_value
attribute.is_applicable_to_group = request.attribute.is_applicable_to_group
attribute.is_nullable = request.attribute.is_nullable
attribute.description = request.attribute.description
await self.session.commit()
return UpdateAttributeResponse(ok=True, message="Атрибут успешно обновлен")
async def delete(self, attribute_id: int) -> DeleteAttributeResponse:
attribute: Optional[Attribute] = await self.session.get(Attribute, attribute_id)
if not attribute:
return DeleteAttributeResponse(ok=False, message=f"Атрибут с ID {attribute_id} не найден")
attribute.is_deleted = True
await self.session.commit()
return DeleteAttributeResponse(ok=True, message=f"Атрибут успешно удален")

View File

@@ -356,6 +356,7 @@ class CardsService(BaseService):
card.comment = request.data.comment
card.is_deleted = request.data.is_deleted
card.is_completed = request.data.is_completed
card.client_id = request.data.client_id
if card.board_id != request.data.board_id or card.current_status_id != request.data.status_id:
if card.group:

View File

@@ -1,9 +1,11 @@
from datetime import datetime
from typing import Optional
from sqlalchemy import select, update, func, delete
from sqlalchemy.orm import selectinload
from models import Project, Board
from card_attributes import CardAttributesCommandHandler
from models import Project, Board, Module, Attribute
from schemas.project import *
from services.base import BaseService
@@ -28,6 +30,7 @@ class ProjectService(BaseService):
selectinload(Project.attributes),
selectinload(Project.modules),
)
.order_by(Project.id)
)
project_data = (await self.session.execute(stmt)).all()
@@ -81,3 +84,37 @@ class ProjectService(BaseService):
await self.session.execute(stmt)
await self.session.commit()
return DeleteProjectResponse(ok=True, message="Проект успешно удален")
async def get_all_modules(self) -> GetAllModulesResponse:
stmt = (
select(Module)
.where(Module.is_deleted == False)
)
modules = await self.session.scalars(stmt)
return GetAllModulesResponse(modules=modules.all())
async def update_project_modules(self, request: UpdateModulesRequest) -> UpdateModulesResponse:
project: Optional[Project] = await self.session.get(Project, request.project_id)
if not project:
return UpdateModulesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден")
modules_stmt = (
select(Module)
.where(Module.id.in_(request.module_ids))
)
modules = (await self.session.scalars(modules_stmt)).all()
project.modules = modules
await self.session.commit()
return UpdateModulesResponse(ok=True, message="Модули успешно обновлены")
async def update_project_attributes(self, request: UpdateAttributesRequest) -> UpdateAttributesResponse:
project: Optional[Project] = await self.session.get(Project, request.project_id)
if not project:
return UpdateAttributesResponse(ok=False, message=f"Проект с ID {request.project_id} не найден")
card_attrs_handler = CardAttributesCommandHandler(self.session)
await card_attrs_handler.set_project_attributes(project, request.attribute_ids)
return UpdateAttributesResponse(ok=True, message="Атрибуты успешно обновлены")

View File

@@ -178,7 +178,7 @@ class ResiduesService(BaseService):
pallet = ResidualPallet(client_id=client_id, created_at=datetime.now())
self.session.add(pallet)
await self.session.flush()
await self._load_receipt_boxes(receipt_pallet.boxes, pallet.id)
await self._load_receipt_boxes(receipt_pallet.boxes, None, pallet.id)
await self._load_receipt_products(receipt_pallet.products, pallet_id=pallet.id)
async def _load_receipt_products(