From c860b101e9ad6165b748ffb90e9da5fed3ae9073 Mon Sep 17 00:00:00 2001 From: Dinesh <97143739+dinesh-aot@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:31:33 -0700 Subject: [PATCH] Latest project notification related changes (#1086) * event template import related changes * latest project notification and related changes --- ...be4d0d_state_enums_for_work_and_project.py | 53 +++++++++++ .../versions/4b5f3a264271_act_sections.py | 44 +++++++++ ...71_event_types_event_categories_actions.py | 60 +++++++++++++ epictrack-api/src/api/models/act_section.py | 7 +- epictrack-api/src/api/models/action.py | 19 ++-- .../src/api/models/event_category.py | 1 + epictrack-api/src/api/models/project.py | 20 ++++- epictrack-api/src/api/models/work.py | 16 +++- epictrack-api/src/api/models/work_phase.py | 1 + .../src/api/schemas/request/task_request.py | 5 +- .../src/api/services/action_template.py | 6 +- epictrack-api/src/api/services/event.py | 4 +- .../src/api/services/event_template.py | 12 ++- epictrack-api/src/api/services/work.py | 1 + .../001-Project_Notification.xlsx | Bin 16436 -> 32241 bytes .../src/components/shared/TrackDialog.tsx | 8 +- .../components/workPlan/event/EventForm.tsx | 85 +++++++++++------- .../workPlan/event/EventListTable.tsx | 2 +- .../event/components/ExtensionInput.tsx | 1 + epictrack-web/src/models/event.ts | 1 + 20 files changed, 290 insertions(+), 56 deletions(-) create mode 100644 epictrack-api/migrations/versions/449afdbe4d0d_state_enums_for_work_and_project.py create mode 100644 epictrack-api/migrations/versions/4b5f3a264271_act_sections.py create mode 100644 epictrack-api/migrations/versions/cff39cd2d471_event_types_event_categories_actions.py diff --git a/epictrack-api/migrations/versions/449afdbe4d0d_state_enums_for_work_and_project.py b/epictrack-api/migrations/versions/449afdbe4d0d_state_enums_for_work_and_project.py new file mode 100644 index 000000000..2e6ae09f9 --- /dev/null +++ b/epictrack-api/migrations/versions/449afdbe4d0d_state_enums_for_work_and_project.py @@ -0,0 +1,53 @@ +"""state enums for work and project + +Revision ID: 449afdbe4d0d +Revises: cff39cd2d471 +Create Date: 2023-10-24 20:43:26.313149 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '449afdbe4d0d' +down_revision = 'cff39cd2d471' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute("UPDATE event_types set name='Interregnum', event_category_id=8 where id = 11") + op.execute("CREATE TYPE projectstateenum AS ENUM('UNDER_EAC_ASSESSMENT', 'UNDER_EXEMPTION_REQUEST', 'UNDER_AMENDMENT', 'UNDER_DISPUTE_RESOLUTION', 'PRE_CONSTRUCTION', 'CONSTRUCTION', 'OPERATION', 'CARE_AND_MAINTENANCE', 'DECOMMISSION', 'UNKNOWN')") + op.execute("CREATE TYPE workstateenum AS ENUM('SUSPENDED', 'IN_PROGRESS', 'WITHDRAWN', 'TERMINATED', 'CLOSED', 'COMPLETED')") + with op.batch_alter_table('projects', schema=None) as batch_op: + batch_op.add_column(sa.Column('project_state', sa.Enum('UNDER_EAC_ASSESSMENT', 'UNDER_EXEMPTION_REQUEST', 'UNDER_AMENDMENT', 'UNDER_DISPUTE_RESOLUTION', 'PRE_CONSTRUCTION', 'CONSTRUCTION', 'OPERATION', 'CARE_AND_MAINTENANCE', 'DECOMMISSION', 'UNKNOWN', name='projectstateenum'), nullable=True)) + + with op.batch_alter_table('projects_history', schema=None) as batch_op: + batch_op.add_column(sa.Column('project_state', sa.Enum('UNDER_EAC_ASSESSMENT', 'UNDER_EXEMPTION_REQUEST', 'UNDER_AMENDMENT', 'UNDER_DISPUTE_RESOLUTION', 'PRE_CONSTRUCTION', 'CONSTRUCTION', 'OPERATION', 'CARE_AND_MAINTENANCE', 'DECOMMISSION', 'UNKNOWN', name='projectstateenum'), autoincrement=False, nullable=True)) + + with op.batch_alter_table('works', schema=None) as batch_op: + batch_op.add_column(sa.Column('work_state', sa.Enum('SUSPENDED', 'IN_PROGRESS', 'WITHDRAWN', 'TERMINATED', 'CLOSED', 'COMPLETED', name='workstateenum'), nullable=True)) + + with op.batch_alter_table('works_history', schema=None) as batch_op: + batch_op.add_column(sa.Column('work_state', sa.Enum('SUSPENDED', 'IN_PROGRESS', 'WITHDRAWN', 'TERMINATED', 'CLOSED', 'COMPLETED', name='workstateenum'), autoincrement=False, nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('works_history', schema=None) as batch_op: + batch_op.drop_column('work_state') + + with op.batch_alter_table('works', schema=None) as batch_op: + batch_op.drop_column('work_state') + + with op.batch_alter_table('projects_history', schema=None) as batch_op: + batch_op.drop_column('project_state') + + with op.batch_alter_table('projects', schema=None) as batch_op: + batch_op.drop_column('project_state') + + # ### end Alembic commands ### diff --git a/epictrack-api/migrations/versions/4b5f3a264271_act_sections.py b/epictrack-api/migrations/versions/4b5f3a264271_act_sections.py new file mode 100644 index 000000000..1667b1677 --- /dev/null +++ b/epictrack-api/migrations/versions/4b5f3a264271_act_sections.py @@ -0,0 +1,44 @@ +"""act_sections + +Revision ID: 4b5f3a264271 +Revises: 449afdbe4d0d +Create Date: 2023-10-24 21:24:14.502652 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4b5f3a264271' +down_revision = '449afdbe4d0d' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('act_sections', schema=None) as batch_op: + batch_op.add_column(sa.Column('ea_act_id', sa.Integer(), nullable=False)) + batch_op.create_foreign_key(None, 'ea_acts', ['ea_act_id'], ['id']) + + with op.batch_alter_table('act_sections_history', schema=None) as batch_op: + batch_op.add_column(sa.Column('ea_act_id', sa.Integer(), autoincrement=False, nullable=False)) + batch_op.create_foreign_key(None, 'ea_acts', ['ea_act_id'], ['id']) + for sort_order, act in enumerate(["Time Limit Extension 38(1)(a)", "Time Limit Suspension 45(1)"]): + op.execute(f"INSERT INTO act_sections(name, ea_act_id, sort_order)VALUES('{act}',3,{sort_order + 1})") + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('act_sections_history', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_column('ea_act_id') + + with op.batch_alter_table('act_sections', schema=None) as batch_op: + batch_op.drop_constraint(None, type_='foreignkey') + batch_op.drop_column('ea_act_id') + + # ### end Alembic commands ### diff --git a/epictrack-api/migrations/versions/cff39cd2d471_event_types_event_categories_actions.py b/epictrack-api/migrations/versions/cff39cd2d471_event_types_event_categories_actions.py new file mode 100644 index 000000000..27eef7f02 --- /dev/null +++ b/epictrack-api/migrations/versions/cff39cd2d471_event_types_event_categories_actions.py @@ -0,0 +1,60 @@ +"""event_types, event_categories, actions + +Revision ID: cff39cd2d471 +Revises: eed10a65e3c3 +Create Date: 2023-10-24 17:59:01.979152 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'cff39cd2d471' +down_revision = 'eed10a65e3c3' +branch_labels = None +depends_on = None + +actions = [ + "SetEventDate", + "AddEvent", + "SetPhasesStatus", + "SetEventsStatus", + "SetWorkState", + "SetProjectStatus", + "LockWorkStartDate", + "SetWorkDecisionMaker", + "AddPhase", + "SetPhaseLegislation", + "CreateWork" +] + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('work_phases', schema=None) as batch_op: + batch_op.add_column(sa.Column('legislated', sa.Boolean(), nullable=True)) + + with op.batch_alter_table('work_phases_history', schema=None) as batch_op: + batch_op.add_column(sa.Column('legislated', sa.Boolean(), autoincrement=False, nullable=True)) + op.execute("TRUNCATE actions RESTART IDENTITY CASCADE") + for action in actions: + op.execute(f"INSERT INTO actions(name) VALUES('{action}')") + op.execute("INSERT INTO event_categories(name, sort_order)VALUES('Special Extension',8)") + op.execute("UPDATE event_types set name='PCP Time Limit Extension' where id = 25") + op.execute("alter sequence event_types_id_seq restart with 37") + op.execute("alter sequence event_categories_id_seq restart with 8") + op.execute("INSERT INTO event_types(name, event_category_id, sort_order) VALUES ('Date Capture', 1, 10)") + op.execute("INSERT INTO event_types(name, event_category_id, sort_order) VALUES ('Time Limit Resumption', 3, 2)") + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('work_phases_history', schema=None) as batch_op: + batch_op.drop_column('legislated') + + with op.batch_alter_table('work_phases', schema=None) as batch_op: + batch_op.drop_column('legislated') + + # ### end Alembic commands ### diff --git a/epictrack-api/src/api/models/act_section.py b/epictrack-api/src/api/models/act_section.py index 46f2beb66..9da504aa7 100644 --- a/epictrack-api/src/api/models/act_section.py +++ b/epictrack-api/src/api/models/act_section.py @@ -13,7 +13,9 @@ # limitations under the License. """Model to handle all operations related to act sections.""" -from sqlalchemy import Column, Integer, String +from sqlalchemy import Column, Integer, String, ForeignKey + +from sqlalchemy.orm import relationship from .code_table import CodeTableVersioned from .db import db @@ -26,4 +28,7 @@ class ActSection(db.Model, CodeTableVersioned): id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String()) + ea_act_id = Column(ForeignKey('ea_acts.id'), nullable=False) sort_order = Column(Integer, nullable=False) + + ea_act = relationship('EAAct', foreign_keys=[ea_act_id], lazy='select') diff --git a/epictrack-api/src/api/models/action.py b/epictrack-api/src/api/models/action.py index ec7ead214..4966b5b8c 100644 --- a/epictrack-api/src/api/models/action.py +++ b/epictrack-api/src/api/models/action.py @@ -22,14 +22,17 @@ class ActionEnum(enum.Enum): """Action enum""" - COMPLETE_CURRENT_PHASE = 1 - DISABLE_WORK_START_DATE = 2 - CLOSE_EVERYTHING = 3 - DUPLICATE_PHASE = 4 - DEACTIVATE_ALL_EVENTS = 5 - DELETE_ALL_EVENTS = 6 - CLOSE_WORK = 7 - CREATE_NEW_WORK = 8 + SET_EVENT_DATE = 1 + ADD_EVENT = 2 + SET_PHASES_STATUS = 3 + SET_EVENTS_STATUS = 4 + SET_WORK_STATE = 5 + SET_PROJECT_STATUS = 6 + LOCK_WORK_START_DATE = 7 + SET_WORK_DECISION_MAKER = 8 + ADD_PHASE = 9 + SET_PHASE_LEGISLATION = 10 + CREATE_WORK = 11 class Action(db.Model, CodeTableVersioned): diff --git a/epictrack-api/src/api/models/event_category.py b/epictrack-api/src/api/models/event_category.py index 7911940da..dc14a562c 100644 --- a/epictrack-api/src/api/models/event_category.py +++ b/epictrack-api/src/api/models/event_category.py @@ -29,6 +29,7 @@ class EventCategoryEnum(enum.Enum): PCP = 5 CALENDAR = 6 FINANCE = 7 + SPECIAL_EXTENSION = 8 class EventCategory(BaseModelVersioned): diff --git a/epictrack-api/src/api/models/project.py b/epictrack-api/src/api/models/project.py index 9916511a9..d8d7dcbab 100644 --- a/epictrack-api/src/api/models/project.py +++ b/epictrack-api/src/api/models/project.py @@ -12,14 +12,29 @@ # See the License for the specific language governing permissions and # limitations under the License. """Model to manage Project.""" - -from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer, String, Text, func +import enum +from sqlalchemy import Boolean, Column, Float, ForeignKey, Integer, String, Text, Enum, func from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import TSTZRANGE from .base_model import BaseModel, BaseModelVersioned +class ProjectStateEnum(enum.Enum): + """Enum for project state""" + + UNDER_EAC_ASSESSMENT = "UNDER_EAC_ASSESSMENT" + UNDER_EXEMPTION_REQUEST = "UNDER_EXEMPTION_REQUEST" + UNDER_AMENDMENT = "UNDER_AMENDMENT" + UNDER_DISPUTE_RESOLUTION = "UNDER_DISPUTE_RESOLUTION" + PRE_CONSTRUCTION = "PRE_CONSTRUCTION" + CONSTRUCTION = "CONSTRUCTION" + OPERATION = "OPERATION" + CARE_AND_MAINTENANCE = "CARE_AND_MAINTENANCE" + DECOMMISSION = "DECOMMISSION" + UNKNOWN = "UNKNOWN" + + class Project(BaseModelVersioned): """Model class for Project.""" @@ -37,6 +52,7 @@ class Project(BaseModelVersioned): address = Column(Text, nullable=True, default=None) fte_positions_construction = Column(Integer(), nullable=True) fte_positions_operation = Column(Integer(), nullable=True) + project_state = Column(Enum(ProjectStateEnum)) ea_certificate = Column(String(255), nullable=True, default=None) sub_type_id = Column(ForeignKey("sub_types.id"), nullable=False) diff --git a/epictrack-api/src/api/models/work.py b/epictrack-api/src/api/models/work.py index 544195f74..c746b98cb 100644 --- a/epictrack-api/src/api/models/work.py +++ b/epictrack-api/src/api/models/work.py @@ -12,13 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. """Model to handle all operations related to Work.""" - -from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Text, func +import enum +from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Text, Enum, func from sqlalchemy.orm import relationship from .base_model import BaseModelVersioned +class WorkStateEnum(enum.Enum): + """Enum for WorkState""" + + SUSPENDED = "SUSPENDED" + IN_PROGRESS = "IN_PROGRESS" + WITHDRAWN = "WITHDRAWN" + TERMINATED = "TERMINATED" + CLOSED = "CLOSED" + COMPLETED = "COMPLETED" + + class Work(BaseModelVersioned): """Model class for Work.""" @@ -56,6 +67,7 @@ class Work(BaseModelVersioned): decision_by_id = Column(ForeignKey('staffs.id'), nullable=False) start_date_locked = Column(Boolean(), default=False) decision_maker_position_id = Column(ForeignKey('positions.id'), nullable=True) + work_state = Column(Enum(WorkStateEnum), default=WorkStateEnum.IN_PROGRESS) project = relationship('Project', foreign_keys=[project_id], lazy='select') ministry = relationship('Ministry', foreign_keys=[ministry_id], lazy='select') diff --git a/epictrack-api/src/api/models/work_phase.py b/epictrack-api/src/api/models/work_phase.py index 496d2d36c..ba657a784 100644 --- a/epictrack-api/src/api/models/work_phase.py +++ b/epictrack-api/src/api/models/work_phase.py @@ -31,6 +31,7 @@ class WorkPhase(BaseModelVersioned): work_id = Column(ForeignKey('works.id'), nullable=False) phase_id = Column(ForeignKey('phase_codes.id'), nullable=False) + legislated = Column(Boolean, default=False) task_added = Column(Boolean, default=False,) number_of_days = Column(Integer, default=0) is_completed = Column(Boolean, default=False) diff --git a/epictrack-api/src/api/schemas/request/task_request.py b/epictrack-api/src/api/schemas/request/task_request.py index ace33d03f..36d6fddc1 100644 --- a/epictrack-api/src/api/schemas/request/task_request.py +++ b/epictrack-api/src/api/schemas/request/task_request.py @@ -172,7 +172,10 @@ class TaskEventBodyParamSchema(RequestBodyParameterSchema): allow_none=True, ) - notes = fields.Str(metadata={"description": "Notes for the task"}) + notes = fields.Str( + metadata={"description": "Notes for the task"}, + allow_none=True + ) assignee_ids = fields.List( fields.Int(metadata={"description": "List of assignees of the task"}) diff --git a/epictrack-api/src/api/services/action_template.py b/epictrack-api/src/api/services/action_template.py index 9b0574d94..bb21d6cd0 100644 --- a/epictrack-api/src/api/services/action_template.py +++ b/epictrack-api/src/api/services/action_template.py @@ -22,8 +22,8 @@ class ActionTemplateService: # pylint: disable=too-few-public-methods @classmethod def get_action_params(cls, action_type: ActionEnum, request_data: dict): """Return the action params for the template""" - if action_type == ActionEnum.DUPLICATE_PHASE: - return cls._get_phase_param(request_data) + if action_type == ActionEnum.ADD_EVENT: + return request_data # cls._get_phase_param(request_data) return request_data @classmethod @@ -35,6 +35,8 @@ def _get_phase_param(cls, request_data: dict) -> dict: "ea_act_id": request_data.get("ea_act_id") } result = PhaseCode.find_by_params(param) + if not result: + return {} return { "phase_id": result[0].id } diff --git a/epictrack-api/src/api/services/event.py b/epictrack-api/src/api/services/event.py index 5103d5aa1..5caf1fbb6 100644 --- a/epictrack-api/src/api/services/event.py +++ b/epictrack-api/src/api/services/event.py @@ -134,7 +134,7 @@ def _process_event( all_work_phases, current_work_phase ) current_future_work_phases = all_work_phases[current_work_phase_index:] - if current_work_phase.phase.legislated: + if current_work_phase.legislated: phase_events = list( filter( lambda x, _work_phase_id=current_work_phase.id: x.event_configuration.work_phase_id == @@ -190,7 +190,7 @@ def _process_event( event, all_work_event_configurations, ) - if not current_work_phase.phase.legislated: + if not current_work_phase.legislated: cls._push_work_phases( current_future_work_phases, all_work_events, diff --git a/epictrack-api/src/api/services/event_template.py b/epictrack-api/src/api/services/event_template.py index ab3fd2123..026f11c62 100644 --- a/epictrack-api/src/api/services/event_template.py +++ b/epictrack-api/src/api/services/event_template.py @@ -46,20 +46,24 @@ def import_events_template(cls, configuration_file): outcome_dict = excel_dict.get("Outcomes") action_dict = excel_dict.get("Actions") for event_type in event_types: - event_dict = event_dict.replace({'event_type_id': rf'^{event_type.name}$'}, + name = escape_characters(event_type.name, ['(', ')']) + event_dict = event_dict.replace({'event_type_id': rf'^{name}$'}, {'event_type_id': event_type.id}, regex=True) for event_category in event_categories: - event_dict = event_dict.replace({'event_category_id': rf'^{event_category.name}$'}, + name = escape_characters(event_category.name, ['(', ')']) + event_dict = event_dict.replace({'event_category_id': rf'^{name}$'}, {'event_category_id': event_category.id}, regex=True) for work_type in work_types: - phase_dict = phase_dict.replace({'work_type_id': rf'^{work_type.name}$'}, + name = escape_characters(work_type.name, ['(', ')']) + phase_dict = phase_dict.replace({'work_type_id': rf'^{name}$'}, {'work_type_id': work_type.id}, regex=True) for ea_act in ea_acts: name = escape_characters(ea_act.name, ['(', ')']) phase_dict = phase_dict.replace({'ea_act_id': rf'^{name}$'}, {'ea_act_id': ea_act.id}, regex=True) for action in actions: - action_dict = action_dict.replace({'action_id': rf'^{action.name}$'}, + name = escape_characters(action.name, ['(', ')']) + action_dict = action_dict.replace({'action_id': rf'^{name}$'}, {'action_id': action.id}, regex=True) event_dict = event_dict.to_dict('records') diff --git a/epictrack-api/src/api/services/work.py b/epictrack-api/src/api/services/work.py index 87c735d0e..0b887573e 100644 --- a/epictrack-api/src/api/services/work.py +++ b/epictrack-api/src/api/services/work.py @@ -131,6 +131,7 @@ def create_work(cls, payload): "phase_id": phase.id, "start_date": f"{phase_start_date}", "end_date": f"{end_date}", + "legislated": phase.legislated, "number_of_days": phase.number_of_days, } ) diff --git a/epictrack-api/src/api/templates/event_templates/project_notification/001-Project_Notification.xlsx b/epictrack-api/src/api/templates/event_templates/project_notification/001-Project_Notification.xlsx index 750aac2ad6130684d5b60a6c484057bc9bd0adcc..f357cd503c083a03dd1f86aa71a1577bb602fdef 100644 GIT binary patch delta 27236 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 = ({ color: Palette.neutral.dark, }} > - {dialogContentText} + + {dialogContentText} + )} {props.children} diff --git a/epictrack-web/src/components/workPlan/event/EventForm.tsx b/epictrack-web/src/components/workPlan/event/EventForm.tsx index 780319e2e..abbfdcbfe 100644 --- a/epictrack-web/src/components/workPlan/event/EventForm.tsx +++ b/epictrack-web/src/components/workPlan/event/EventForm.tsx @@ -72,6 +72,7 @@ const EventForm = ({ onSave, event, isFormFieldsLocked }: EventFormProps) => { const [anticipatedLabel, setAnticipatedLabel] = React.useState("Anticipated Date"); const [actualDateLabel, setActualDateLabel] = React.useState("Actual Date"); + const isCreateMode = React.useMemo(() => !event, [event]); const titleRef = React.useRef(); const schema = React.useMemo( () => @@ -100,6 +101,13 @@ const EventForm = ({ onSave, event, isFormFieldsLocked }: EventFormProps) => { then: () => yup.string().required("Please select the decision maker"), otherwise: () => yup.string().nullable(), }), + act_section_id: yup.string().when([], { + is: () => + selectedConfiguration?.event_category_id === + EventCategory.EXTENSION, + then: () => yup.string().required("Please select the act section"), + otherwise: () => yup.string().nullable(), + }), }), [selectedConfiguration, actualAdded] ); @@ -182,19 +190,21 @@ const EventForm = ({ onSave, event, isFormFieldsLocked }: EventFormProps) => { } }; - const onSubmitHandler = async (data: MilestoneEvent) => { + const onSubmitHandler = async (submittedData: MilestoneEvent) => { try { - data.anticipated_date = Moment(data.anticipated_date).format(); - if (!!data.actual_date) { - data.actual_date = Moment(data.actual_date).format(); + submittedData.anticipated_date = Moment( + submittedData.anticipated_date + ).format(); + if (!!submittedData.actual_date) { + submittedData.actual_date = Moment(submittedData.actual_date).format(); } - data.notes = notes; + submittedData.notes = notes; // setSubmittedEvent(data); const showConfirmDialog = - (event === undefined && !!data.actual_date) || - (event != null && event.actual_date == null && !!data.actual_date); + (isCreateMode && !!submittedData.actual_date) || + (!isCreateMode && !event?.actual_date && !!submittedData.actual_date); if (!showConfirmDialog) { - saveEvent(data); + saveEvent(submittedData); } setShowEventLockDialog(showConfirmDialog); } catch (e: any) { @@ -211,33 +221,44 @@ const EventForm = ({ onSave, event, isFormFieldsLocked }: EventFormProps) => { const saveEvent = React.useCallback( async (data?: MilestoneEvent) => { - const dataToBeSubmitted = data || getValues(); - if (event) { - const createResult = await eventService.update( - dataToBeSubmitted, - Number(event.id) - ); - if (createResult.status === 200) { - showNotification("Milestone details updated", { - type: "success", - }); - if (onSave) { - onSave(); + try { + const dataToBeSubmitted = data || getValues(); + if (event) { + const createResult = await eventService.update( + dataToBeSubmitted, + Number(event.id) + ); + if (createResult.status === 200) { + showNotification("Milestone details updated", { + type: "success", + }); + if (onSave) { + onSave(); + } } - } - } else { - const createResult = await eventService.create( - dataToBeSubmitted, - Number(ctx.selectedWorkPhase?.id) - ); - if (createResult.status === 201) { - showNotification("Milestone details inserted", { - type: "success", - }); - if (onSave) { - onSave(); + } else { + const createResult = await eventService.create( + dataToBeSubmitted, + Number(ctx.selectedWorkPhase?.id) + ); + if (createResult.status === 201) { + showNotification("Milestone details inserted", { + type: "success", + }); + if (onSave) { + onSave(); + } } } + } catch (e) { + const error = getAxiosError(e); + const message = + error?.response?.status === 422 + ? error.response.data?.toString() + : COMMON_ERROR_MESSAGE; + showNotification(message, { + type: "error", + }); } }, [event, submittedEvent] diff --git a/epictrack-web/src/components/workPlan/event/EventListTable.tsx b/epictrack-web/src/components/workPlan/event/EventListTable.tsx index d51102b94..c1335b516 100644 --- a/epictrack-web/src/components/workPlan/event/EventListTable.tsx +++ b/epictrack-web/src/components/workPlan/event/EventListTable.tsx @@ -407,7 +407,7 @@ const EventListTable = ({ row.original.end_date === undefined && row.original.type === EVENT_TYPE.MILESTONE, indeterminate: - row.original.end_date !== undefined && + row.original.is_complete && row.original.type === EVENT_TYPE.MILESTONE, })} columns={columns} diff --git a/epictrack-web/src/components/workPlan/event/components/ExtensionInput.tsx b/epictrack-web/src/components/workPlan/event/components/ExtensionInput.tsx index ee0080137..8d325add6 100644 --- a/epictrack-web/src/components/workPlan/event/components/ExtensionInput.tsx +++ b/epictrack-web/src/components/workPlan/event/components/ExtensionInput.tsx @@ -39,6 +39,7 @@ const ExtensionInput = (props: ExtensionInputProps) => { unregister("phase_end_date"); }; }, []); + React.useEffect(() => { let numberOfDays = Number(getValues("number_of_days")); if (numberOfDaysRef.current as any) { diff --git a/epictrack-web/src/models/event.ts b/epictrack-web/src/models/event.ts index aa37b02d9..3a18d8f5c 100644 --- a/epictrack-web/src/models/event.ts +++ b/epictrack-web/src/models/event.ts @@ -55,6 +55,7 @@ export enum EventCategory { PCP = 5, CALENDAR = 6, FINANCE = 7, + SPECIAL_EXTENSION = 8, } export enum EventType { OPEN_HOUSE = 23,