feat: assignment of employees to deals

This commit is contained in:
2024-12-20 00:27:26 +04:00
parent a791f7edf8
commit c65ca39d08
5 changed files with 119 additions and 3 deletions

View File

@@ -9,7 +9,7 @@ from models.work_shifts import WorkShift
if TYPE_CHECKING: if TYPE_CHECKING:
from models.payroll import PayRate, PaymentRecord from models.payroll import PayRate, PaymentRecord
from models import Deal from models import Deal, Assignment
role_permissions = Table( role_permissions = Table(
'role_permissions', 'role_permissions',
@@ -121,6 +121,11 @@ class User(BaseModel):
cascade="all, delete-orphan" cascade="all, delete-orphan"
) )
assignments: Mapped[list['Assignment']] = relationship(
back_populates='user',
lazy='selectin'
)
class Position(BaseModel): class Position(BaseModel):
__tablename__ = 'positions' __tablename__ = 'positions'

View File

@@ -108,6 +108,8 @@ class Deal(BaseModel):
pallets: Mapped[list[Pallet]] = relationship(back_populates='deal', lazy='selectin') pallets: Mapped[list[Pallet]] = relationship(back_populates='deal', lazy='selectin')
boxes: Mapped[list[Box]] = relationship(back_populates='deal', lazy='selectin') boxes: Mapped[list[Box]] = relationship(back_populates='deal', lazy='selectin')
assignments: Mapped[list['Assignment']] = relationship(back_populates='deal', lazy='selectin')
class DealStatusHistory(BaseModel): class DealStatusHistory(BaseModel):
__tablename__ = 'deals_status_history' __tablename__ = 'deals_status_history'
@@ -126,3 +128,14 @@ class DealStatusHistory(BaseModel):
next_status_deadline = Column(DateTime, next_status_deadline = Column(DateTime,
comment='Дедлайн до которого сделку нужно перевести на следующий этап') comment='Дедлайн до которого сделку нужно перевести на следующий этап')
comment = Column(String, nullable=False, comment='Коментарий', server_default='') comment = Column(String, nullable=False, comment='Коментарий', server_default='')
class Assignment(BaseModel):
__tablename__ = 'assignments'
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'), primary_key=True)
user: Mapped['User'] = relationship('User', back_populates='assignments', lazy='selectin')
deal_id: Mapped[int] = mapped_column(ForeignKey('deals.id'), primary_key=True)
deal: Mapped[Deal] = relationship('Deal', back_populates='assignments', lazy='selectin')
created_at: Mapped[datetime] = mapped_column()

View File

