diff --git a/epictrack-api/src/api/models/staff_work_role.py b/epictrack-api/src/api/models/staff_work_role.py index 6c37c89f1..f52c71621 100644 --- a/epictrack-api/src/api/models/staff_work_role.py +++ b/epictrack-api/src/api/models/staff_work_role.py @@ -47,3 +47,28 @@ def as_dict(self): # pylint:disable=arguments-differ def find_by_work_id(cls, work_id: int): """Return by work id.""" return cls.query.filter_by(work_id=work_id) + + @classmethod + def find_by_role_and_work(cls, work_id: int, role_id): + """Return by work and role ids.""" + return cls.query.filter( + StaffWorkRole.work_id == work_id, + StaffWorkRole.role_id == role_id, + StaffWorkRole.is_deleted.is_(False), + StaffWorkRole.is_active.is_(True), + ).all() + + @classmethod + def find_by_work_and_staff_and_role(cls, work_id: int, staff_id: object, role_id: object, work_staff_id: object): + """Return by work, staff and role ids.""" + query = cls.query.filter( + StaffWorkRole.work_id == work_id, + StaffWorkRole.staff_id == staff_id, + StaffWorkRole.is_deleted.is_(False), + StaffWorkRole.role_id == role_id, + ) + + if work_staff_id: + query = query.filter(StaffWorkRole.id != work_staff_id) + + return query.all() diff --git a/epictrack-api/src/api/services/work.py b/epictrack-api/src/api/services/work.py index b4060f2a2..1525d60be 100644 --- a/epictrack-api/src/api/services/work.py +++ b/epictrack-api/src/api/services/work.py @@ -112,7 +112,7 @@ def fetch_all_work_plans( serialized_works = [] - work_staffs = WorkService.find_staff_for_works(work_ids) + work_staffs = WorkService.find_staff_for_works(work_ids, is_active=True) works_statuses = WorkStatus.list_latest_approved_statuses_for_work_ids(work_ids) work_id_phase_id_dict = {work.id: work.current_work_phase_id for work in works} work_phases = WorkPhaseService.find_multiple_works_phases_status( @@ -367,27 +367,42 @@ def check_work_staff_existence( cls, work_id: int, staff_id: int, role_id: int, work_staff_id: int = None ) -> bool: """Check the existence of staff in work""" - query = db.session.query(StaffWorkRole).filter( - StaffWorkRole.work_id == work_id, - StaffWorkRole.staff_id == staff_id, - StaffWorkRole.is_deleted.is_(False), - StaffWorkRole.role_id == role_id, - ) - if work_staff_id: - query = query.filter(StaffWorkRole.id != work_staff_id) - if query.count() > 0: + staff_work_roles = StaffWorkRole.find_by_work_and_staff_and_role( + work_id, staff_id, role_id, work_staff_id) + if staff_work_roles: return True return False + @classmethod + def check_work_staff_existence_duplication( + cls, work_id: int, staff_id: int, role_id: int, work_staff_id: int = None + ): + """Check the existence of staff in work""" + exists = cls.check_work_staff_existence( + work_id, staff_id, role_id, work_staff_id) + if exists: + raise ResourceExistsError("Staff Work association already exists") + + @classmethod + def check_valid_role_association( + cls, work_id: int, role_id: int + ): + """Check the existence of staff in work""" + if role_id != Membership.LEAD.value: + return + staff_work_roles = StaffWorkRole.find_by_role_and_work(work_id, role_id) + if staff_work_roles: + raise ResourceExistsError("This work already has a active Team Lead") + @classmethod def create_work_staff( cls, work_id: int, data: dict, commit: bool = True ) -> StaffWorkRole: """Create Staff Work""" - if cls.check_work_staff_existence( + cls.check_work_staff_existence_duplication( work_id, data.get("staff_id"), data.get("role_id") - ): - raise ResourceExistsError("Staff Work association already exists") + ) + cls.check_valid_role_association(work_id, data.get("role_id")) cls._check_can_create_or_team_member_auth(work_id) @@ -416,11 +431,11 @@ def update_work_staff( ) if not work_staff: raise ResourceNotFoundError("No staff work association found") - if cls.check_work_staff_existence( - work_staff.work_id, data.get("staff_id"), data.get("role_id"), work_staff_id - ): - raise ResourceExistsError("Staff Work association already exists") + cls.check_work_staff_existence_duplication( + work_staff.work_id, data.get("staff_id"), data.get("role_id"), work_staff_id + ) + cls.check_valid_role_association(work_staff.work_id, data.get("role_id")) cls._check_can_edit_or_team_member_auth(work_staff.work_id) work_staff.is_active = data.get("is_active") @@ -590,28 +605,10 @@ def generate_workplan( # unsupported-assignment-operation file_buffer = BytesIO() - columns = [ - "name", - "type", - "start_date", - "end_date", - "days", - "assigned", - "responsibility", - "notes", - "progress", - ] - headers = [ - "Name", - "Type", - "Start Date", - "End Date", - "Days", - "Assigned", - "Responsibility", - "Notes", - "Progress", - ] + columns = ["name", "type", "start_date", "end_date", "days", "assigned", + "responsibility", "notes", "progress"] + headers = ["Name", "Type", "Start Date", "End Date", "Days", "Assigned", + "Responsibility", "Notes", "Progress"] data.to_excel(file_buffer, index=False, columns=columns, header=headers) file_buffer.seek(0, 0) return file_buffer.getvalue() diff --git a/epictrack-web/src/components/myWorkplans/Card/CardFooter.tsx b/epictrack-web/src/components/myWorkplans/Card/CardFooter.tsx index c0a199a8b..f7126b521 100644 --- a/epictrack-web/src/components/myWorkplans/Card/CardFooter.tsx +++ b/epictrack-web/src/components/myWorkplans/Card/CardFooter.tsx @@ -1,11 +1,9 @@ +import React from "react"; import { Button, Grid } from "@mui/material"; import { Palette } from "../../../styles/theme"; -import { ETCaption1, ETCaption2, ETParagraph } from "../../shared"; -import Icons from "../../icons"; -import { IconProps } from "../../icons/type"; +import { ETCaption1, ETParagraph } from "../../shared"; import { CardProps } from "./type"; import { useNavigate } from "react-router-dom"; -import React from "react"; import StaffGroup from "./Staff/StaffGroup"; const CardFooter = ({ workplan }: CardProps) => { diff --git a/epictrack-web/src/components/workPlan/team/TeamForm.tsx b/epictrack-web/src/components/workPlan/team/TeamForm.tsx index 6b613b97a..908ffa754 100644 --- a/epictrack-web/src/components/workPlan/team/TeamForm.tsx +++ b/epictrack-web/src/components/workPlan/team/TeamForm.tsx @@ -131,40 +131,26 @@ const TeamForm = ({ onSave, workStaffId }: TeamFormProps) => { handleSubmit, formState: { errors }, reset, - control, } = methods; + const saveTeamMember = (data: StaffWorkRole) => { + if (workStaffId) { + return workService.updateWorkStaff(data, Number(workStaffId)); + } + return workService.createWorkStaff(data, Number(ctx.work?.id)); + }; + const onSubmitHandler = async (data: StaffWorkRole) => { try { - if (workStaffId) { - const createResult = await workService.updateWorkStaff( - data, - Number(workStaffId) - ); - if (createResult.status === 200) { - showNotification("Team details updated", { - type: "success", - }); - if (onSave) { - onSave(); - } - } - } else { - const createResult = await workService.createWorkStaff( - data, - Number(ctx.work?.id) - ); - if (createResult.status === 201) { - showNotification("Team details inserted", { - type: "success", - }); - if (onSave) { - onSave(); - } - } + await saveTeamMember(data); + showNotification("Team details saved", { + type: "success", + }); + if (onSave) { + onSave(); } - } catch (e: any) { - const message = getErrorMessage(e); + } catch (error: any) { + const message = getErrorMessage(error); showNotification(message, { type: "error", });