From 614514d6a2040ed9217f0ddb4f27c3ee50ff0ab2 Mon Sep 17 00:00:00 2001 From: leigh-mil Date: Mon, 25 Nov 2019 14:16:15 -0500 Subject: [PATCH] Update tables to match business logic --- .secrets.baseline | 4 +- ...9_update_schema_based_on_business_logic.py | 198 ++++++++++++++++++ atst/domain/task_orders.py | 6 +- atst/models/application_invitation.py | 5 +- atst/models/application_role.py | 4 +- atst/models/clin.py | 12 +- atst/models/environment_role.py | 4 +- atst/models/mixins/invites.py | 20 +- atst/models/portfolio.py | 6 +- atst/models/portfolio_invitation.py | 2 +- atst/models/portfolio_role.py | 4 +- atst/models/task_order.py | 5 +- atst/models/user.py | 4 +- atst/routes/task_orders/new.py | 6 +- script/seed_sample.py | 21 +- tests/domain/test_portfolios.py | 1 + tests/domain/test_task_orders.py | 2 - tests/domain/test_users.py | 15 +- tests/factories.py | 33 ++- tests/models/test_task_order.py | 12 +- tests/routes/task_orders/test_index.py | 2 +- tests/routes/task_orders/test_new.py | 34 ++- tests/test_access.py | 7 +- 23 files changed, 328 insertions(+), 79 deletions(-) create mode 100644 alembic/versions/67a2151d6269_update_schema_based_on_business_logic.py diff --git a/.secrets.baseline b/.secrets.baseline index 07353d5a..7a81d3cb 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -161,7 +161,7 @@ "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", "is_secret": false, "is_verified": false, - "line_number": 32, + "line_number": 31, "type": "Hex High Entropy String" } ], @@ -170,7 +170,7 @@ "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", "is_secret": false, "is_verified": false, - "line_number": 656, + "line_number": 657, "type": "Hex High Entropy String" } ] diff --git a/alembic/versions/67a2151d6269_update_schema_based_on_business_logic.py b/alembic/versions/67a2151d6269_update_schema_based_on_business_logic.py new file mode 100644 index 00000000..06fd5d40 --- /dev/null +++ b/alembic/versions/67a2151d6269_update_schema_based_on_business_logic.py @@ -0,0 +1,198 @@ +"""update schema based on business logic + +Revision ID: 67a2151d6269 +Revises: 687fd43489d6 +Create Date: 2019-12-02 14:16:24.902108 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = '67a2151d6269' # pragma: allowlist secret +down_revision = '687fd43489d6' # pragma: allowlist secret +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('application_invitations', 'application_role_id', + existing_type=postgresql.UUID(), + nullable=False) + op.alter_column('application_invitations', 'dod_id', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('application_invitations', 'expiration_time', + existing_type=postgresql.TIMESTAMP(timezone=True), + nullable=False) + op.alter_column('application_invitations', 'first_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('application_invitations', 'inviter_id', + existing_type=postgresql.UUID(), + nullable=False) + op.alter_column('application_invitations', 'last_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('application_invitations', 'token', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('application_roles', 'status', + existing_type=sa.VARCHAR(length=8), + nullable=False) + op.alter_column('clins', 'end_date', + existing_type=sa.DATE(), + nullable=False) + op.alter_column('clins', 'jedi_clin_type', + existing_type=sa.VARCHAR(length=11), + nullable=False) + op.alter_column('clins', 'number', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('clins', 'obligated_amount', + existing_type=sa.NUMERIC(), + nullable=False) + op.alter_column('clins', 'start_date', + existing_type=sa.DATE(), + nullable=False) + op.alter_column('clins', 'total_amount', + existing_type=sa.NUMERIC(), + nullable=False) + op.alter_column('environment_roles', 'status', + existing_type=sa.VARCHAR(length=9), + nullable=False) + op.alter_column('portfolio_invitations', 'dod_id', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('portfolio_invitations', 'expiration_time', + existing_type=postgresql.TIMESTAMP(timezone=True), + nullable=False) + op.alter_column('portfolio_invitations', 'first_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('portfolio_invitations', 'inviter_id', + existing_type=postgresql.UUID(), + nullable=False) + op.alter_column('portfolio_invitations', 'last_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('portfolio_invitations', 'portfolio_role_id', + existing_type=postgresql.UUID(), + nullable=False) + op.alter_column('portfolio_invitations', 'token', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('portfolio_roles', 'status', + existing_type=sa.VARCHAR(length=8), + nullable=False) + op.alter_column('portfolios', 'defense_component', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('portfolios', 'name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('task_orders', 'portfolio_id', + existing_type=postgresql.UUID(), + nullable=False) + op.drop_constraint('task_orders_user_id_fkey', 'task_orders', type_='foreignkey') + op.drop_column('task_orders', 'user_id') + op.alter_column('users', 'first_name', + existing_type=sa.VARCHAR(), + nullable=False) + op.alter_column('users', 'last_name', + existing_type=sa.VARCHAR(), + nullable=False) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.alter_column('users', 'last_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('users', 'first_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.add_column('task_orders', sa.Column('user_id', postgresql.UUID(), autoincrement=False, nullable=True)) + op.create_foreign_key('task_orders_user_id_fkey', 'task_orders', 'users', ['user_id'], ['id']) + op.alter_column('task_orders', 'portfolio_id', + existing_type=postgresql.UUID(), + nullable=True) + op.alter_column('portfolios', 'name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('portfolios', 'defense_component', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('portfolio_roles', 'status', + existing_type=sa.VARCHAR(length=8), + nullable=True) + op.alter_column('portfolio_invitations', 'token', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('portfolio_invitations', 'portfolio_role_id', + existing_type=postgresql.UUID(), + nullable=True) + op.alter_column('portfolio_invitations', 'last_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('portfolio_invitations', 'inviter_id', + existing_type=postgresql.UUID(), + nullable=True) + op.alter_column('portfolio_invitations', 'first_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('portfolio_invitations', 'expiration_time', + existing_type=postgresql.TIMESTAMP(timezone=True), + nullable=True) + op.alter_column('portfolio_invitations', 'dod_id', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('environment_roles', 'status', + existing_type=sa.VARCHAR(length=9), + nullable=True) + op.alter_column('clins', 'total_amount', + existing_type=sa.NUMERIC(), + nullable=True) + op.alter_column('clins', 'start_date', + existing_type=sa.DATE(), + nullable=True) + op.alter_column('clins', 'obligated_amount', + existing_type=sa.NUMERIC(), + nullable=True) + op.alter_column('clins', 'number', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('clins', 'jedi_clin_type', + existing_type=sa.VARCHAR(length=11), + nullable=True) + op.alter_column('clins', 'end_date', + existing_type=sa.DATE(), + nullable=True) + op.alter_column('application_roles', 'status', + existing_type=sa.VARCHAR(length=8), + nullable=True) + op.alter_column('application_invitations', 'token', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('application_invitations', 'last_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('application_invitations', 'inviter_id', + existing_type=postgresql.UUID(), + nullable=True) + op.alter_column('application_invitations', 'first_name', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('application_invitations', 'expiration_time', + existing_type=postgresql.TIMESTAMP(timezone=True), + nullable=True) + op.alter_column('application_invitations', 'dod_id', + existing_type=sa.VARCHAR(), + nullable=True) + op.alter_column('application_invitations', 'application_role_id', + existing_type=postgresql.UUID(), + nullable=True) + # ### end Alembic commands ### diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 93521843..0c67e1d4 100644 --- a/atst/domain/task_orders.py +++ b/atst/domain/task_orders.py @@ -11,10 +11,8 @@ class TaskOrders(BaseDomainClass): resource_name = "task_order" @classmethod - def create(cls, creator, portfolio_id, number, clins, pdf): - task_order = TaskOrder( - portfolio_id=portfolio_id, creator=creator, number=number, pdf=pdf - ) + def create(cls, portfolio_id, number, clins, pdf): + task_order = TaskOrder(portfolio_id=portfolio_id, number=number, pdf=pdf) db.session.add(task_order) db.session.commit() diff --git a/atst/models/application_invitation.py b/atst/models/application_invitation.py index d24cc54d..02be5e14 100644 --- a/atst/models/application_invitation.py +++ b/atst/models/application_invitation.py @@ -12,7 +12,10 @@ class ApplicationInvitation( __tablename__ = "application_invitations" application_role_id = Column( - UUID(as_uuid=True), ForeignKey("application_roles.id"), index=True + UUID(as_uuid=True), + ForeignKey("application_roles.id"), + index=True, + nullable=False, ) role = relationship( "ApplicationRole", diff --git a/atst/models/application_role.py b/atst/models/application_role.py index f8f7f201..d65ceac7 100644 --- a/atst/models/application_role.py +++ b/atst/models/application_role.py @@ -46,7 +46,9 @@ class ApplicationRole( UUID(as_uuid=True), ForeignKey("users.id"), index=True, nullable=True ) - status = Column(SQLAEnum(Status, native_enum=False), default=Status.PENDING) + status = Column( + SQLAEnum(Status, native_enum=False), default=Status.PENDING, nullable=False + ) permission_sets = relationship( "PermissionSet", secondary=application_roles_permission_sets diff --git a/atst/models/clin.py b/atst/models/clin.py index 2802e292..0624d985 100644 --- a/atst/models/clin.py +++ b/atst/models/clin.py @@ -23,12 +23,12 @@ class CLIN(Base, mixins.TimestampsMixin): task_order_id = Column(ForeignKey("task_orders.id"), nullable=False) task_order = relationship("TaskOrder") - number = Column(String, nullable=True) - start_date = Column(Date, nullable=True) - end_date = Column(Date, nullable=True) - total_amount = Column(Numeric(scale=2), nullable=True) - obligated_amount = Column(Numeric(scale=2), nullable=True) - jedi_clin_type = Column(SQLAEnum(JEDICLINType, native_enum=False), nullable=True) + number = Column(String, nullable=False) + start_date = Column(Date, nullable=False) + end_date = Column(Date, nullable=False) + total_amount = Column(Numeric(scale=2), nullable=False) + obligated_amount = Column(Numeric(scale=2), nullable=False) + jedi_clin_type = Column(SQLAEnum(JEDICLINType, native_enum=False), nullable=False) # # NOTE: For now obligated CLINS are CLIN 1 + CLIN 3 diff --git a/atst/models/environment_role.py b/atst/models/environment_role.py index 541b6d40..5b3a2c27 100644 --- a/atst/models/environment_role.py +++ b/atst/models/environment_role.py @@ -43,7 +43,9 @@ class EnvironmentRole( COMPLETED = "completed" DISABLED = "disabled" - status = Column(SQLAEnum(Status, native_enum=False), default=Status.PENDING) + status = Column( + SQLAEnum(Status, native_enum=False), default=Status.PENDING, nullable=False + ) def __repr__(self): return "".format( diff --git a/atst/models/mixins/invites.py b/atst/models/mixins/invites.py index 69e016f8..18916dc4 100644 --- a/atst/models/mixins/invites.py +++ b/atst/models/mixins/invites.py @@ -31,23 +31,29 @@ class InvitesMixin(object): @declared_attr def inviter_id(cls): - return Column(UUID(as_uuid=True), ForeignKey("users.id"), index=True) + return Column( + UUID(as_uuid=True), ForeignKey("users.id"), index=True, nullable=False + ) @declared_attr def inviter(cls): return relationship("User", foreign_keys=[cls.inviter_id]) - status = Column(SQLAEnum(Status, native_enum=False, default=Status.PENDING)) + status = Column( + SQLAEnum(Status, native_enum=False, default=Status.PENDING, nullable=False) + ) - expiration_time = Column(TIMESTAMP(timezone=True)) + expiration_time = Column(TIMESTAMP(timezone=True), nullable=False) - token = Column(String, index=True, default=lambda: secrets.token_urlsafe()) + token = Column( + String, index=True, default=lambda: secrets.token_urlsafe(), nullable=False + ) email = Column(String, nullable=False) - dod_id = Column(String) - first_name = Column(String) - last_name = Column(String) + dod_id = Column(String, nullable=False) + first_name = Column(String, nullable=False) + last_name = Column(String, nullable=False) phone_number = Column(String) phone_ext = Column(String) diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index 08a65f1c..ed26b4d4 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -18,8 +18,10 @@ class Portfolio( __tablename__ = "portfolios" id = types.Id() - name = Column(String) - defense_component = Column(String) # Department of Defense Component + name = Column(String, nullable=False) + defense_component = Column( + String, nullable=False + ) # Department of Defense Component app_migration = Column(String) # App Migration complexity = Column(ARRAY(String)) # Application Complexity diff --git a/atst/models/portfolio_invitation.py b/atst/models/portfolio_invitation.py index 55d895c6..4ab9088d 100644 --- a/atst/models/portfolio_invitation.py +++ b/atst/models/portfolio_invitation.py @@ -12,7 +12,7 @@ class PortfolioInvitation( __tablename__ = "portfolio_invitations" portfolio_role_id = Column( - UUID(as_uuid=True), ForeignKey("portfolio_roles.id"), index=True + UUID(as_uuid=True), ForeignKey("portfolio_roles.id"), index=True, nullable=False ) role = relationship( "PortfolioRole", diff --git a/atst/models/portfolio_role.py b/atst/models/portfolio_role.py index 500a0ddd..53204e82 100644 --- a/atst/models/portfolio_role.py +++ b/atst/models/portfolio_role.py @@ -52,7 +52,9 @@ class PortfolioRole( UUID(as_uuid=True), ForeignKey("users.id"), index=True, nullable=True ) - status = Column(SQLAEnum(Status, native_enum=False), default=Status.PENDING) + status = Column( + SQLAEnum(Status, native_enum=False), default=Status.PENDING, nullable=False + ) permission_sets = relationship( "PermissionSet", secondary=portfolio_roles_permission_sets diff --git a/atst/models/task_order.py b/atst/models/task_order.py index c79d3b83..85bf363a 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -33,12 +33,9 @@ class TaskOrder(Base, mixins.TimestampsMixin): id = types.Id() - portfolio_id = Column(ForeignKey("portfolios.id")) + portfolio_id = Column(ForeignKey("portfolios.id"), nullable=False) portfolio = relationship("Portfolio") - user_id = Column(ForeignKey("users.id")) - creator = relationship("User", foreign_keys="TaskOrder.user_id") - pdf_attachment_id = Column(ForeignKey("attachments.id")) _pdf = relationship("Attachment", foreign_keys=[pdf_attachment_id]) number = Column(String) # Task Order Number diff --git a/atst/models/user.py b/atst/models/user.py index 4ba23895..29b377d6 100644 --- a/atst/models/user.py +++ b/atst/models/user.py @@ -56,8 +56,8 @@ class User( email = Column(String) dod_id = Column(String, unique=True, nullable=False) - first_name = Column(String) - last_name = Column(String) + first_name = Column(String, nullable=False) + last_name = Column(String, nullable=False) phone_number = Column(String) phone_ext = Column(String) service_branch = Column(String) diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 24460204..dca751e3 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -66,7 +66,7 @@ def update_task_order( task_order = TaskOrders.update(task_order_id, **form.data) portfolio_id = task_order.portfolio_id else: - task_order = TaskOrders.create(g.current_user, portfolio_id, **form.data) + task_order = TaskOrders.create(portfolio_id, **form.data) return redirect(url_for(next_page, task_order_id=task_order.id)) else: @@ -181,9 +181,7 @@ def cancel_edit(task_order_id=None, portfolio_id=None): if task_order_id: task_order = TaskOrders.update(task_order_id, **form.data) else: - task_order = TaskOrders.create( - g.current_user, portfolio_id, **form.data - ) + task_order = TaskOrders.create(portfolio_id, **form.data) elif not save and task_order_id: TaskOrders.delete(task_order_id) diff --git a/script/seed_sample.py b/script/seed_sample.py index 11a45530..a9cec40b 100644 --- a/script/seed_sample.py +++ b/script/seed_sample.py @@ -30,6 +30,8 @@ from atst.domain.users import Users from atst.routes.dev import _DEV_USERS as DEV_USERS +from atst.utils import pick + from tests.factories import ( random_service_branch, TaskOrderFactory, @@ -238,6 +240,7 @@ def add_applications_to_portfolio(portfolio): None, first_name=user_data["first_name"], last_name=user_data["last_name"], + email=user_data["email"], ) app_role = ApplicationRoles.create( @@ -263,7 +266,23 @@ def add_applications_to_portfolio(portfolio): def create_demo_portfolio(name, data): try: - portfolio_owner = Users.get_or_create_by_dod_id("2345678901") # Amanda + portfolio_owner = Users.get_or_create_by_dod_id( + "2345678901", + **pick( + [ + "permission_sets", + "first_name", + "last_name", + "email", + "service_branch", + "phone_number", + "citizenship", + "designation", + "date_latest_training", + ], + DEV_USERS["amanda"], + ), + ) # Amanda # auditor = Users.get_by_dod_id("3453453453") # Sally except NotFoundError: print( diff --git a/tests/domain/test_portfolios.py b/tests/domain/test_portfolios.py index 80dade92..41e3fc81 100644 --- a/tests/domain/test_portfolios.py +++ b/tests/domain/test_portfolios.py @@ -9,6 +9,7 @@ from atst.domain.portfolios import ( ) from atst.domain.portfolio_roles import PortfolioRoles from atst.domain.applications import Applications +from atst.domain.application_roles import ApplicationRoles from atst.domain.environments import Environments from atst.domain.permission_sets import PermissionSets, PORTFOLIO_PERMISSION_SETS from atst.models.application_role import Status as ApplicationRoleStatus diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py index 089741d5..8b1eb724 100644 --- a/tests/domain/test_task_orders.py +++ b/tests/domain/test_task_orders.py @@ -96,7 +96,6 @@ def test_create_adds_clins(): }, ] task_order = TaskOrders.create( - creator=portfolio.owner, portfolio_id=portfolio.id, number="0123456789", clins=clins, @@ -127,7 +126,6 @@ def test_update_adds_clins(): }, ] task_order = TaskOrders.create( - creator=task_order.creator, portfolio_id=task_order.portfolio_id, number="0000000000", clins=clins, diff --git a/tests/domain/test_users.py b/tests/domain/test_users.py index b5a24058..20bd8266 100644 --- a/tests/domain/test_users.py +++ b/tests/domain/test_users.py @@ -4,36 +4,41 @@ from uuid import uuid4 from atst.domain.users import Users from atst.domain.exceptions import NotFoundError, AlreadyExistsError, UnauthorizedError +from atst.utils import pick from tests.factories import UserFactory DOD_ID = "my_dod_id" +REQUIRED_KWARGS = {"first_name": "Luke", "last_name": "Skywalker"} def test_create_user(): - user = Users.create(DOD_ID) + user = Users.create(DOD_ID, **REQUIRED_KWARGS) assert user.dod_id == DOD_ID def test_create_user_with_existing_email(): - Users.create(DOD_ID, email="thisusersemail@usersRus.com") + Users.create(DOD_ID, email="thisusersemail@usersRus.com", **REQUIRED_KWARGS) with pytest.raises(AlreadyExistsError): Users.create(DOD_ID, email="thisusersemail@usersRus.com") def test_create_user_with_nonexistent_permission_set(): with pytest.raises(NotFoundError): - Users.create(DOD_ID, permission_sets=["nonexistent"]) + Users.create(DOD_ID, permission_sets=["nonexistent"], **REQUIRED_KWARGS) def test_get_or_create_nonexistent_user(): - user = Users.get_or_create_by_dod_id(DOD_ID) + user = Users.get_or_create_by_dod_id(DOD_ID, **REQUIRED_KWARGS) assert user.dod_id == DOD_ID def test_get_or_create_existing_user(): fact_user = UserFactory.create() - user = Users.get_or_create_by_dod_id(fact_user.dod_id) + user = Users.get_or_create_by_dod_id( + fact_user.dod_id, + **pick(["first_name", "last_name"], fact_user.to_dictionary()), + ) assert user == fact_user diff --git a/tests/factories.py b/tests/factories.py index efb6fb82..9c8f8c02 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -236,9 +236,17 @@ class ApplicationRoleFactory(Base): @classmethod def _create(cls, model_class, *args, **kwargs): with_invite = kwargs.pop("invite", True) - app_role = super()._create(model_class, *args, **kwargs) + app_role = model_class(*args, **kwargs) - if with_invite: + if with_invite and app_role.user: + ApplicationInvitationFactory.create( + role=app_role, + dod_id=app_role.user.dod_id, + first_name=app_role.user.first_name, + last_name=app_role.user.last_name, + email=app_role.user.email, + ) + elif with_invite: ApplicationInvitationFactory.create(role=app_role) return app_role @@ -260,6 +268,14 @@ class PortfolioInvitationFactory(Base): email = factory.Faker("email") status = InvitationStatus.PENDING expiration_time = PortfolioInvitations.current_expiration_time() + dod_id = factory.LazyFunction(random_dod_id) + first_name = factory.Faker("first_name") + last_name = factory.Faker("last_name") + + @classmethod + def _create(cls, model_class, *args, **kwargs): + inviter_id = kwargs.pop("inviter_id", UserFactory.create().id) + return super()._create(model_class, inviter_id=inviter_id, *args, **kwargs) class ApplicationInvitationFactory(Base): @@ -270,6 +286,14 @@ class ApplicationInvitationFactory(Base): status = InvitationStatus.PENDING expiration_time = PortfolioInvitations.current_expiration_time() role = factory.SubFactory(ApplicationRoleFactory, invite=False) + dod_id = factory.LazyFunction(random_dod_id) + first_name = factory.Faker("first_name") + last_name = factory.Faker("last_name") + + @classmethod + def _create(cls, model_class, *args, **kwargs): + inviter_id = kwargs.pop("inviter_id", UserFactory.create().id) + return super()._create(model_class, inviter_id=inviter_id, *args, **kwargs) class AttachmentFactory(Base): @@ -284,11 +308,8 @@ class TaskOrderFactory(Base): class Meta: model = TaskOrder - portfolio = factory.SubFactory( - PortfolioFactory, owner=factory.SelfAttribute("..creator") - ) + portfolio = factory.SubFactory(PortfolioFactory) number = factory.LazyFunction(random_task_order_number) - creator = factory.SubFactory(UserFactory) signed_at = None _pdf = factory.SubFactory(AttachmentFactory) diff --git a/tests/models/test_task_order.py b/tests/models/test_task_order.py index cb1ca7de..91fee15b 100644 --- a/tests/models/test_task_order.py +++ b/tests/models/test_task_order.py @@ -76,7 +76,7 @@ class TestTaskOrderStatus: @patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock) def test_draft_status(self, is_signed, is_completed): # Given that I have a TO that is neither completed nor signed - to = TaskOrder() + to = TaskOrderFactory.create() is_signed.return_value = False is_completed.return_value = False @@ -89,7 +89,7 @@ class TestTaskOrderStatus: def test_active_status(self, is_signed, is_completed, start_date, end_date): # Given that I have a signed TO and today is within its start_date and end_date today = pendulum.today().date() - to = TaskOrder() + to = TaskOrderFactory.create() start_date.return_value = today.subtract(days=1) end_date.return_value = today.add(days=1) @@ -105,7 +105,7 @@ class TestTaskOrderStatus: @patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock) def test_upcoming_status(self, is_signed, is_completed, start_date, end_date): # Given that I have a signed TO and today is before its start_date - to = TaskOrder() + to = TaskOrderFactory.create() start_date.return_value = pendulum.today().add(days=1).date() end_date.return_value = pendulum.today().add(days=2).date() is_signed.return_value = True @@ -120,7 +120,7 @@ class TestTaskOrderStatus: @patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock) def test_expired_status(self, is_signed, is_completed, end_date, start_date): # Given that I have a signed TO and today is after its expiration date - to = TaskOrder() + to = TaskOrderFactory.create() end_date.return_value = pendulum.today().subtract(days=1).date() start_date.return_value = pendulum.today().subtract(days=2).date() is_signed.return_value = True @@ -143,7 +143,7 @@ class TestTaskOrderStatus: class TestBudget: def test_total_contract_amount(self): - to = TaskOrder() + to = TaskOrderFactory.create() assert to.total_contract_amount == 0 clin1 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_1) @@ -156,7 +156,7 @@ class TestBudget: ) def test_total_obligated_funds(self): - to = TaskOrder() + to = TaskOrderFactory.create() assert to.total_obligated_funds == 0 clin1 = CLINFactory(task_order=to, jedi_clin_type=JEDICLINType.JEDI_CLIN_1) diff --git a/tests/routes/task_orders/test_index.py b/tests/routes/task_orders/test_index.py index c800ce25..708b2bdc 100644 --- a/tests/routes/task_orders/test_index.py +++ b/tests/routes/task_orders/test_index.py @@ -30,7 +30,7 @@ def task_order(): portfolio = PortfolioFactory.create(owner=user) attachment = Attachment(filename="sample_attachment", object_name="sample") - return TaskOrderFactory.create(creator=user, portfolio=portfolio) + return TaskOrderFactory.create(portfolio=portfolio) def test_review_task_order_not_draft(client, user_session, task_order): diff --git a/tests/routes/task_orders/test_new.py b/tests/routes/task_orders/test_new.py index 61a97b82..4d2f5fdb 100644 --- a/tests/routes/task_orders/test_new.py +++ b/tests/routes/task_orders/test_new.py @@ -20,14 +20,13 @@ def task_order(): user = UserFactory.create() portfolio = PortfolioFactory.create(owner=user) - return TaskOrderFactory.create(creator=user, portfolio=portfolio) + return TaskOrderFactory.create(portfolio=portfolio) @pytest.fixture def completed_task_order(): portfolio = PortfolioFactory.create() task_order = TaskOrderFactory.create( - creator=portfolio.owner, portfolio=portfolio, create_clins=[{"number": "1234567890123456789012345678901234567890123"}], ) @@ -68,7 +67,7 @@ def test_task_orders_submit_form_step_one_add_pdf(client, user_session, portfoli def test_task_orders_form_step_one_add_pdf_existing_to( client, user_session, task_order ): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.get( url_for("task_orders.form_step_one_add_pdf", task_order_id=task_order.id) ) @@ -77,7 +76,7 @@ def test_task_orders_form_step_one_add_pdf_existing_to( def test_task_orders_submit_form_step_one_add_pdf_existing_to(client, user_session): task_order = TaskOrderFactory.create() - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.post( url_for( "task_orders.submit_form_step_one_add_pdf", task_order_id=task_order.id @@ -140,7 +139,7 @@ def test_task_orders_submit_form_step_one_validates_object_name( def test_task_orders_form_step_two_add_number(client, user_session, task_order): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.get( url_for("task_orders.form_step_two_add_number", task_order_id=task_order.id) ) @@ -148,7 +147,7 @@ def test_task_orders_form_step_two_add_number(client, user_session, task_order): def test_task_orders_submit_form_step_two_add_number(client, user_session, task_order): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) form_data = {"number": "1234567890"} response = client.post( url_for( @@ -164,7 +163,7 @@ def test_task_orders_submit_form_step_two_add_number(client, user_session, task_ def test_task_orders_submit_form_step_two_add_number_existing_to( client, user_session, task_order ): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) form_data = {"number": "0000000000"} original_number = task_order.number response = client.post( @@ -179,7 +178,7 @@ def test_task_orders_submit_form_step_two_add_number_existing_to( def test_task_orders_form_step_three_add_clins(client, user_session, task_order): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.get( url_for("task_orders.form_step_three_add_clins", task_order_id=task_order.id) ) @@ -187,7 +186,7 @@ def test_task_orders_form_step_three_add_clins(client, user_session, task_order) def test_task_orders_submit_form_step_three_add_clins(client, user_session, task_order): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) form_data = { "clins-0-jedi_clin_type": "JEDI_CLIN_1", "clins-0-clin_number": "12312", @@ -237,7 +236,7 @@ def test_task_orders_submit_form_step_three_add_clins_existing_to( TaskOrders.create_clins(task_order.id, clin_list) assert len(task_order.clins) == 2 - user_session(task_order.creator) + user_session(task_order.portfolio.owner) form_data = { "clins-0-jedi_clin_type": "JEDI_CLIN_1", "clins-0-clin_number": "12312", @@ -258,7 +257,7 @@ def test_task_orders_submit_form_step_three_add_clins_existing_to( def test_task_orders_form_step_four_review(client, user_session, completed_task_order): - user_session(completed_task_order.creator) + user_session(completed_task_order.portfolio.owner) response = client.get( url_for( "task_orders.form_step_four_review", task_order_id=completed_task_order.id @@ -270,7 +269,7 @@ def test_task_orders_form_step_four_review(client, user_session, completed_task_ def test_task_orders_form_step_four_review_incomplete_to( client, user_session, task_order ): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.get( url_for("task_orders.form_step_four_review", task_order_id=task_order.id) ) @@ -280,7 +279,7 @@ def test_task_orders_form_step_four_review_incomplete_to( def test_task_orders_form_step_five_confirm_signature( client, user_session, completed_task_order ): - user_session(completed_task_order.creator) + user_session(completed_task_order.portfolio.owner) response = client.get( url_for( "task_orders.form_step_five_confirm_signature", @@ -293,7 +292,7 @@ def test_task_orders_form_step_five_confirm_signature( def test_task_orders_form_step_five_confirm_signature_incomplete_to( client, user_session, task_order ): - user_session(task_order.creator) + user_session(task_order.portfolio.owner) response = client.get( url_for( "task_orders.form_step_five_confirm_signature", task_order_id=task_order.id @@ -340,9 +339,7 @@ def test_task_orders_submit_task_order(client, user_session, task_order): def test_task_orders_edit_redirects_to_latest_incomplete_step( client, user_session, portfolio, to_factory_args, expected_step ): - task_order = TaskOrderFactory.create( - portfolio=portfolio, creator=portfolio.owner, **to_factory_args - ) + task_order = TaskOrderFactory.create(portfolio=portfolio, **to_factory_args) user_session(portfolio.owner) response = client.get(url_for("task_orders.edit", task_order_id=task_order.id)) @@ -414,8 +411,7 @@ def test_task_orders_update_invalid_data(client, user_session, portfolio): @pytest.mark.skip(reason="Update after implementing errors on TO form") def test_task_order_form_shows_errors(client, user_session, task_order): - creator = task_order.creator - user_session(creator) + user_session(task_order.portfolio.owner) task_order_data = TaskOrderFactory.dictionary() funding_data = slice_data_for_section(task_order_data, "funding") diff --git a/tests/test_access.py b/tests/test_access.py index 8f3d201f..24948ec2 100644 --- a/tests/test_access.py +++ b/tests/test_access.py @@ -487,7 +487,9 @@ def test_portfolios_resend_invitation_access(post_url_assert_status): portfolio = PortfolioFactory.create(owner=owner) prr = PortfolioRoleFactory.create(user=invitee, portfolio=portfolio) - invite = PortfolioInvitationFactory.create(user=UserFactory.create(), role=prr) + invite = PortfolioInvitationFactory.create( + user=UserFactory.create(), role=prr, inviter_id=owner.id + ) url = url_for( "portfolios.resend_invitation", @@ -651,7 +653,6 @@ def test_task_orders_new_get_routes(get_url_assert_status): portfolio = PortfolioFactory.create(owner=owner) task_order = TaskOrderFactory.create( - creator=owner, portfolio=portfolio, create_clins=[{"number": "1234567890123456789012345678901234567890123"}], ) @@ -689,7 +690,7 @@ def test_task_orders_new_post_routes(post_url_assert_status): rando = user_with() portfolio = PortfolioFactory.create(owner=owner) - task_order = TaskOrderFactory.create(portfolio=portfolio, creator=owner) + task_order = TaskOrderFactory.create(portfolio=portfolio) for route, data in post_routes: url = url_for(route, task_order_id=task_order.id)