From bba5e5efd4dbeb091d6f9bc8bb923e1c398a76d3 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Mon, 30 Dec 2024 15:39:31 -0500 Subject: [PATCH 1/7] Added reopen endpoint with validation and table update --- ...state_and_reopen_to_useractiontype_enum.py | 74 +++++++++++++++++++ src/sbl_filing_api/config.py | 2 + src/sbl_filing_api/entities/models/dao.py | 9 ++- src/sbl_filing_api/entities/models/dto.py | 9 ++- .../entities/models/model_enums.py | 6 ++ src/sbl_filing_api/routers/filing.py | 33 ++++++++- .../services/validators/filing_validators.py | 10 +++ 7 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py diff --git a/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py b/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py new file mode 100644 index 00000000..ab712ce6 --- /dev/null +++ b/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py @@ -0,0 +1,74 @@ +"""Add filing state + +Revision ID: 7fe49d38726b +Revises: 6ec12afa5b37 +Create Date: 2024-12-30 13:05:01.303998 + +""" + +from typing import Sequence, Union + +from alembic import op, context +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "7fe49d38726b" +down_revision: Union[str, None] = "6ec12afa5b37" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + +filing_state_enum = postgresql.ENUM( + "OPEN", + "CLOSED", + name="filingstate", + create_type=False, +) + +old_user_action = postgresql.ENUM( + "SUBMIT", + "ACCEPT", + "SIGNED", + "CREATE", + name="useractiontype", + create_type=False, +) + +new_user_action = postgresql.ENUM( + "SUBMIT", + "ACCEPT", + "SIGNED", + "CREATE", + "REOPEN", + name="useractiontype", + create_type=False, +) + + +def upgrade() -> None: + filing_state_enum.create(op.get_bind(), checkfirst=True) + op.add_column( + "filing", + sa.Column("state", filing_state_enum), + ) + + if "sqlite" not in context.get_context().dialect.name: + op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") + new_user_action.create(op.get_bind(), checkfirst=True) + op.execute( + "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" + ) + op.execute("DROP TYPE useractiontype_old") + + +def downgrade() -> None: + op.drop_column("filing", "state") + if "sqlite" not in context.get_context().dialect.name: + op.execute(sa.DDL("DROP TYPE filingstate")) + + op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") + old_user_action.create(op.get_bind(), checkfirst=True) + op.execute( + "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" + ) + op.execute("DROP TYPE useractiontype_old") diff --git a/src/sbl_filing_api/config.py b/src/sbl_filing_api/config.py index 0309de73..a4871983 100644 --- a/src/sbl_filing_api/config.py +++ b/src/sbl_filing_api/config.py @@ -95,6 +95,8 @@ class RequestActionValidations(BaseSettings): filing_create: Set[str] = {"valid_period_exists", "valid_no_filing_exists"} + filing_reopen: Set[str] = {"valid_filing_exists", "valid_filing_not_open"} + model_config = SettingsConfigDict(env_prefix="request_validators__", env_file=env_files_to_load, extra="allow") diff --git a/src/sbl_filing_api/entities/models/dao.py b/src/sbl_filing_api/entities/models/dao.py index e1593fa5..fdffe90c 100644 --- a/src/sbl_filing_api/entities/models/dao.py +++ b/src/sbl_filing_api/entities/models/dao.py @@ -1,4 +1,10 @@ -from sbl_filing_api.entities.models.model_enums import FilingType, FilingTaskState, SubmissionState, UserActionType +from sbl_filing_api.entities.models.model_enums import ( + FilingType, + FilingTaskState, + SubmissionState, + UserActionType, + FilingState, +) from datetime import datetime from typing import Any, List from sqlalchemy import Enum as SAEnum, String, desc @@ -125,6 +131,7 @@ class FilingDAO(Base): creator_id: Mapped[int] = mapped_column(ForeignKey("user_action.id")) creator: Mapped[UserActionDAO] = relationship(lazy="selectin", foreign_keys=[creator_id]) is_voluntary: Mapped[bool] = mapped_column(nullable=True) + state: Mapped[FilingState | None] = mapped_column(nullable=True) def __str__(self): return f"ID: {self.id}, Filing Period: {self.filing_period}, LEI: {self.lei}, Tasks: {self.tasks}, Institution Snapshot ID: {self.institution_snapshot_id}, Contact Info: {self.contact_info}" diff --git a/src/sbl_filing_api/entities/models/dto.py b/src/sbl_filing_api/entities/models/dto.py index 5f535dc3..65848a1a 100644 --- a/src/sbl_filing_api/entities/models/dto.py +++ b/src/sbl_filing_api/entities/models/dto.py @@ -2,7 +2,13 @@ from datetime import datetime from typing import Dict, Any, List from pydantic import BaseModel, ConfigDict, Field, model_validator -from sbl_filing_api.entities.models.model_enums import FilingType, FilingTaskState, SubmissionState, UserActionType +from sbl_filing_api.entities.models.model_enums import ( + FilingType, + FilingTaskState, + SubmissionState, + UserActionType, + FilingState, +) class UserActionDTO(BaseModel): @@ -89,6 +95,7 @@ class FilingDTO(BaseModel): signatures: List[UserActionDTO] = [] creator: UserActionDTO is_voluntary: bool | None = None + state: FilingState | None = None class FilingPeriodDTO(BaseModel): diff --git a/src/sbl_filing_api/entities/models/model_enums.py b/src/sbl_filing_api/entities/models/model_enums.py index 81e4053c..c935bbb3 100644 --- a/src/sbl_filing_api/entities/models/model_enums.py +++ b/src/sbl_filing_api/entities/models/model_enums.py @@ -6,6 +6,7 @@ class UserActionType(str, Enum): ACCEPT = "ACCEPT" SIGN = "SIGN" CREATE = "CREATE" + REOPEN = "REOPEN" class SubmissionState(str, Enum): @@ -30,3 +31,8 @@ class FilingTaskState(str, Enum): class FilingType(str, Enum): ANNUAL = "ANNUAL" + + +class FilingState(str, Enum): + OPEN = "OPEN" + CLOSED = "CLOSED" diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index 8e954705..5b7b0eb7 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -12,7 +12,7 @@ from regtech_api_commons.models.auth import AuthenticatedUser from sbl_filing_api.entities.models.dao import FilingDAO -from sbl_filing_api.entities.models.model_enums import UserActionType +from sbl_filing_api.entities.models.model_enums import UserActionType, FilingState from sbl_filing_api.services import submission_processor from sbl_filing_api.services.multithread_handler import handle_submission from sbl_filing_api.config import request_action_validations @@ -411,3 +411,34 @@ async def update_is_voluntary(request: Request, lei: str, period_code: str, upda name="Filing Not Found", detail=f"A Filing for the LEI ({lei}) and period ({period_code}) that was attempted to be updated does not exist.", ) + + +@router.put( + "/institutions/{lei}/filings/{period_code}/reopen", + response_model=FilingDTO, + dependencies=[ + Depends(set_context({UserActionContext.FILING})), + Depends(validate_user_action(request_action_validations.filing_reopen, "Filing Reopen Forbidden")), + ], +) +@requires("authenticated") +async def reopen_filing(request: Request, lei: str, period_code: str): + reopener = await repo.add_user_action( + request.state.db_session, + UserActionDTO( + user_id=request.user.id, + user_name=request.user.name, + user_email=request.user.email, + action_type=UserActionType.REOPEN, + ), + ) + filing = await repo.get_filing(request.state.db_session, lei, period_code) + if filing: + filing.state = FilingState.OPEN + res = await repo.upsert_filing(request.state.db_session, filing) + return res + raise RegTechHttpException( + status_code=status.HTTP_404_NOT_FOUND, + name="Filing Not Found", + detail=f"A Filing for the LEI ({lei}) and period ({period_code}) that was attempted to be reopened does not exist.", + ) \ No newline at end of file diff --git a/src/sbl_filing_api/services/validators/filing_validators.py b/src/sbl_filing_api/services/validators/filing_validators.py index f88d66fe..4e131c0c 100644 --- a/src/sbl_filing_api/services/validators/filing_validators.py +++ b/src/sbl_filing_api/services/validators/filing_validators.py @@ -1,6 +1,7 @@ import logging from sbl_filing_api.entities.models.dao import FilingDAO +from sbl_filing_api.entities.models.model_enums import FilingState from .base_validator import ActionValidator log = logging.getLogger(__name__) @@ -40,3 +41,12 @@ def __init__(self): def __call__(self, filing: FilingDAO, **kwargs): if filing and not filing.contact_info: return f"Cannot sign filing. Filing for {filing.lei} for period {filing.filing_period} does not have contact info defined." + + +class ValidFilingNotOpen(ActionValidator): + def __init__(self): + super().__init__("valid_filing_not_open") + + def __call__(self, *args, filing: FilingDAO, **kwargs): + if filing and filing.state is FilingState.OPEN: + return f"Cannot reopen filing. Filing state for {filing.lei} for period {filing.filing_period} is OPEN." From 77a6362d3bd8cf1f862d7722b6f31299c6bf0cd8 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Mon, 30 Dec 2024 16:15:12 -0500 Subject: [PATCH 2/7] Set filing state when creating and signing filing --- src/sbl_filing_api/entities/repos/submission_repo.py | 4 ++-- src/sbl_filing_api/routers/filing.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/sbl_filing_api/entities/repos/submission_repo.py b/src/sbl_filing_api/entities/repos/submission_repo.py index 70580ee2..1f83e501 100644 --- a/src/sbl_filing_api/entities/repos/submission_repo.py +++ b/src/sbl_filing_api/entities/repos/submission_repo.py @@ -20,7 +20,7 @@ UserActionDAO, ) from sbl_filing_api.entities.models.dto import FilingPeriodDTO, FilingDTO, ContactInfoDTO, UserActionDTO -from sbl_filing_api.entities.models.model_enums import SubmissionState +from sbl_filing_api.entities.models.model_enums import SubmissionState, FilingState logger = logging.getLogger(__name__) @@ -139,7 +139,7 @@ async def upsert_filing(session: AsyncSession, filing: FilingDTO) -> FilingDAO: async def create_new_filing(session: AsyncSession, lei: str, filing_period: str, creator_id: int) -> FilingDAO: - new_filing = FilingDAO(filing_period=filing_period, lei=lei, creator_id=creator_id) + new_filing = FilingDAO(filing_period=filing_period, lei=lei, creator_id=creator_id, state=FilingState.OPEN) return await upsert_helper(session, new_filing, FilingDAO) diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index 5b7b0eb7..4dfeb208 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -139,6 +139,7 @@ async def sign_filing(request: Request, lei: str, period_code: str): sig_timestamp = int(sig.timestamp.timestamp()) filing.confirmation_id = lei + "-" + period_code + "-" + str(latest_sub.counter) + "-" + str(sig_timestamp) filing.signatures.append(sig) + filing.state = FilingState.CLOSED send_confirmation_email( request.user.name, request.user.email, filing.contact_info.email, filing.confirmation_id, sig_timestamp ) @@ -423,7 +424,7 @@ async def update_is_voluntary(request: Request, lei: str, period_code: str, upda ) @requires("authenticated") async def reopen_filing(request: Request, lei: str, period_code: str): - reopener = await repo.add_user_action( + await repo.add_user_action( request.state.db_session, UserActionDTO( user_id=request.user.id, @@ -441,4 +442,4 @@ async def reopen_filing(request: Request, lei: str, period_code: str): status_code=status.HTTP_404_NOT_FOUND, name="Filing Not Found", detail=f"A Filing for the LEI ({lei}) and period ({period_code}) that was attempted to be reopened does not exist.", - ) \ No newline at end of file + ) From b192c0215c4aa2715125f44b55c0ed1ee765e60a Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Thu, 2 Jan 2025 16:00:48 -0500 Subject: [PATCH 3/7] Added unit tests and some config changes --- pyproject.toml | 5 ++- src/.env.local | 5 ++- src/sbl_filing_api/config.py | 4 +- src/sbl_filing_api/routers/filing.py | 12 ++---- .../services/validators/filing_validators.py | 13 +++++- tests/api/routers/test_filing_api.py | 43 ++++++++++++++++++- tests/entities/repos/test_submission_repo.py | 12 +++++- tests/migrations/test_migrations.py | 7 +++ .../services/test_request_action_validator.py | 10 +++-- 9 files changed, 89 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c074b5ff..e0e5a7e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,8 +79,9 @@ env = [ "FS_DOWNLOAD_CONFIG__PROTOCOL=file", "ENV=TEST", "MAIL_API_URL=http://mail-api:8765/internal/confirmation/send", - 'REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"]', - 'REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"]' + 'REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"]', + 'REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"]', + 'REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"]' ] testpaths = ["tests"] diff --git a/src/.env.local b/src/.env.local index fd070a49..d08f438b 100644 --- a/src/.env.local +++ b/src/.env.local @@ -21,5 +21,6 @@ FS_UPLOAD_CONFIG__ROOT="../upload" EXPIRED_SUBMISSION_CHECK_SECS=120 SERVER_CONFIG__RELOAD="true" MAIL_API_URL=http://mail-api:8765/internal/confirmation/send -REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"] -REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"] \ No newline at end of file +REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"] +REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"] +REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"] \ No newline at end of file diff --git a/src/sbl_filing_api/config.py b/src/sbl_filing_api/config.py index a4871983..c854bf87 100644 --- a/src/sbl_filing_api/config.py +++ b/src/sbl_filing_api/config.py @@ -87,7 +87,7 @@ class RequestActionValidations(BaseSettings): sign_and_submit: Set[str] = { "valid_lei_status", "valid_lei_tin", - "valid_filing_exists", + "valid_filing_exists_sign", "valid_sub_accepted", "valid_voluntary_filer", "valid_contact_info", @@ -95,7 +95,7 @@ class RequestActionValidations(BaseSettings): filing_create: Set[str] = {"valid_period_exists", "valid_no_filing_exists"} - filing_reopen: Set[str] = {"valid_filing_exists", "valid_filing_not_open"} + filing_reopen: Set[str] = {"valid_filing_exists_reopen", "valid_filing_not_open"} model_config = SettingsConfigDict(env_prefix="request_validators__", env_file=env_files_to_load, extra="allow") diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index 4dfeb208..c38af43a 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -434,12 +434,6 @@ async def reopen_filing(request: Request, lei: str, period_code: str): ), ) filing = await repo.get_filing(request.state.db_session, lei, period_code) - if filing: - filing.state = FilingState.OPEN - res = await repo.upsert_filing(request.state.db_session, filing) - return res - raise RegTechHttpException( - status_code=status.HTTP_404_NOT_FOUND, - name="Filing Not Found", - detail=f"A Filing for the LEI ({lei}) and period ({period_code}) that was attempted to be reopened does not exist.", - ) + filing.state = FilingState.OPEN + res = await repo.upsert_filing(request.state.db_session, filing) + return res diff --git a/src/sbl_filing_api/services/validators/filing_validators.py b/src/sbl_filing_api/services/validators/filing_validators.py index 4e131c0c..bbe30fa7 100644 --- a/src/sbl_filing_api/services/validators/filing_validators.py +++ b/src/sbl_filing_api/services/validators/filing_validators.py @@ -16,15 +16,24 @@ def __call__(self, filing: FilingDAO, period_code: str, lei: str, **kwargs): return f"Filing already exists for Filing Period {period_code} and LEI {lei}" -class ValidFilingExists(ActionValidator): +class ValidFilingExistsSign(ActionValidator): def __init__(self): - super().__init__("valid_filing_exists") + super().__init__("valid_filing_exists_sign") def __call__(self, filing: FilingDAO, lei: str, period_code: str, **kwargs): if not filing: return f"There is no Filing for LEI {lei} in period {period_code}, unable to sign a non-existent Filing." +class ValidFilingExistsReopen(ActionValidator): + def __init__(self): + super().__init__("valid_filing_exists_reopen") + + def __call__(self, filing: FilingDAO, lei: str, period_code: str, **kwargs): + if not filing: + return f"There is no Filing for LEI {lei} in period {period_code}, unable to reopen a non-existent Filing." + + class ValidVoluntaryFiler(ActionValidator): def __init__(self): super().__init__("valid_voluntary_filer") diff --git a/tests/api/routers/test_filing_api.py b/tests/api/routers/test_filing_api.py index 4f298b19..4ee5b30d 100644 --- a/tests/api/routers/test_filing_api.py +++ b/tests/api/routers/test_filing_api.py @@ -21,7 +21,7 @@ UserActionDAO, ) from sbl_filing_api.entities.models.dto import ContactInfoDTO, UserActionDTO -from sbl_filing_api.entities.models.model_enums import UserActionType +from sbl_filing_api.entities.models.model_enums import UserActionType, FilingState from sbl_filing_api.services import submission_processor from sbl_filing_api.services.multithread_handler import handle_submission @@ -1001,6 +1001,7 @@ async def test_good_sign_filing( self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock, get_filing_mock: Mock ): get_filing_mock.return_value.is_voluntary = True + get_filing_mock.return_value.state = FilingState.CLOSED get_filing_mock.return_value.submissions = [ SubmissionDAO( id=1, @@ -1302,3 +1303,43 @@ def test_contact_info_invalid_phone_number( in res.json()["error_detail"] ) assert res.status_code == 422 + + async def test_unauthed_reopen_filing(self, mocker: MockerFixture, app_fixture: FastAPI, unauthed_user_mock): + client = TestClient(app_fixture) + res = client.put("/v1/filing/institutions/123456790/filings/2024/reopen") + assert res.status_code == 403 + + def test_reopen_filing( + self, mocker: MockerFixture, app_fixture: FastAPI, get_filing_mock: Mock, authed_user_mock: Mock + ): + add_user_action_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.add_user_action") + add_user_action_mock.return_value = None + get_filing_mock.return_value.state = FilingState.OPEN + + upsert_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.upsert_filing") + updated_filing_obj = deepcopy(get_filing_mock.return_value) + upsert_mock.return_value = updated_filing_obj + + client = TestClient(app_fixture) + res = client.put("/v1/filing/institutions/1234567890ABCDEFGH00/filings/2024/reopen") + + assert res.status_code == 403 + assert res.json()["error_name"] == "Filing Reopen Forbidden" + assert ( + res.json()["error_detail"] + == "['Cannot reopen filing. Filing state for 1234567890ABCDEFGH00 for period 2024 is OPEN.']" + ) + + get_filing_mock.return_value.state = FilingState.CLOSED + res = client.put("/v1/filing/institutions/1234567890ABCDEFGH00/filings/2024/reopen") + assert res.status_code == 200 + assert res.json()["state"] == "OPEN" + + get_filing_mock.return_value = None + res = client.put("/v1/filing/institutions/1234567890ABCDEFGH00/filings/2024/reopen") + assert res.status_code == 403 + assert res.json()["error_name"] == "Filing Reopen Forbidden" + assert ( + res.json()["error_detail"] + == "['There is no Filing for LEI 1234567890ABCDEFGH00 in period 2024, unable to reopen a non-existent Filing.']" + ) diff --git a/tests/entities/repos/test_submission_repo.py b/tests/entities/repos/test_submission_repo.py index ab9bb6b8..188c4849 100644 --- a/tests/entities/repos/test_submission_repo.py +++ b/tests/entities/repos/test_submission_repo.py @@ -72,12 +72,21 @@ async def setup( action_type=UserActionType.SIGN, timestamp=dt.now(), ) + user_action6 = UserActionDAO( + id=6, + user_id="test_sig@local.host", + user_name="signer name", + user_email="test_sig@local.host", + action_type=UserActionType.REOPEN, + timestamp=dt.now(), + ) transaction_session.add(user_action1) transaction_session.add(user_action2) transaction_session.add(user_action3) transaction_session.add(user_action4) transaction_session.add(user_action5) + transaction_session.add(user_action6) filing_task_1 = FilingTaskDAO(name="Task-1", task_order=1) filing_task_2 = FilingTaskDAO(name="Task-2", task_order=2) @@ -262,6 +271,7 @@ async def test_add_filing(self, transaction_session: AsyncSession): assert res.creator.user_name == "test creator" assert res.creator.user_email == "test@local.host" assert res.creator.action_type == UserActionType.CREATE + assert res.state == "OPEN" async def test_modify_filing(self, transaction_session: AsyncSession): user_action_create = await repo.add_user_action( @@ -606,7 +616,7 @@ async def test_get_user_action(self, query_session: AsyncSession): async def test_get_user_actions(self, query_session: AsyncSession): res = await repo.get_user_actions(session=query_session) - assert len(res) == 5 + assert len(res) == 6 assert res[0].id == 1 assert res[0].user_name == "signer name" diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index bb8aec29..b08b2ad4 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -462,3 +462,10 @@ def test_migrations_to_63138f5cf036(alembic_runner: MigrationContext, alembic_en inspector = sqlalchemy.inspect(alembic_engine) columns = inspector.get_columns("filing") assert next(c for c in columns if c["name"] == "is_voluntary")["nullable"] + + +def test_migrations_to_7fe49d38726b(alembic_runner: MigrationContext, alembic_engine: Engine): + alembic_runner.migrate_up_to("7fe49d38726b") + inspector = sqlalchemy.inspect(alembic_engine) + + assert "state" in set([c["name"] for c in inspector.get_columns("filing")]) diff --git a/tests/services/test_request_action_validator.py b/tests/services/test_request_action_validator.py index ae3505ab..05f1b12f 100644 --- a/tests/services/test_request_action_validator.py +++ b/tests/services/test_request_action_validator.py @@ -8,7 +8,7 @@ from regtech_api_commons.api.exceptions import RegTechHttpException from sbl_filing_api.entities.models.dao import ContactInfoDAO, FilingDAO, SubmissionDAO -from sbl_filing_api.entities.models.model_enums import SubmissionState +from sbl_filing_api.entities.models.model_enums import SubmissionState, FilingState from sbl_filing_api.services.request_action_validator import UserActionContext, set_context, validate_user_action @@ -37,7 +37,7 @@ def httpx_authed_mock(mocker: MockerFixture) -> None: async def filing_mock(mocker: MockerFixture) -> FilingDAO: sub_mock = mocker.patch("sbl_filing_api.entities.models.dao.SubmissionDAO") sub_mock.state = SubmissionState.UPLOAD_FAILED - filing = FilingDAO(lei="1234567890ABCDEFGH00", filing_period="2024", submissions=[sub_mock]) + filing = FilingDAO(lei="1234567890ABCDEFGH00", filing_period="2024", submissions=[sub_mock], state=FilingState.OPEN) return filing @@ -53,6 +53,7 @@ def request_mock_valid_context(mocker: MockerFixture, request_mock: Request, fil filing_mock.is_voluntary = True filing_mock.submissions = [SubmissionDAO(state=SubmissionState.SUBMISSION_ACCEPTED)] filing_mock.contact_info = ContactInfoDAO() + filing_mock.state = FilingState.CLOSED request_mock.state.context = { "lei": "1234567890ABCDEFGH00", @@ -95,6 +96,7 @@ async def test_validations_with_errors(request_mock_invalid_context: Request): "valid_sub_accepted", "valid_voluntary_filer", "valid_contact_info", + "valid_filing_not_open", }, "Test Exception", ) @@ -116,6 +118,7 @@ async def test_validations_with_errors(request_mock_invalid_context: Request): ) assert "Cannot sign filing. TIN is required to file." in errors assert "Cannot sign filing. LEI status of LAPSED cannot file." in errors + assert "Cannot reopen filing. Filing state for 1234567890ABCDEFGH00 for period 2024 is OPEN." async def test_validations_no_errors(request_mock_valid_context: Request): @@ -123,10 +126,11 @@ async def test_validations_no_errors(request_mock_valid_context: Request): { "valid_lei_status", "valid_lei_tin", - "valid_filing_exists", + "valid_filing_exists_sign", "valid_sub_accepted", "valid_voluntary_filer", "valid_contact_info", + "valid_filing_not_open", }, "Test Exception", ) From 4684694d63e69a34f54718305257a352d1c2d4d2 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Wed, 8 Jan 2025 10:44:14 -0500 Subject: [PATCH 4/7] Added filing reopen table and added open filing validation to sign endpoint --- ...actiontype_enum_and_create_filing_reopen.py} | 14 ++++++++++++-- src/.env.local | 3 ++- src/sbl_filing_api/config.py | 1 + src/sbl_filing_api/entities/models/dao.py | 12 ++++++++++++ .../services/validators/filing_validators.py | 9 +++++++++ tests/migrations/test_migrations.py | 17 +++++++++++++++++ 6 files changed, 53 insertions(+), 3 deletions(-) rename db_revisions/versions/{7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py => 7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py} (78%) diff --git a/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py b/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py similarity index 78% rename from db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py rename to db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py index ab712ce6..9899b5d7 100644 --- a/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum.py +++ b/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py @@ -28,7 +28,7 @@ old_user_action = postgresql.ENUM( "SUBMIT", "ACCEPT", - "SIGNED", + "SIGN", "CREATE", name="useractiontype", create_type=False, @@ -37,7 +37,7 @@ new_user_action = postgresql.ENUM( "SUBMIT", "ACCEPT", - "SIGNED", + "SIGN", "CREATE", "REOPEN", name="useractiontype", @@ -52,6 +52,15 @@ def upgrade() -> None: sa.Column("state", filing_state_enum), ) + op.create_table( + "filing_reopen", + sa.Column("user_action", sa.INTEGER, primary_key=True, unique=True, nullable=False), + sa.Column("filing", sa.Integer, nullable=False), + sa.PrimaryKeyConstraint("user_action", name="filing_reopen_pkey"), + sa.ForeignKeyConstraint(["user_action"], ["user_action.id"], name="filing_reopen_user_action_fkey"), + sa.ForeignKeyConstraint(["filing"], ["filing.id"], name="filing_reopen_filing_fkey"), + ) + if "sqlite" not in context.get_context().dialect.name: op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") new_user_action.create(op.get_bind(), checkfirst=True) @@ -63,6 +72,7 @@ def upgrade() -> None: def downgrade() -> None: op.drop_column("filing", "state") + op.drop_table("filing_reopen") if "sqlite" not in context.get_context().dialect.name: op.execute(sa.DDL("DROP TYPE filingstate")) diff --git a/src/.env.local b/src/.env.local index d08f438b..92db9f51 100644 --- a/src/.env.local +++ b/src/.env.local @@ -23,4 +23,5 @@ SERVER_CONFIG__RELOAD="true" MAIL_API_URL=http://mail-api:8765/internal/confirmation/send REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"] REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"] -REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"] \ No newline at end of file +REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"] +USER_FI_API_URL=http://localhost:8881/v1/institutions/ \ No newline at end of file diff --git a/src/sbl_filing_api/config.py b/src/sbl_filing_api/config.py index c854bf87..7b90704a 100644 --- a/src/sbl_filing_api/config.py +++ b/src/sbl_filing_api/config.py @@ -88,6 +88,7 @@ class RequestActionValidations(BaseSettings): "valid_lei_status", "valid_lei_tin", "valid_filing_exists_sign", + "valid_filing_open", "valid_sub_accepted", "valid_voluntary_filer", "valid_contact_info", diff --git a/src/sbl_filing_api/entities/models/dao.py b/src/sbl_filing_api/entities/models/dao.py index fdffe90c..f69bd1c0 100644 --- a/src/sbl_filing_api/entities/models/dao.py +++ b/src/sbl_filing_api/entities/models/dao.py @@ -113,6 +113,15 @@ class FilingSignatureDAO(Base): filing: Mapped[int] = mapped_column(ForeignKey("filing.id"), index=True, nullable=False) +class FilingReopenDAO(Base): + __tablename__ = "filing_reopen" + user_action: Mapped[int] = mapped_column( + ForeignKey("user_action.id"), nullable=False, primary_key=True, unique=True + ) + filing: Mapped[int] = mapped_column(ForeignKey("filing.id"), index=True, nullable=False) + + + class FilingDAO(Base): __tablename__ = "filing" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) @@ -132,6 +141,9 @@ class FilingDAO(Base): creator: Mapped[UserActionDAO] = relationship(lazy="selectin", foreign_keys=[creator_id]) is_voluntary: Mapped[bool] = mapped_column(nullable=True) state: Mapped[FilingState | None] = mapped_column(nullable=True) + reopens: Mapped[List[UserActionDAO] | None] = relationship( + "UserActionDAO", secondary="filing_reopen", lazy="selectin", order_by="desc(UserActionDAO.timestamp)" + ) def __str__(self): return f"ID: {self.id}, Filing Period: {self.filing_period}, LEI: {self.lei}, Tasks: {self.tasks}, Institution Snapshot ID: {self.institution_snapshot_id}, Contact Info: {self.contact_info}" diff --git a/src/sbl_filing_api/services/validators/filing_validators.py b/src/sbl_filing_api/services/validators/filing_validators.py index bbe30fa7..7595d1fc 100644 --- a/src/sbl_filing_api/services/validators/filing_validators.py +++ b/src/sbl_filing_api/services/validators/filing_validators.py @@ -52,6 +52,15 @@ def __call__(self, filing: FilingDAO, **kwargs): return f"Cannot sign filing. Filing for {filing.lei} for period {filing.filing_period} does not have contact info defined." +class ValidFilingOpen(ActionValidator): + def __init__(self): + super().__init__("valid_filing_open") + + def __call__(self, *args, filing: FilingDAO, **kwargs): + if filing and filing.state is FilingState.CLOSED: + return f"Cannot sign filing. Filing state for {filing.lei} for period {filing.filing_period} is CLOSED." + + class ValidFilingNotOpen(ActionValidator): def __init__(self): super().__init__("valid_filing_not_open") diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index b08b2ad4..013680ca 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -469,3 +469,20 @@ def test_migrations_to_7fe49d38726b(alembic_runner: MigrationContext, alembic_en inspector = sqlalchemy.inspect(alembic_engine) assert "state" in set([c["name"] for c in inspector.get_columns("filing")]) + + assert set(["user_action", "filing",]) == set([c["name"] for c in inspector.get_columns("filing_reopen")]) + + filing_reopen_fks = inspector.get_foreign_keys("filing_reopen") + assert filing_reopen_fks[0]["name"] == "filing_reopen_user_action_fkey" + assert filing_reopen_fks[1]["name"] == "filing_reopen_filing_fkey" + + assert ( + "user_action" in filing_reopen_fks[0]["constrained_columns"] + and "user_action" == filing_reopen_fks[0]["referred_table"] + and "id" in filing_reopen_fks[0]["referred_columns"] + ) + assert ( + "filing" in filing_reopen_fks[1]["constrained_columns"] + and "filing" == filing_reopen_fks[1]["referred_table"] + and "id" in filing_reopen_fks[1]["referred_columns"] + ) \ No newline at end of file From 09d35dbcbd7b59a07da2c3017fc1c0abc2614587 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Wed, 8 Jan 2025 14:22:29 -0500 Subject: [PATCH 5/7] Added tests. Separated table migrations into different files. Linting --- ..._filing_state_and_create_filing_reopen.py} | 35 +---------- .../a655265a6c59_add_reopen_to_user_action.py | 58 +++++++++++++++++++ src/sbl_filing_api/entities/models/dao.py | 1 - src/sbl_filing_api/entities/models/dto.py | 1 + tests/migrations/test_migrations.py | 21 ++++--- .../services/test_request_action_validator.py | 12 ++++ 6 files changed, 85 insertions(+), 43 deletions(-) rename db_revisions/versions/{7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py => 7fe49d38726b_add_filing_state_and_create_filing_reopen.py} (58%) create mode 100644 db_revisions/versions/a655265a6c59_add_reopen_to_user_action.py diff --git a/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py b/db_revisions/versions/7fe49d38726b_add_filing_state_and_create_filing_reopen.py similarity index 58% rename from db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py rename to db_revisions/versions/7fe49d38726b_add_filing_state_and_create_filing_reopen.py index 9899b5d7..efa1ee25 100644 --- a/db_revisions/versions/7fe49d38726b_add_filing_state_and_reopen_to_useractiontype_enum_and_create_filing_reopen.py +++ b/db_revisions/versions/7fe49d38726b_add_filing_state_and_create_filing_reopen.py @@ -25,25 +25,6 @@ create_type=False, ) -old_user_action = postgresql.ENUM( - "SUBMIT", - "ACCEPT", - "SIGN", - "CREATE", - name="useractiontype", - create_type=False, -) - -new_user_action = postgresql.ENUM( - "SUBMIT", - "ACCEPT", - "SIGN", - "CREATE", - "REOPEN", - name="useractiontype", - create_type=False, -) - def upgrade() -> None: filing_state_enum.create(op.get_bind(), checkfirst=True) @@ -61,24 +42,10 @@ def upgrade() -> None: sa.ForeignKeyConstraint(["filing"], ["filing.id"], name="filing_reopen_filing_fkey"), ) - if "sqlite" not in context.get_context().dialect.name: - op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") - new_user_action.create(op.get_bind(), checkfirst=True) - op.execute( - "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" - ) - op.execute("DROP TYPE useractiontype_old") - def downgrade() -> None: op.drop_column("filing", "state") op.drop_table("filing_reopen") + if "sqlite" not in context.get_context().dialect.name: op.execute(sa.DDL("DROP TYPE filingstate")) - - op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") - old_user_action.create(op.get_bind(), checkfirst=True) - op.execute( - "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" - ) - op.execute("DROP TYPE useractiontype_old") diff --git a/db_revisions/versions/a655265a6c59_add_reopen_to_user_action.py b/db_revisions/versions/a655265a6c59_add_reopen_to_user_action.py new file mode 100644 index 00000000..985666af --- /dev/null +++ b/db_revisions/versions/a655265a6c59_add_reopen_to_user_action.py @@ -0,0 +1,58 @@ +"""Add REOPEN to user action + +Revision ID: a655265a6c59 +Revises: 7fe49d38726b +Create Date: 2025-01-08 13:59:33.098890 + +""" + +from typing import Sequence, Union + +from alembic import op, context +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "a655265a6c59" +down_revision: Union[str, None] = "7fe49d38726b" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +old_user_action = postgresql.ENUM( + "SUBMIT", + "ACCEPT", + "SIGN", + "CREATE", + name="useractiontype", + create_type=False, +) + +new_user_action = postgresql.ENUM( + "SUBMIT", + "ACCEPT", + "SIGN", + "CREATE", + "REOPEN", + name="useractiontype", + create_type=False, +) + + +def upgrade() -> None: + if "sqlite" not in context.get_context().dialect.name: + op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") + new_user_action.create(op.get_bind(), checkfirst=True) + op.execute( + "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" + ) + op.execute("DROP TYPE useractiontype_old") + + +def downgrade() -> None: + if "sqlite" not in context.get_context().dialect.name: + op.execute("ALTER TYPE useractiontype RENAME TO useractiontype_old") + old_user_action.create(op.get_bind(), checkfirst=True) + op.execute( + "ALTER TABLE user_action ALTER COLUMN action_type TYPE useractiontype USING user_action::text::useractiontype" + ) + op.execute("DROP TYPE useractiontype_old") diff --git a/src/sbl_filing_api/entities/models/dao.py b/src/sbl_filing_api/entities/models/dao.py index f69bd1c0..f25fe89e 100644 --- a/src/sbl_filing_api/entities/models/dao.py +++ b/src/sbl_filing_api/entities/models/dao.py @@ -121,7 +121,6 @@ class FilingReopenDAO(Base): filing: Mapped[int] = mapped_column(ForeignKey("filing.id"), index=True, nullable=False) - class FilingDAO(Base): __tablename__ = "filing" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) diff --git a/src/sbl_filing_api/entities/models/dto.py b/src/sbl_filing_api/entities/models/dto.py index 65848a1a..fd9972d8 100644 --- a/src/sbl_filing_api/entities/models/dto.py +++ b/src/sbl_filing_api/entities/models/dto.py @@ -96,6 +96,7 @@ class FilingDTO(BaseModel): creator: UserActionDTO is_voluntary: bool | None = None state: FilingState | None = None + reopens: List[UserActionDTO] = [] class FilingPeriodDTO(BaseModel): diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index 013680ca..d11000ca 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -470,19 +470,24 @@ def test_migrations_to_7fe49d38726b(alembic_runner: MigrationContext, alembic_en assert "state" in set([c["name"] for c in inspector.get_columns("filing")]) - assert set(["user_action", "filing",]) == set([c["name"] for c in inspector.get_columns("filing_reopen")]) + assert set( + [ + "user_action", + "filing", + ] + ) == set([c["name"] for c in inspector.get_columns("filing_reopen")]) filing_reopen_fks = inspector.get_foreign_keys("filing_reopen") assert filing_reopen_fks[0]["name"] == "filing_reopen_user_action_fkey" assert filing_reopen_fks[1]["name"] == "filing_reopen_filing_fkey" assert ( - "user_action" in filing_reopen_fks[0]["constrained_columns"] - and "user_action" == filing_reopen_fks[0]["referred_table"] - and "id" in filing_reopen_fks[0]["referred_columns"] + "user_action" in filing_reopen_fks[0]["constrained_columns"] + and "user_action" == filing_reopen_fks[0]["referred_table"] + and "id" in filing_reopen_fks[0]["referred_columns"] ) assert ( - "filing" in filing_reopen_fks[1]["constrained_columns"] - and "filing" == filing_reopen_fks[1]["referred_table"] - and "id" in filing_reopen_fks[1]["referred_columns"] - ) \ No newline at end of file + "filing" in filing_reopen_fks[1]["constrained_columns"] + and "filing" == filing_reopen_fks[1]["referred_table"] + and "id" in filing_reopen_fks[1]["referred_columns"] + ) diff --git a/tests/services/test_request_action_validator.py b/tests/services/test_request_action_validator.py index 05f1b12f..7ca0b56f 100644 --- a/tests/services/test_request_action_validator.py +++ b/tests/services/test_request_action_validator.py @@ -160,3 +160,15 @@ async def test_invalid_validation(request_mock_invalid_context: Request, log_moc run_validations = validate_user_action({"fake_validation"}, "Test Exception") await run_validations(request_mock_invalid_context) log_mock.warning.assert_called_with("Action validator [%s] not found.", "fake_validation") + + +async def test_valid_filing_state_for_signing(request_mock_invalid_context: Request): + run_validations = validate_user_action({"valid_filing_open"}, "Test Exception") + await run_validations(request_mock_invalid_context) + + +async def test_invalid_filing_state_for_signing(request_mock_valid_context: Request): + run_validations = validate_user_action({"valid_filing_open"}, "Test Exception") + with pytest.raises(RegTechHttpException) as e: + await run_validations(request_mock_valid_context) + assert "Cannot sign filing. Filing state for 1234567890ABCDEFGH00 for period 2024 is CLOSED." in e.value.detail From 7588b68948a6fe6ceeaa290088de3e9525765f43 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Wed, 8 Jan 2025 15:14:22 -0500 Subject: [PATCH 6/7] Appended reopens to reopen table. Updated config files --- pyproject.toml | 2 +- src/.env.local | 2 +- src/sbl_filing_api/routers/filing.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e0e5a7e8..c1ebc135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ env = [ "FS_DOWNLOAD_CONFIG__PROTOCOL=file", "ENV=TEST", "MAIL_API_URL=http://mail-api:8765/internal/confirmation/send", - 'REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"]', + 'REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_filing_open","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"]', 'REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"]', 'REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"]' ] diff --git a/src/.env.local b/src/.env.local index 92db9f51..bad853e6 100644 --- a/src/.env.local +++ b/src/.env.local @@ -21,7 +21,7 @@ FS_UPLOAD_CONFIG__ROOT="../upload" EXPIRED_SUBMISSION_CHECK_SECS=120 SERVER_CONFIG__RELOAD="true" MAIL_API_URL=http://mail-api:8765/internal/confirmation/send -REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"] +REQUEST_VALIDATORS__SIGN_AND_SUBMIT=["valid_lei_status","valid_lei_tin","valid_filing_exists_sign","valid_filing_open","valid_sub_accepted","valid_voluntary_filer","valid_contact_info"] REQUEST_VALIDATORS__FILING_CREATE=["valid_period_exists", "valid_no_filing_exists"] REQUEST_VALIDATORS__FILING_REOPEN=["valid_filing_exists_reopen", "valid_filing_not_open"] USER_FI_API_URL=http://localhost:8881/v1/institutions/ \ No newline at end of file diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index c38af43a..0025df0f 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -424,7 +424,7 @@ async def update_is_voluntary(request: Request, lei: str, period_code: str, upda ) @requires("authenticated") async def reopen_filing(request: Request, lei: str, period_code: str): - await repo.add_user_action( + reopen = await repo.add_user_action( request.state.db_session, UserActionDTO( user_id=request.user.id, @@ -434,6 +434,7 @@ async def reopen_filing(request: Request, lei: str, period_code: str): ), ) filing = await repo.get_filing(request.state.db_session, lei, period_code) + filing.reopens.append(reopen) filing.state = FilingState.OPEN res = await repo.upsert_filing(request.state.db_session, filing) return res From 46fb9c79a678949ed1139e807020336b3456ed47 Mon Sep 17 00:00:00 2001 From: jmcguffee Date: Wed, 8 Jan 2025 15:23:25 -0500 Subject: [PATCH 7/7] Fixed test --- tests/api/routers/test_filing_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/api/routers/test_filing_api.py b/tests/api/routers/test_filing_api.py index 4ee5b30d..e03a3184 100644 --- a/tests/api/routers/test_filing_api.py +++ b/tests/api/routers/test_filing_api.py @@ -1001,7 +1001,7 @@ async def test_good_sign_filing( self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock, get_filing_mock: Mock ): get_filing_mock.return_value.is_voluntary = True - get_filing_mock.return_value.state = FilingState.CLOSED + get_filing_mock.return_value.state = FilingState.OPEN get_filing_mock.return_value.submissions = [ SubmissionDAO( id=1,