@@ -234,6 +234,30 @@ async def recalculate_deal_price(
return await DealService(session).recalculate_price(request) return await DealService(session).recalculate_price(request)
@deal_router.post(
'/employee',
response_model=ManageEmployeeResponse,
operation_id='manage_employee',
)
async def manage_employee(
session: SessionDependency,
request: ManageEmployeeRequest,
):
return await DealService(session).manage_employee(request)
@deal_router.get(
'/employee/available/{deal_id}',
response_model=GetAvailableEmployeesToAssignResponse,
operation_id='get_available_employees_to_assign',
)
async def get_available_employees_to_assign(
session: Annotated[AsyncSession, Depends(get_session)],
deal_id: int,
):
return await DealService(session).get_available_employees_to_assign(deal_id)
# endregion # endregion
# region Deal services # region Deal services

View File

@@ -84,6 +84,11 @@ class DealStatusHistorySchema(BaseSchema):
comment: str | None = None comment: str | None = None
class AssignmentSchema(BaseSchema):
user: UserSchema
created_at: datetime.datetime
class DealSchema(BaseSchema): class DealSchema(BaseSchema):
id: int id: int
name: str name: str
@@ -105,6 +110,7 @@ class DealSchema(BaseSchema):
manager: Optional[UserSchema] = None manager: Optional[UserSchema] = None
pallets: List[PalletSchema] = [] pallets: List[PalletSchema] = []
boxes: List[BoxSchema] = [] boxes: List[BoxSchema] = []
assignments: List[AssignmentSchema] = []
delivery_date: Optional[datetime.datetime] = None delivery_date: Optional[datetime.datetime] = None
receiving_slot_date: Optional[datetime.datetime] = None receiving_slot_date: Optional[datetime.datetime] = None
@@ -257,6 +263,12 @@ class DealRecalculatePriceRequest(BaseSchema):
deal_id: int deal_id: int
class ManageEmployeeRequest(BaseSchema):
deal_id: int
user_id: int
is_assign: bool
class DealAddToGroupRequest(BaseSchema): class DealAddToGroupRequest(BaseSchema):
deal_id: int deal_id: int
group_id: int group_id: int
@@ -389,6 +401,14 @@ class DealRecalculatePriceResponse(OkMessageSchema):
pass pass
class ManageEmployeeResponse(OkMessageSchema):
pass
class GetAvailableEmployeesToAssignResponse(BaseSchema):
employees: list[UserSchema]
class DealAddToGroupResponse(OkMessageSchema): class DealAddToGroupResponse(OkMessageSchema):
pass pass

View File

@@ -1,7 +1,7 @@
import lexorank import lexorank
from attr import dataclass from attr import dataclass
from fastapi import HTTPException from fastapi import HTTPException
from sqlalchemy import select, func, update, delete, insert from sqlalchemy import select, func, update, delete, insert, and_
from sqlalchemy.orm import joinedload, selectinload from sqlalchemy.orm import joinedload, selectinload
from starlette import status from starlette import status
@@ -339,6 +339,8 @@ class DealService(BaseService):
selectinload(Deal.boxes) selectinload(Deal.boxes)
.selectinload(Box.product) .selectinload(Box.product)
.noload(Product.barcodes), .noload(Product.barcodes),
selectinload(Deal.assignments)
.joinedload(Assignment.user),
) )
.where(Deal.id == deal_id) .where(Deal.id == deal_id)
) )
@@ -1136,7 +1138,6 @@ class DealService(BaseService):
for deal in deals: for deal in deals:
await self._recalculate_price_single(deal, services_quantity) await self._recalculate_price_single(deal, services_quantity)
async def recalculate_price(self, request: DealRecalculatePriceRequest) -> DealRecalculatePriceResponse: async def recalculate_price(self, request: DealRecalculatePriceRequest) -> DealRecalculatePriceResponse:
try: try:
deal_stmt = ( deal_stmt = (
@@ -1164,6 +1165,59 @@ class DealService(BaseService):
except Exception as e: except Exception as e:
return DealRecalculatePriceResponse(ok=False, message=str(e)) return DealRecalculatePriceResponse(ok=False, message=str(e))
async def _assign_employee(self, deal: Deal, user: User) -> tuple[bool, str]:
assigned_employee_ids = [assignment.user_id for assignment in deal.assignments]
if user.id in assigned_employee_ids:
return False, "Работник уже назначен"
assignment = Assignment(user_id=user.id, deal_id=deal.id, created_at=datetime.datetime.now())
self.session.add(assignment)
await self.session.commit()
return True, "Работник успешно назначен"
async def _unassign_employee(self, deal: Deal, user: User) -> tuple[bool, str]:
assigned_employee_ids = [assignment.user_id for assignment in deal.assignments]
if user.id not in assigned_employee_ids:
return False, "Работник еще не назначен"
stmt = delete(Assignment).where(and_(Assignment.user_id == user.id, Assignment.deal_id == deal.id))
await self.session.execute(stmt)
await self.session.commit()
return True, "Работник успешно удален"
async def manage_employee(self, request: ManageEmployeeRequest) -> ManageEmployeeResponse:
deal: Optional[Deal] = await self._get_deal_by_id(request.deal_id)
if not deal:
return ManageEmployeeResponse(ok=False, message=f"Сделка с ID {request.deal_id} не найдена")
user: Optional[User] = await self.session.get(User, request.user_id)
if not user:
return ManageEmployeeResponse(ok=False, message=f"Пользователь с ID {request.user_id} не найден")
if request.is_assign:
ok, message = await self._assign_employee(deal, user)
else:
ok, message = await self._unassign_employee(deal, user)
return ManageEmployeeResponse(ok=ok, message=message)
async def get_available_employees_to_assign(self, deal_id: int) -> GetAvailableEmployeesToAssignResponse:
assigned_users = select(Assignment.user_id).where(Assignment.deal_id == deal_id)
stmt_free_employees = (
select(User)
.where(and_(
User.is_deleted == False,
User.role_key == "employee",
User.id.not_in(assigned_users),
))
)
free_employees = (await self.session.execute(stmt_free_employees)).scalars().all()
return GetAvailableEmployeesToAssignResponse(employees=free_employees)
async def add_to_group(self, user: User, request: DealAddToGroupRequest) -> DealAddToGroupResponse: async def add_to_group(self, user: User, request: DealAddToGroupRequest) -> DealAddToGroupResponse:
try: try:
group_bill_request = await self.session.get(GroupBillRequest, request.group_id) group_bill_request = await self.session.get(GroupBillRequest, request.group_id)