Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Add REQUESTED_BY_EAO package status

Revision ID: 77862b346adf
Revises: e27054af162b
Create Date: 2026-03-02 16:02:40.724455

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '77862b346adf'
down_revision = 'e27054af162b'
branch_labels = None
depends_on = None

def upgrade():
op.execute("ALTER TYPE packagestatus ADD VALUE IF NOT EXISTS 'REQUESTED_BY_EAO';")

def downgrade():
pass
3 changes: 2 additions & 1 deletion submit-api/src/submit_api/models/account_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class AccountProject(BaseModel):
primaryjoin='AccountProjectWork.account_project_id==AccountProject.id',
lazy='select',
cascade='all, delete',
passive_deletes=True)
passive_deletes=True,
back_populates='account_project')

@property
def latest_packages(self):
Expand Down
11 changes: 8 additions & 3 deletions submit-api/src/submit_api/models/account_project_work.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,21 @@ class AccountProjectWork(BaseModel):
comment='Whether this association is currently active'
)

account_project = db.relationship('AccountProject', foreign_keys=[account_project_id], lazy='joined')
account_project = db.relationship(
'AccountProject',
foreign_keys=[account_project_id],
lazy='joined',
back_populates='account_project_works')

work = db.relationship('TrackWork', foreign_keys=[work_id], lazy='joined')

packages = db.relationship(
'Package',
primaryjoin='Package.account_project_work_id==AccountProjectWork.id',
lazy='select',
cascade='all, delete',
passive_deletes=True
)
passive_deletes=True,
back_populates='account_project_work')

@classmethod
def find_by_account_project_id(cls, account_project_id: int):
Expand Down
3 changes: 2 additions & 1 deletion submit-api/src/submit_api/models/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class PackageStatus(enum.Enum):
REVISION_REQUIRED = 'REVISION_REQUIRED'
NO_REVISION_REQUIRED = 'NO_REVISION_REQUIRED'
RESUBMITTED = 'RESUBMITTED'
REQUESTED_BY_EAO = 'REQUESTED_BY_EAO'

@classmethod
def check_value(cls, value):
Expand All @@ -83,7 +84,7 @@ class Package(BaseModel):
account_project_work_id = Column(db.Integer, ForeignKey(
'account_project_works.id', ondelete='SET NULL'), nullable=True)
account_project_work = db.relationship('AccountProjectWork', foreign_keys=[
account_project_work_id], lazy='joined')
account_project_work_id], lazy='joined', back_populates='packages')
submitted_on = Column(db.DateTime, nullable=True)
submitted_by = Column(db.String, ForeignKey(
'users.auth_guid', name='packages_submitted_by_fkey'), nullable=True)
Expand Down
15 changes: 15 additions & 0 deletions submit-api/src/submit_api/schemas/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from submit_api.schemas.package import PackageSchema, StaffPackageSchema
from submit_api.schemas.proponent import ProponentSchema
from submit_api.schemas.track_work import TrackWorkSchema


class ProjectSchema(Schema):
Expand Down Expand Up @@ -48,6 +49,19 @@ class Meta: # pylint: disable=too-few-public-methods
items = fields.Function(lambda obj: [])


class AccountProjectWorkSchema(Schema):
"""Account project work schema."""

class Meta: # pylint: disable=too-few-public-methods
"""Exclude unknown fields in the deserialized output."""

unknown = EXCLUDE

id = fields.Int(data_key="id")
work_id = fields.Int(data_key="work_id")
work = fields.Nested(TrackWorkSchema, data_key="work")


class AccountProjectSchema(Schema):
"""Account project schema."""

Expand All @@ -61,6 +75,7 @@ class Meta: # pylint: disable=too-few-public-methods
project_id = fields.Int(data_key="project_id")
project = fields.Nested(ProjectSchema, data_key="project")
latest_packages = fields.List(fields.Nested(AccountProjectPackageSchema), data_key="packages")
account_project_works = fields.List(fields.Nested(AccountProjectWorkSchema, data_key="account_project_works"))


