Skip to content

Commit

Permalink
Merge branch 'bcgov:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
dinesh-aot authored Nov 8, 2024
2 parents a8cdb36 + 01bead3 commit c172d18
Show file tree
Hide file tree
Showing 31 changed files with 523 additions and 90 deletions.
2 changes: 1 addition & 1 deletion epictrack-api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pylint: ## Linting with pylint
. venv/bin/activate && pylint --rcfile=setup.cfg src/$(PROJECT_NAME)

flake8: ## Linting with flake8
. venv/bin/activate && flake8 --extend-ignore=Q000,D400,D401,I005,W503 src/$(PROJECT_NAME) tests
. venv/bin/activate && flake8 --extend-ignore=Q000,D400,D401,I005,W503,E261,E121 src/$(PROJECT_NAME) tests

lint: pylint flake8 ## run all lint type scripts

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

def upgrade():
op.execute("ALTER TYPE projectstateenum ADD VALUE 'PRE_WORK'")

op.execute("COMMIT")
with op.batch_alter_table('projects_history', schema=None) as batch_op:
batch_op.add_column(sa.Column('project_state', sa.Enum('PRE_WORK', 'UNDER_EAC_ASSESSMENT', 'UNDER_EXEMPTION_REQUEST', 'UNDER_AMENDMENT', 'UNDER_DISPUTE_RESOLUTION', 'PRE_CONSTRUCTION', 'CONSTRUCTION', 'OPERATION', 'CARE_AND_MAINTENANCE', 'DECOMMISSION', 'UNKNOWN', 'CLOSED', 'UNDER_DESIGNATION', name='projectstateenum'), autoincrement=False, nullable=True))
# ### end Alembic commands ###
Expand Down
179 changes: 179 additions & 0 deletions epictrack-api/migrations/versions/af4022c1a70c_project_state_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
"""project state table
Revision ID: af4022c1a70c
Revises: b7a3fafa6f1b
Create Date: 2024-10-28 16:27:25.026807
"""

from alembic import op
from sqlalchemy.dialects.postgresql import ARRAY
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = "af4022c1a70c"
down_revision = "b7a3fafa6f1b"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"project_states",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("name", sa.String(), nullable=False),
sa.Column(
"component",
ARRAY(
sa.Enum(
"COMPLIANCE", "TRACK", "SUBMIT", name="projectstatecomponentenum"
)
),
nullable=False,
),
sa.Column("sort_order", sa.Integer(), nullable=False),
sa.Column("created_by", sa.String(length=255), nullable=True),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
server_default=sa.text("TIMEZONE('utc', CURRENT_TIMESTAMP)"),
nullable=True,
),
sa.Column("updated_by", sa.String(length=255), nullable=True),
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True),
sa.Column("is_active", sa.Boolean(), server_default="t", nullable=False),
sa.Column("is_deleted", sa.Boolean(), server_default="f", nullable=False),
sa.PrimaryKeyConstraint("id"),
sqlite_autoincrement=True,
)
op.create_table(
"project_states_history",
sa.Column("id", sa.Integer(), autoincrement=False, nullable=False),
sa.Column("name", sa.String(), autoincrement=False, nullable=False),
sa.Column(
"component",
ARRAY(
sa.Enum(
"COMPLIANCE", "TRACK", "SUBMIT", name="projectstatecomponentenum"
)
),
nullable=False,
),
sa.Column("sort_order", sa.Integer(), autoincrement=False, nullable=False),
sa.Column(
"created_by", sa.String(length=255), autoincrement=False, nullable=True
),
sa.Column(
"created_at", sa.DateTime(timezone=True), autoincrement=False, nullable=True
),
sa.Column(
"updated_by", sa.String(length=255), autoincrement=False, nullable=True
),
sa.Column(
"updated_at", sa.DateTime(timezone=True), autoincrement=False, nullable=True
),
sa.Column("is_active", sa.Boolean(), autoincrement=False, nullable=False),
sa.Column("is_deleted", sa.Boolean(), autoincrement=False, nullable=False),
sa.Column("pk", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("during", postgresql.TSTZRANGE(), nullable=True),
sa.PrimaryKeyConstraint("id", "pk"),
sqlite_autoincrement=True,
)
with op.batch_alter_table("projects", schema=None) as batch_op:
batch_op.add_column(sa.Column("project_state_id", sa.Integer(), nullable=True))
batch_op.create_foreign_key(
"projects_project_state_id_project_state_fk",
"project_states",
["project_state_id"],
["id"],
)

with op.batch_alter_table("projects_history", schema=None) as batch_op:
batch_op.add_column(
sa.Column(
"project_state_id", sa.Integer(), autoincrement=False, nullable=True
)
)
batch_op.create_foreign_key(
"projects_project_state_id_project_state_fk",
"project_states",
["project_state_id"],
["id"],
)
project_states = [
{"name": "Potential Work", "component": ["SUBMIT"]},
{"name": "Pre Work", "component": ["TRACK", "SUBMIT"]},
{"name": "Under Work", "component": ["TRACK", "SUBMIT"]},
{"name": "Work Pending", "component": ["TRACK", "SUBMIT"]},
{"name": "Under Dispute Resolution", "component": ["TRACK", "SUBMIT"]},
{"name": "Other Work", "component": ["TRACK"]},
{"name": "Project Withdrawn", "component": ["TRACK"]},
{"name": "Project Terminated", "component": ["TRACK"]},
{"name": "EAC Expired", "component": ["TRACK"]},
{"name": "EAC Or Order Cancelled", "component": ["TRACK"]},
{"name": "EAC Or Order Suspended", "component": ["TRACK"]},
{"name": "Indeterminate", "component": ["COMPLIANCE"]},
{"name": "Preconstruction", "component": ["COMPLIANCE"]},
{"name": "Construction", "component": ["COMPLIANCE"]},
{"name": "Operation", "component": ["COMPLIANCE"]},
{"name": "Care and Maintenance", "component": ["COMPLIANCE"]},
{"name": "Decommissioning", "component": ["COMPLIANCE"]},
{"name": "Closed", "component": ["TRACK"]},
]

for idx, state in enumerate(project_states, start=1):
name = state['name']
component = state['component']
component_array = "{" + ", ".join(component) + "}" # Proper format for PostgreSQL array
op.execute(
f"""
INSERT INTO project_states (name, component, sort_order, created_by, created_at, updated_by, updated_at, is_active, is_deleted)
VALUES ('{name}', '{component_array}', {idx}, 'system', NOW(), 'system', NOW(), TRUE, FALSE)
"""
)
op.execute("ALTER TYPE projectstateenum ADD VALUE IF NOT EXISTS 'PRE_WORK'")
state_map = {
"PRE_WORK": 2,
"UNDER_EAC_ASSESSMENT": 3,
"UNDER_EXEMPTION_REQUEST": 3,
"UNDER_AMENDMENT": 3,
"UNDER_DISPUTE_RESOLUTION": 5,
"PRE_CONSTRUCTION": 13,
"CONSTRUCTION": 14,
"OPERATION": 15,
"CARE_AND_MAINTENANCE": 16,
"DECOMMISSION": 17,
"UNKNOWN": 13,
"CLOSED": 18,
"UNDER_DESIGNATION": 3
}
for state, state_id in state_map.items():
op.execute(f"UPDATE projects SET project_state_id={state_id} WHERE project_state='{state}'")
op.execute("ALTER TABLE projects DROP COLUMN project_state")
param = '{"project_state_id": 13}'
op.execute(f"update action_configurations set additional_params = '{param}' where action_id = 13")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###

with op.batch_alter_table("projects_history", schema=None) as batch_op:
batch_op.drop_constraint(
"projects_project_state_id_project_state_fk", type_="foreignkey"
)
batch_op.drop_column("project_state_id")

with op.batch_alter_table("projects", schema=None) as batch_op:
batch_op.drop_constraint(
"projects_project_state_id_project_state_fk", type_="foreignkey"
)
batch_op.drop_column("project_state_id")

op.drop_table("project_states_history")
op.drop_table("project_states")
op.execute("DROP TYPE IF EXISTS projectstatecomponentenum")
op.execute("alter table projects add column project_state projectstateenum")
# ### end Alembic commands ###
2 changes: 1 addition & 1 deletion epictrack-api/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ notes=FIXME,XXX,TODO
ignored-modules=flask_sqlalchemy,sqlalchemy,SQLAlchemy,alembic,scoped_session
ignored-classes=scoped_session
min-similarity-lines=15
disable=C0301,W0511
disable=C0301,W0511, R0917, C0411, R1710, E1101, W4904
good-names=f,id,k,v

[isort]
Expand Down
4 changes: 3 additions & 1 deletion epictrack-api/src/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ def create_app(run_mode=os.getenv('FLASK_ENV', 'production')):
"""Return a configured Flask App using the Factory method."""
app = Flask(__name__)
app.config.from_object(config.CONFIGURATION[run_mode])
app.logger.setLevel(logging.INFO) # pylint: disable=no-member
log_level = os.getenv('LOG_LEVEL', 'INFO').upper()
app.logger.info(f'Current log level: {log_level}')
app.logger.setLevel(getattr(logging, log_level, logging.INFO)) # pylint: disable=no-member
app.json_provider_class = CustomJSONEncoder

db.init_app(app)
Expand Down
4 changes: 2 additions & 2 deletions epictrack-api/src/api/actions/set_project_state.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Sets the state of the project"""
from api.actions.base import ActionFactory
from api.models.event import Event
from api.models.project import Project, ProjectStateEnum
from api.models.project import Project


class SetProjectState(ActionFactory):
Expand All @@ -10,5 +10,5 @@ class SetProjectState(ActionFactory):
def run(self, source_event: Event, params) -> None:
"""Sets the federal involvement field to None"""
project = Project.find_by_id(source_event.work.project_id)
project.project_state = ProjectStateEnum(params.get("project_state"))
project.project_state_id = params.get("project_state_id")
project.update(project.as_dict(recursive=False), commit=False)
1 change: 1 addition & 0 deletions epictrack-api/src/api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,4 @@
from .work_type import WorkType
from .indigenous_consultation_levels import IndigenousConsultationLevel
from .linked_work import LinkedWork
from .project_state import ProjectState
36 changes: 20 additions & 16 deletions epictrack-api/src/api/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""Model to manage Project."""
import enum

from sqlalchemy import Boolean, Column, Date, Enum, Float, ForeignKey, Integer, String, Text, func
from sqlalchemy import Boolean, Column, Date, Float, ForeignKey, Integer, String, Text, func
from sqlalchemy.orm import relationship

from .base_model import BaseModelVersioned
Expand All @@ -23,19 +23,24 @@
class ProjectStateEnum(enum.Enum):
"""Enum for project state"""

PRE_WORK = "PRE_WORK"
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"
CLOSED = "CLOSED"
UNDER_DESIGNATION = "UNDER_DESIGNATION"
POTENTIAL_WORK = 1
PRE_WORK = 2
UNDER_WORK = 3
WORK_PENDING = 4
UNDER_DISPUTE_RESOLUTION = 5
OTHER_WORK = 6
PROJECT_WITHDRAWN = 7
PROJECT_TERMINATED = 8
EAC_EXPIRED = 9
EAC_OR_ORDER_CANCELLED = 10
EAC_OR_ORDER_SUSPENDED = 11
INDETERMINATE = 12
PRECONSTRUCTION = 13
CONSTRUCTION = 14
OPERATION = 15
CARE_AND_MAINTENANCE = 16
DECOMMISSIONING = 17
CLOSED = 18


class Project(BaseModelVersioned):
Expand All @@ -55,7 +60,6 @@ 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)
Expand All @@ -66,6 +70,7 @@ class Project(BaseModelVersioned):
abbreviation = Column(String(10), nullable=True, unique=True)
eac_signed = Column(Date(), nullable=True)
eac_expires = Column(Date(), nullable=True)
project_state_id = Column(ForeignKey("project_states.id", name="projects_project_state_id_project_state_fk"))
sub_type = relationship("SubType", foreign_keys=[sub_type_id], lazy="select")
type = relationship("Type", foreign_keys=[type_id], lazy="select")
proponent = relationship("Proponent", foreign_keys=[proponent_id], lazy="select")
Expand Down Expand Up @@ -103,5 +108,4 @@ def get_by_abbreviation(cls, abbreviation: str):
def as_dict(self, recursive=True):
"""Return JSON Representation."""
data = super().as_dict(recursive)
data["project_state"] = self.project_state.value
return data
46 changes: 46 additions & 0 deletions epictrack-api/src/api/models/project_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright © 2019 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Model to manage Project State."""
import enum
from sqlalchemy import Column, Integer, String, Enum, or_, any_
from sqlalchemy.dialects.postgresql import ARRAY
from .base_model import BaseModelVersioned


class ProjectStateComponentEnum(enum.Enum):
"""Enum for project state component"""

COMPLIANCE = "COMPLIANCE"
TRACK = "TRACK"
SUBMIT = "SUBMIT"


class ProjectState(BaseModelVersioned):
"""ProjectState."""

__tablename__ = "project_states"
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(), nullable=False)
component = Column(
ARRAY(Enum("COMPLIANCE", "TRACK", "SUBMIT", name="projectstatecomponentenum")),
nullable=False,
)
sort_order = Column(Integer, nullable=False)

@classmethod
def find_by_components(cls, components: [str]):
"""Get project states by component"""
return cls.query.filter(
or_(*(comp == any_(cls.component) for comp in components))
).all()
Loading

0 comments on commit c172d18

Please sign in to comment.