class StaffAccountProjectPackageSchema(StaffPackageSchema):
Expand Down
23 changes: 23 additions & 0 deletions submit-api/src/submit_api/schemas/track_phase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""TrackPhase schema.

This module defines the schema for the track_phase entity.
"""
from marshmallow import EXCLUDE, Schema, fields


class TrackPhaseSchema(Schema):
"""Track phase schema."""

class Meta: # pylint: disable=too-few-public-methods
"""Exclude unknown fields in the deserialized output."""

unknown = EXCLUDE

id = fields.Int(data_key="id")
name = fields.Str(data_key="name")
ea_act_id = fields.Int(data_key="ea_act_id", allow_none=True)
work_type_id = fields.Int(data_key="work_type_id")
work_type_name = fields.Str(data_key="work_type_name", allow_none=True)
sort_order = fields.Int(data_key="sort_order", allow_none=True)
number_of_days = fields.Int(data_key="number_of_days", allow_none=True)
legislated = fields.Boolean(data_key="legislated")
23 changes: 23 additions & 0 deletions submit-api/src/submit_api/schemas/track_work.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""TrackWork schema.

This module defines the schema for the track_work entity.
"""
from marshmallow import EXCLUDE, Schema, fields

from submit_api.schemas.track_phase import TrackPhaseSchema


class TrackWorkSchema(Schema):
"""Track work schema."""

class Meta: # pylint: disable=too-few-public-methods
"""Exclude unknown fields in the deserialized output."""

unknown = EXCLUDE

id = fields.Int(data_key="id")
project_id = fields.Int(data_key="project_id")
current_phase_id = fields.Int(data_key="current_phase_id", allow_none=True)
work_state = fields.Str(data_key="work_state", allow_none=True)
title = fields.Str(data_key="title", allow_none=True)
current_phase = fields.Nested(TrackPhaseSchema, data_key="current_phase", allow_none=True)
10 changes: 10 additions & 0 deletions submit-web/src/components/App/PackageStatusChip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,16 @@ const statusStyles: Record<
},
label: "Resubmitted",
},
REQUESTED_BY_EAO: {
sx: {
borderRadius: 1,
border: `1px solid ${BCDesignTokens.supportBorderColorWarning}`,
background: BCDesignTokens.supportSurfaceColorWarning,
height: "24px",
width: "139px",
},
label: "Requested by EAO",
},
};

type PackageStatusChipProps = Readonly<{
Expand Down
124 changes: 21 additions & 103 deletions submit-web/src/components/App/Projects/Project.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
import { Box, Button, Divider, styled, Typography } from "@mui/material";
import { BCDesignTokens } from "epic.theme";
import AddIcon from "@mui/icons-material/Add";
import { ProjectStatus } from "@/components/App/registration/addProjects/ProjectStatus";
import { PROJECT_STATUS } from "@/components/App/registration/addProjects/ProjectCard/constants";
import ProjectTable from "@/components/App/Projects/ProjectTable";
import { ContentBox } from "@/components/Shared/Layouts/ContentBox";
import { AccountProject } from "@/models/Project";
import { Box, styled } from "@mui/material";
import { useNavigate } from "@tanstack/react-router";
import { ContentBox } from "@/components/Shared/Layouts/ContentBox";
import { When } from "react-if";
import { useAccount } from "@/store/accountStore";
import { USER_TYPE } from "@/models/User";
import PermissionsGate from "@/components/Shared/PermissionGate";
import { ACCOUNT_USER_PERMISSIONS } from "@/models/Role";
import { ProjectSubmissionsCard } from "./ProjectSubmissionsCard";
import { PROJECT_STATUS } from "@/components/App/registration/addProjects/ProjectCard/constants";

export const CardInnerBox = styled(Box)({
display: "flex",
Expand All @@ -28,16 +20,10 @@ type ProjectParam = {

export const Project = ({ accountProject }: ProjectParam) => {
const navigate = useNavigate();
const { userType } = useAccount();

const activeSubmissionPackages = accountProject.packages.filter(
(subPackage) => !subPackage.completed_on,
);
const pastSubmissionPackages = accountProject.packages.filter((subPackage) =>
Boolean(subPackage.completed_on),
);

const { name, ea_certificate } = accountProject.project;
const currentPhase =
accountProject.account_project_works?.at(-1)?.work?.current_phase ?? null;

const handleNewSubmission = () => {
navigate({
Expand All @@ -52,89 +38,21 @@ export const Project = ({ accountProject }: ProjectParam) => {
topLabel={accountProject.project.proponent?.name || ""}
bottomLabel={ea_certificate ? `EAC # ${ea_certificate}` : ""}
>
<Box
sx={{
borderRadius: "3px",
border: `1px solid ${BCDesignTokens.surfaceColorBorderDefault}`,
boxShadow: "0px 1px 2px rgba(0, 0, 0, 0.1)",
}}
>
<Box
display={"flex"}
justifyContent={"space-between"}
sx={{
pt: BCDesignTokens.layoutPaddingMedium,
pb: BCDesignTokens.layoutPaddingXlarge,
}}
>
<CardInnerBox>
<Typography variant="h4" fontWeight={400}>
Management Plans & Related Documents
</Typography>
<ProjectStatus status={PROJECT_STATUS.POST_DECISION} />
</CardInnerBox>
<When condition={userType === USER_TYPE.PROPONENT}>
<CardInnerBox>
<PermissionsGate
scopes={[ACCOUNT_USER_PERMISSIONS.CREATE_PACKAGE]}
>
<Button onClick={handleNewSubmission}>
<AddIcon sx={{ p: 0, mr: 0.5 }} />
New Submission
</Button>
</PermissionsGate>
</CardInnerBox>
</When>
</Box>
<Box height={"100%"} px={BCDesignTokens.layoutPaddingXsmall}>
<Divider
sx={{
ml: BCDesignTokens.layoutPaddingSmall,
mb: BCDesignTokens.layoutPaddingXsmall,
}}
/>
<Typography
variant="body1"
sx={{
fontWeight: "bold",
backgroundColor: BCDesignTokens.themeGold10,
ml: BCDesignTokens.layoutPaddingSmall,
}}
>
Active Submissions
</Typography>
<CardInnerBox
sx={{ height: "100%", py: BCDesignTokens.layoutPaddingSmall }}
>
<ProjectTable submissionPackages={activeSubmissionPackages} />
</CardInnerBox>
<Divider
sx={{
mb: BCDesignTokens.layoutPaddingXsmall,
mt: BCDesignTokens.layoutPaddingSmall,
ml: BCDesignTokens.layoutPaddingSmall,
}}
/>
<Typography
variant="body1"
sx={{
fontWeight: "bold",
backgroundColor: BCDesignTokens.themeGold10,
ml: BCDesignTokens.layoutPaddingSmall,
}}
>
Review Completed by the EAO
</Typography>
<CardInnerBox
sx={{ height: "100%", py: BCDesignTokens.layoutPaddingMedium }}
>
<ProjectTable
headless
submissionPackages={pastSubmissionPackages}
/>
</CardInnerBox>
</Box>
</Box>
{currentPhase?.work_type_name == "ASSESSMENT" ? (
<ProjectSubmissionsCard
title={`${name} - Assessment`}
status={PROJECT_STATUS.EARLY_ENGAGEMENT}
packages={accountProject.packages}
onNewSubmission={handleNewSubmission}
/>
) : (
<ProjectSubmissionsCard
title="Management Plans & Related Documents"
status={PROJECT_STATUS.POST_DECISION}
packages={accountProject.packages}
onNewSubmission={handleNewSubmission}
/>
)}
</ContentBox>
);
};
Loading